All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.dev.component.Component Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

package com.tangosol.dev.component;


import com.tangosol.dev.assembler.ClassFile;
import com.tangosol.dev.assembler.CodeAttribute;
import com.tangosol.dev.assembler.Field;
import com.tangosol.dev.assembler.Method;

import com.tangosol.dev.compiler.java.ScriptParser;

import com.tangosol.java.type.ArrayType;
import com.tangosol.java.type.ClassType;
import com.tangosol.java.type.Type;

import com.tangosol.run.xml.SimpleDocument;
import com.tangosol.run.xml.XmlDocument;
import com.tangosol.run.xml.XmlElement;
import com.tangosol.run.xml.XmlHelper;
import com.tangosol.run.xml.XmlSerializable;

import com.tangosol.util.CacheCollator;
import com.tangosol.util.ChainedEnumerator;
import com.tangosol.util.ClassHelper;
import com.tangosol.util.ErrorList;
import com.tangosol.util.NullImplementation;
import com.tangosol.util.SimpleEnumerator;
import com.tangosol.util.StringTable;
import com.tangosol.util.UID;

import java.beans.PropertyVetoException;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

import java.text.Collator;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;


/**
* A Component Definition represents the set of information that describes a
* component, a complex property, or a Java Class Signature (JCS).
*
* @version 1.00, 09/01/97
* @author  Cameron Purdy
*/
public class Component
        extends    Trait
        implements Constants, Cloneable, XmlSerializable
    {
    // ----- construction ---------------------------------------------------

    /**
    * Construct a Component.  This is the "default" constructor.
    *
    * @param parent  the Component or Property that contains this Component
    * @param nType   one of COMPONENT, COMPLEX, or SIGNATURE
    * @param sName   the unqualified name of this Component Definition
    */
    protected Component(Trait parent, int nType, String sName)
        {
        super(parent, RESOLVED);

        // validate type/name and determine read only status

        boolean fReadOnly = false;

        switch (nType)
            {
            case COMPONENT:
                // validate name
                if (sName == null || sName.length() == 0)
                    {
                    throw new IllegalArgumentException(CLASS + ":  "
                            + "Name required for Components!");
                    }
                if (!isSimpleNameLegal(sName, true))
                    {
                    throw new IllegalArgumentException(CLASS + ":  "
                            + "Illegal component name (" + sName + ")");
                    }
                break;

            case COMPLEX:
                // a complex name is the same as the super name, which is
                // the name of the component this is a complex property of
                // validate name
                if (sName == null || sName.length() == 0)
                    {
                    throw new IllegalArgumentException(CLASS + ":  "
                            + "Name required for Complex Components!");
                    }
                break;

            case SIGNATURE:
                // validate name - BLANK names are used to create an empty "root"
                // signature for resolving interfaces against
                if (sName != BLANK)
                    {
                    if (sName == null || sName.length() == 0)
                        {
                        throw new IllegalArgumentException(CLASS + ":  "
                                + "Name required for Signatures!");
                        }
                    if (!ClassHelper.isQualifiedNameLegal(sName))
                        {
                        throw new IllegalArgumentException(CLASS + ":  "
                                + "Illegal signature name (" + sName + ")");
                        }
                    }
                break;

            default:
                throw new IllegalArgumentException(CLASS + ":  "
                        + "Invalid component Type (" + nType + ")");
            }

        m_nType     = nType;
        m_fReadOnly = fReadOnly;
        m_sName     = sName;

        createTables();
        }

    /**
    * Construct a derived Component Definition.  This is not a constructor
    * but since it is public and creates a component it is placed here.
    *
    * @param sName the simple name of the derived Component
    */
    public Component createDerivedComponent(String sName, Loader loader)
        {
        Component cdSuper = this;

        // gg: 2001.5.17 allow JCS creation
        /*
        // validate type of component
        if (!cdSuper.isComponent())
            {
            throw new IllegalArgumentException(CLASS + ".createDerivedComponent:  "
                    + "Can only derive Components!");
            }
        */
        if (cdSuper.getParent() != null)
            {
            throw new IllegalArgumentException(CLASS + ".createDerivedComponent:  "
                    + "Super Component cannot be a child!");
            }

        // validate parameters
        if (sName == null || sName.length() == 0)
            {
            throw new IllegalArgumentException(CLASS + ".createDerivedComponent:  "
                    + "Component Definition name required!");
            }
        else if (cdSuper.isComponent() && !isSimpleNameLegal(sName, true) ||
                 cdSuper.isSignature() && !ClassHelper.isQualifiedNameLegal(sName))
            {
            throw new IllegalArgumentException(CLASS + ".createDerivedComponent:  "
                    + "Illegal Component Definition name! (" + sName + ")");
            }

        Component cdDelta = (Component) cdSuper.getNullDerivedTrait(null, DERIVATION);
        cdDelta.m_sSuper  = getQualifiedName();
        cdDelta.m_sName   = sName;

        try
            {
            ErrorList errlist = new ErrorList();
            Component cdSub   = cdSuper.resolve(cdDelta, loader, errlist);
            cdSub.finalizeResolve(loader, errlist);
            if (errlist.isSevere())
                {
                errlist.print();
                throw new ComponentException(CLASS + ".createDerivedComponent:  "
                        + "Serious errors occurred during resolution!");
                }

            cdSub.validate();
            return cdSub;
            }
        catch (ComponentException e)
            {
            // should not be possible to get a Component exception when
            // resolving a null derivation
            throw new RuntimeException(e.toString());
            }
        }

    /**
    * Construct a complex property using this component as the base.
    * This is not a constructor but since it is public and creates
    * a component it is placed here.
    *
    * @return  the complex property component
    */
    public Component createComplexProperty()
        {
        Component cdBase = this;

        // validate type of component
        if (!cdBase.isComponent())
            {
            throw new IllegalArgumentException(CLASS + ".createComplexProperty:  "
                    + "Can only use Components!");
            }

        if (cdBase.getParent() != null)
            {
            throw new IllegalArgumentException(CLASS + ".createComplexProperty:  "
                    + "Component cannot be a child!");
            }

        // create a child modification from the specified component
        Component cdDelta = (Component) cdBase.getNullDerivedTrait(null, MODIFICATION);
        cdDelta.m_nType   = COMPLEX;
        cdDelta.assignUID();

        // create the new complex property value
        try
            {
            Loader    loader  = new NullStorage();
            ErrorList errlist = new ErrorList();
            Component cdComplex = (Component) cdBase.resolve(cdDelta, null, loader, errlist);
            cdComplex.finalizeResolve(loader, errlist);
            if (errlist.isSevere())
                {
                errlist.print();
                throw new ComponentException(CLASS + ".createComplexProperty:  "
                        + "Serious errors occurred during resolution!");
                }
            cdComplex.validate();
            return cdComplex;
            }
        catch (ComponentException e)
            {
            // should not be possible to get a Component exception when
            // resolving a null derivation
            throw new RuntimeException(e.toString());
            }
        }

    /**
    * Construct a Java Class Signature (JCS) from a Java class using the
    * assembler ClassFile structure.
    *
    * @param clz  the ClassFile to create a signature from
    */
    public Component(ClassFile clz)
            throws ComponentException
        {
        this(clz, null);
        }

    /**
    * Construct a Java Class Signature (JCS) from a Java class using the
    * assembler ClassFile structure.
    *
    * @param clz      the ClassFile to create a signature from
    * @param sScript  the source code that created the ClassFile
    */
    public Component(ClassFile clz, String sScript)
            throws ComponentException
        {
        this(null, SIGNATURE, clz.getName().replace('/', '.'));

        // get attribute information
        int nFlags = EXISTS_INSERT | STG_PERSIST | DIST_LOCAL;
        switch (clz.getAccess())
            {
            case com.tangosol.dev.assembler.Constants.ACC_PUBLIC:
                nFlags |= ACCESS_PUBLIC    | VIS_VISIBLE;
                break;
            case com.tangosol.dev.assembler.Constants.ACC_PROTECTED:
                nFlags |= ACCESS_PROTECTED | VIS_HIDDEN;
                break;
            case com.tangosol.dev.assembler.Constants.ACC_PACKAGE:
                nFlags |= ACCESS_PACKAGE   | VIS_HIDDEN;
                break;
            case com.tangosol.dev.assembler.Constants.ACC_PRIVATE:
                nFlags |= ACCESS_PRIVATE   | VIS_HIDDEN;
                break;
            }
        nFlags |= (clz.isStatic()     ? SCOPE_STATIC     : SCOPE_INSTANCE  );
        nFlags |= (clz.isFinal()      ? DERIVE_FINAL     : DERIVE_DERIVABLE);
        nFlags |= (clz.isAbstract()   ? IMPL_ABSTRACT    : IMPL_CONCRETE   );
        nFlags |= (clz.isDeprecated() ? ANTIQ_DEPRECATED : ANTIQ_CURRENT   );

        // check if the signature represents a throwable class
        if (m_sName.equals("java.lang.Throwable"))
            {
            nFlags |= MISC_ISTHROWABLE;
            }

        // get the super class name
        String sSuper = clz.getSuper();
        if (sSuper == null || sSuper.length() == 0)
            {
            sSuper = BLANK;
            }
        else
            {
            sSuper = sSuper.replace('/', '.');
            }

        // check if the signature is an interface
        if (clz.isInterface())
            {
            nFlags |= MISC_ISINTERFACE;
            // make sure that it's super is java.lang.Object
            if (!sSuper.equals("java.lang.Object"))
                {
                throw new IllegalArgumentException(CLASS + ":  "
                        + "Illegal interface class file (" + m_sName + ") does not have a super java.lang.Object");
                }
            sSuper = BLANK;
            }
        m_sSuper = sSuper;

        // iterate through the class's interfaces
        for (Enumeration enmr = clz.getImplements(); enmr.hasMoreElements(); )
            {
            String sIface = ((String) enmr.nextElement()).replace('/', '.');
            Interface iface = new Interface(this, sIface);
            m_tblImplements.put(sIface, iface);
            }

        // "reflect" the ClassFile fields
        StringTable tblFields = m_tblState;
        for (Enumeration enmr = clz.getFields(); enmr.hasMoreElements(); )
            {
            Field field = (Field) enmr.nextElement();

            if (!field.isSynthetic() && (field.isPublic() || field.isProtected()))
                {
                Property prop = new Property(this, field);
                prop.setExists(EXISTS_INSERT);
                tblFields.put(prop.getUniqueName(), prop);
                }
            }

        // 2002-07-22 cp - parse the parameter names if available
        Map mapParam = new HashMap();
        if (sScript != null && sScript.length() > 0)
            {
            ScriptParser parser = new ScriptParser();
            try
                {
                parser.parse(sScript, mapParam);
                }
            catch (Exception e)
                {
                }
            }

        // "reflect" the ClassFile methods
        StringTable tblMethods = m_tblBehavior;
        for (Enumeration enmr = clz.getMethods(); enmr.hasMoreElements(); )
            {
            Method method = (Method) enmr.nextElement();

            // only show public methods on interfaces
            if (method.isPublic() || (!isInterface() && method.isProtected()))
                {
                Behavior beh = new Behavior(this, method, mapParam);
                String sSig = beh.getUniqueName();

                // we won't know whether this is an insert or update till the
                // resolution time (see Behavior#resolve())
                beh.setExists(EXISTS_INSERT);

                Behavior behPrev = (Behavior) tblMethods.get(sSig);
                if (behPrev == null || behPrev.isSynthetic() && !beh.isSynthetic())
                    {
                    tblMethods.put(sSig, beh);
                    }
                // else; compiler generated methods can be discarded
                }
            }

        // store ClassFile attributes
        m_nFlags = nFlags;

        // adjust our type if we need to be resolved when loaded
        // The only resolved signature is "java.lang.Object"
        if (m_sSuper != BLANK || clz.isInterface())
            {
            setMode(DERIVATION);
            }
        }

    /**
    * Construct a blank Component Trait.
    *
    * @param base    the base Component to derive from
    * @param parent  the containing Component or Property
    * @param nMode   one of RESOLVED, DERIVATION, MODIFICATION
    *
    * @see #getBlankDerivedTrait(Trait, int)
    */
    protected Component(Component base, Trait parent, int nMode)
        {
        super(base, parent, nMode);

        this.m_nType  = base.m_nType;
        this.m_sName  = base.m_sName;
        this.m_sSuper = base.m_sSuper;

        createTables();
        }

    /**
    * Copy constructor.
    *
    * @param parent  the Component or Property that will contain the new
    *                Component
    * @param that    the trait to copy from
    */
    protected Component(Trait parent, Component that)
        {
        super(parent, that);

        // copy intrinsic/immutable attributes
        this.m_nType      = that.m_nType;
        this.m_fReadOnly  = that.m_fReadOnly;
        this.m_sName      = that.m_sName;
        this.m_sSuper     = that.m_sSuper;
        this.m_nFlags     = that.m_nFlags;
        this.m_nPrevFlags = that.m_nPrevFlags;
        this.m_fBaseLevel = that.m_fBaseLevel;

        // integration
        if (that.m_integration != null)
            {
            this.m_integration = new Integration(this, that.m_integration);
            }

        createTables();
        StringTable tblThat;
        StringTable tblThis;

        // implements
        tblThat = that.m_tblImplements;
        if (!tblThat.isEmpty())
            {
            tblThis = this.m_tblImplements;
            for (Enumeration enmr = tblThat.elements(); enmr.hasMoreElements(); )
                {
                Interface iface = (Interface) enmr.nextElement();
                tblThis.put(iface.getUniqueName(), new Interface(this, iface));
                }
            }

        // dispatches
        tblThat = that.m_tblDispatches;
        if (!tblThat.isEmpty())
            {
            tblThis = this.m_tblDispatches;
            for (Enumeration enmr = tblThat.elements(); enmr.hasMoreElements(); )
                {
                Interface iface = (Interface) enmr.nextElement();
                tblThis.put(iface.getUniqueName(), new Interface(this, iface));
                }
            }

        // Properties
        tblThat = that.m_tblState;
        if (!tblThat.isEmpty())
            {
            tblThis = this.m_tblState;
            for (Enumeration enmr = tblThat.elements(); enmr.hasMoreElements(); )
                {
                Property prop = (Property) enmr.nextElement();
                tblThis.put(prop.getUniqueName(), new Property(this, prop));
                }
            }

        // Behaviors
        tblThat = that.m_tblBehavior;
        if (!tblThat.isEmpty())
            {
            tblThis = this.m_tblBehavior;
            for (Enumeration enmr = tblThat.elements(); enmr.hasMoreElements(); )
                {
                Behavior behavior = (Behavior) enmr.nextElement();
                tblThis.put(behavior.getUniqueName(), new Behavior(this, behavior));
                }
            }

        // aggregation categories
        tblThat = that.m_tblCategories;
        if (!tblThat.isEmpty())
            {
            this.m_tblCategories = (StringTable) tblThat.clone();
            }

        // Children
        tblThat = that.m_tblChildren;
        if (!tblThat.isEmpty())
            {
            tblThis = this.m_tblChildren;
            for (Enumeration enmr = tblThat.elements(); enmr.hasMoreElements(); )
                {
                Component cd = (Component) enmr.nextElement();
                tblThis.put(cd.getUniqueName(), new Component(this, cd));
                }
            }
        }

    /**
    * Construct the component from a stream.
    *
    * This is a custom serialization implementation that is unrelated to the
    * Serializable interface and the Java implementation of persistence.
    *
    * @param stream   the stream to read this Component Definition from
    *
    * @exception IOException An IOException is thrown if an error occurs
    *            reading the Component Definition from the stream or if the
    *            stream does not contain a valid Component Definition
    */
    public Component(DataInput stream)
            throws IOException
        {
        this(null, stream, getVersion(stream));
        validate();
        }

    /**
    * Construct the component from a stream.
    *
    * This is a custom serialization implementation that is unrelated to the
    * Serializable interface and the Java implementation of persistence.
    *
    * @param traitParent the containing Component Definition (if this CD is
    *                    aggregated) or Property (if this Component
    *                    Definition is used to store a complex property)
    * @param stream      the stream to read this Component Definition from
    * @param nVersion    version of the data structure in the stream
    *
    * @exception IOException An IOException is thrown if an error occurs
    *            reading the Component Definition from the stream or if the
    *            stream does not contain a valid Component Definition.
    */
    protected Component(Trait traitParent, DataInput stream, int nVersion)
            throws IOException
        {
        super(traitParent, stream, nVersion);

        // version
        m_nVersion   = nVersion;

        // identity
        m_nType      = stream.readUnsignedByte();
        m_sName      = readString(stream);
        m_sSuper     = readString(stream);
        m_nFlags     = stream.readInt();
        m_nPrevFlags = stream.readInt();
        m_fBaseLevel = stream.readBoolean();

        createTables();

        // integration
        if (stream.readBoolean())
            {
            m_integration = new Integration(this, stream, nVersion);
            }

        // implements
        StringTable tbl    = m_tblImplements;
        int         cItems = stream.readInt();
        for (int i = 0; i < cItems; ++i)
            {
            Interface iface = new Interface(this, stream, nVersion);
            tbl.put(iface.getUniqueName(), iface);
            }

        // dispatches
        tbl    = m_tblDispatches;
        cItems = stream.readInt();
        for (int i = 0; i < cItems; ++i)
            {
            Interface iface = new Interface(this, stream, nVersion);
            tbl.put(iface.getUniqueName(), iface);
            }

        // state
        tbl    = m_tblState;
        cItems = stream.readInt();
        for (int i = 0; i < cItems; ++i)
            {
            Property prop = new Property(this, stream, nVersion);
            tbl.put(prop.getUniqueName(), prop);
            }

        // behavior
        tbl    = m_tblBehavior;
        cItems = stream.readInt();
        for (int i = 0; i < cItems; ++i)
            {
            Behavior behavior = new Behavior(this, stream, nVersion);
            tbl.put(behavior.getUniqueName(), behavior);
            }

        // aggregation
        tbl    = m_tblCategories;
        cItems = stream.readInt();
        for (int i = 0; i < cItems; ++i)
            {
            tbl.put(stream.readUTF(), toBoolean(stream.readBoolean()));
            }

        // children
        tbl    = m_tblChildren;
        cItems = stream.readInt();
        for (int i = 0; i < cItems; ++i)
            {
            Component cd = new Component(this, stream, nVersion);
            tbl.put(cd.getUniqueName(), cd);
            }
        }

    /**
    * Construct the component from an XmlDocument.
    *
    * This is a custom serialization implementation that is unrelated to the
    * Serializable interface and the Java implementation of persistence.
    *
    * @param xml  the XmlDocument to read this Component Definition from
    *
    * @exception IOException An IOException is thrown if an error occurs
    *            reading the Component Definition from the XML or if the
    *            XML does not contain a valid Component Definition
    */
    public Component(XmlDocument xml)
            throws IOException
        {
        this(null, xml, getVersion(xml));
        validate();
        }

    /**
    * Construct a Trait object from persistent data.  All traits implement
    * implement a constructor from persistent data.
    *
    * @param parent    the trait that contains this trait
    * @param xml       the XmlElement to read the persistent information from
    * @param nVersion  version of the data structure in the stream
    *
    * @throws IOException if an exception occurs reading the trait data
    */
    protected Component(Trait parent, XmlElement xml, int nVersion)
            throws IOException
        {
        super(parent, xml, nVersion);

        // version
        m_nVersion   = nVersion;

        // identity
        String sName = readString(xml.getElement("name"));
        String sType = readString(xml.getElement("type"));
        if (sName == BLANK || sType == BLANK)
            {
            throw new IOException("name or type is missing");
            }

        m_sName = sName;
        m_nType = -1;
        for (int i = 0, c = DESCRIPTORS.length; i < c; ++i)
            {
            if (DESCRIPTORS[i].equalsIgnoreCase(sType))
                {
                m_nType = i;
                break;
                }
            }
        if (m_nType < 0)
            {
            throw new IOException("illegal type: " + sType);
            }

        m_sSuper     = readString(xml.getElement("super"));
        m_nFlags     = readFlags(xml, "flags", 0);
        m_nPrevFlags = readFlags(xml, "prev-flags", 0);
        m_fBaseLevel = readBoolean(xml.getElement("base-level"));

        createTables();

        // integration
        XmlElement xmlIntegration = xml.getElement("integration");
        if (xmlIntegration != null)
            {
            m_integration = new Integration(this, xmlIntegration, nVersion);
            }

        // implements
        XmlElement xmlImplements = xml.getElement("implements");
        if (xmlImplements != null)
            {
            StringTable tbl = m_tblImplements;
            for (Iterator iter = xmlImplements.getElements("interface"); iter.hasNext(); )
                {
                XmlElement xmlIFace = (XmlElement) iter.next();
                Interface  iface    = new Interface(this, xmlIFace, nVersion);
                tbl.put(iface.getUniqueName(), iface);
                }
            }

        // dispatches
        XmlElement xmlDispatches = xml.getElement("dispatches");
        if (xmlDispatches != null)
            {
            StringTable tbl = m_tblDispatches;
            for (Iterator iter = xmlDispatches.getElements("interface"); iter.hasNext(); )
                {
                XmlElement xmlIFace = (XmlElement) iter.next();
                Interface  iface    = new Interface(this, xmlIFace, nVersion);
                tbl.put(iface.getUniqueName(), iface);
                }
            }

        // state
        XmlElement xmlProps = xml.getElement("properties");
        if (xmlProps != null)
            {
            StringTable tbl = m_tblState;
            for (Iterator iter = xmlProps.getElements("property"); iter.hasNext(); )
                {
                XmlElement xmlProp = (XmlElement) iter.next();
                Property   prop    = new Property(this, xmlProp, nVersion);
                tbl.put(prop.getUniqueName(), prop);
                }
            }

        // behavior
        XmlElement xmlBehaviors = xml.getElement("behaviors");
        if (xmlBehaviors != null)
            {
            StringTable tbl = m_tblBehavior;
            for (Iterator iter = xmlBehaviors.getElements("behavior"); iter.hasNext(); )
                {
                XmlElement xmlBehavior = (XmlElement) iter.next();
                Behavior behavior = new Behavior(this, xmlBehavior, nVersion);
                tbl.put(behavior.getUniqueName(), behavior);
                }
            }

        // aggregation
        XmlElement xmlCategories = xml.getElement("categories");
        if (xmlCategories != null)
            {
            StringTable tbl = m_tblCategories;
            for (Iterator iter = xmlCategories.getElements("category"); iter.hasNext(); )
                {
                XmlElement xmlCat   = (XmlElement) iter.next();
                String     sCatName = readString(xmlCat.getElement("name"));
                boolean    fCatDecl = readBoolean(xmlCat.getElement("declared"));
                if (sCatName == BLANK)
                    {
                    throw new IOException("category name is missing");
                    }

                tbl.put(sCatName, toBoolean(fCatDecl));
                }
            }

        // children
        XmlElement xmlChildren = xml.getElement("children");
        if (xmlChildren != null)
            {
            StringTable tbl = m_tblChildren;
            for (Iterator iter = xmlChildren.getElements("child"); iter.hasNext(); )
                {
                XmlElement xmlChild = (XmlElement) iter.next();
                Component  cd       = new Component(this, xmlChild, nVersion);
                tbl.put(cd.getUniqueName(), cd);
                }
            }
        }

    /**
    * Create the tables of sub-trait information based on the type of the
    * Component.
    */
    private void createTables()
        {
        m_tblImplements = new StringTable();
        m_tblDispatches = new StringTable();
        m_tblCategories = new StringTable();

        if (m_nType == SIGNATURE)
            {
            m_tblState      = new StringTable();
            m_tblBehavior   = new StringTable();
            m_tblChildren   = new StringTable();
            }
        else
            {
            m_tblState      = new StringTable(INSENS);
            m_tblBehavior   = new StringTable(INSENS);
            m_tblChildren   = new StringTable(INSENS);
            }
        }


    // ----- persistence ----------------------------------------------------

    /**
    * Save the Component Definition to a stream.  This method is responsible
    * for recursively saving the Component Definition and its aggregated
    * Component Definitions.
    *
    * This is a custom serialization implementation that is unrelated to the
    * Serializable interface and the Java implementation of persistence.
    */
    public synchronized void save(DataOutput stream)
            throws IOException
        {
        // write the header
        Trait parent = getParentTrait();
        if (parent == null)
            {
            stream.writeInt(MAGIC);
            stream.writeInt(VERSION);
            }

        // save the trait information
        super.save(stream);

        // write the identity
        stream.writeByte(m_nType);
        stream.writeUTF(m_sName);
        stream.writeUTF(m_sSuper);
        stream.writeInt(m_nFlags);
        stream.writeInt(m_nPrevFlags);
        stream.writeBoolean(m_fBaseLevel);

        // integration
        Integration integration = m_integration;
        boolean     fExists     = (integration != null);
        stream.writeBoolean(fExists);
        if (fExists)
            {
            integration.save(stream);
            }

        // implements
        StringTable tbl = m_tblImplements;
        stream.writeInt(tbl.getSize());
        for (Enumeration enmr = tbl.elements(); enmr.hasMoreElements(); )
            {
            ((Interface) enmr.nextElement()).save(stream);
            }

        // dispatches
        tbl = m_tblDispatches;
        stream.writeInt(tbl.getSize());
        for (Enumeration enmr = tbl.elements(); enmr.hasMoreElements(); )
            {
            ((Interface) enmr.nextElement()).save(stream);
            }

        // state
        tbl = m_tblState;
        stream.writeInt(tbl.getSize());
        for (Enumeration enmr = tbl.elements(); enmr.hasMoreElements(); )
            {
            ((Property) enmr.nextElement()).save(stream);
            }

        // behavior
        tbl = m_tblBehavior;
        stream.writeInt(tbl.getSize());
        for (Enumeration enmr = tbl.elements(); enmr.hasMoreElements(); )
            {
            ((Behavior) enmr.nextElement()).save(stream);
            }

        // aggregation
        tbl = m_tblCategories;
        stream.writeInt(tbl.getSize());
        for (Enumeration enmr = tbl.keys(); enmr.hasMoreElements(); )
            {
            String  sCategory  = (String) enmr.nextElement();
            boolean fThisLevel = ((Boolean) tbl.get(sCategory)).booleanValue();
            stream.writeUTF(sCategory);
            stream.writeBoolean(fThisLevel);
            }

        // children
        tbl = m_tblChildren;
        stream.writeInt(tbl.getSize());
        for (Enumeration enmr = tbl.elements(); enmr.hasMoreElements(); )
            {
            ((Component) enmr.nextElement()).save(stream);
            }
        }

    /**
    * Save the Component Definition to a stream.  This method is responsible
    * for recursively saving the Component Definition and its aggregated
    * Component Definitions.
    *
    * This is a custom serialization implementation that is unrelated to the
    * Serializable interface and the Java implementation of persistence.
    */
    public synchronized void save(XmlElement xml)
            throws IOException
        {
        // write the identity
        xml.addElement("type").setString(DESCRIPTORS[m_nType]);
        xml.addElement("name").setString(m_sName);
        xml.addElement("super").setString(m_sSuper);

        // save the trait information
        super.save(xml);

        saveFlags(xml, "flags", m_nFlags, 0);
        saveFlags(xml, "prev-flags", m_nPrevFlags, 0);

        if (isComponent())
            {
            xml.addElement("base-level").setBoolean(m_fBaseLevel);
            }

        // integration
        Integration integration = m_integration;
        if (integration != null)
            {
            integration.save(xml.addElement("integration"));
            }

        // implements
        saveTable(xml, m_tblImplements, "implements", "interface");

        // dispatches
        saveTable(xml, m_tblDispatches, "dispatches", "interface");

        // state
        saveTable(xml, m_tblState, "properties", "property");

        // behavior
        saveTable(xml, m_tblBehavior, "behaviors", "behavior");

        // aggregation
        StringTable tblCats = m_tblCategories;
        if (!tblCats.isEmpty())
            {
            XmlElement xmlCats = xml.addElement("categories");
            for (Enumeration enmr = tblCats.keys(); enmr.hasMoreElements(); )
                {
                String  sCategory  = (String) enmr.nextElement();
                boolean fThisLevel = ((Boolean) tblCats.get(sCategory)).booleanValue();
                XmlElement xmlCat = xmlCats.addElement("category");
                xmlCat.addElement("name").setString(sCategory);
                if (fThisLevel)
                    {
                    xmlCat.addElement("declared").setBoolean(true);
                    }
                }
            }

        // children
        saveTable(xml, m_tblChildren, "children", "child");
        }

    /**
    * Read the header of the Component Definition, extracting the version.
    *
    * @param stream
    *
    * @return version of the Component Definition in the stream
    *
    * @exception IOException if the stream does not contain a Component
    *            Definition, if the Component Definition version is not
    *            supported, or if there is any other error reading from
    *            the stream
    */
    protected static int getVersion(DataInput stream)
            throws IOException
        {
        // read header
        if (stream.readInt() != MAGIC)
            {
            throw new IOException(CLASS + ".getVersion:  "
                    + "Stream does not contain a Component Definition");
            }

        // read version
        int nVersion = stream.readInt();
        switch (nVersion)
            {
            case VERSION:
                break;
            default:
                throw new IOException(CLASS + ".getVersion:  "
                    + "Stream contains an unsupported version of a Component Definition");
            }

        return nVersion;
        }

    /**
    * Get the version of the Component Definition from the passed
    *  XmlDocument.
    *
    * @param xml  the XmlDocument to extract the version from
    *
    * @return version of the Component Definition in the stream
    *
    * @exception IOException if the stream does not contain a Component
    *            Definition, if the Component Definition version is not
    *            supported, or if there is any other error reading from
    *            the stream
    */
    protected static int getVersion(XmlDocument xml)
            throws IOException
        {
        int nVersion = xml.getSafeElement("version").getInt();
        switch (nVersion)
            {
            case 0:
                throw new IOException(CLASS + ".getVersion:  "
                    + "XmlDocument does not contain a valid Component Definition");

            case VERSION:
                break;

            default:
                throw new IOException(CLASS + ".getVersion:  "
                    + "XmlDocument contains an unsupported version of a Component Definition");
            }

        return nVersion;
        }


    // ----- XmlSerializable interface --------------------------------------

    /**
    * Serialize the object into an XmlElement.
    *
    * @return an XmlElement that contains the serialized form of the object
    */
    public XmlElement toXml()
        {
        XmlDocument xml = new SimpleDocument("component");

        // write the header
        Trait parent = getParentTrait();
        if (parent == null)
            {
            xml.addElement("version").setInt(VERSION);
            }

        try
            {
            save(xml);
            }
        catch (IOException e)
            {
            throw ensureRuntimeException(e);
            }

        return xml;
        }

    /**
    * Deserialize the object from an XmlElement.
    *
    * This method can throw one of several RuntimeExceptions.
    *
    * @param xml  an XmlElement that contains the serialized form of the
    *             object
    *
    * @throws UnsupportedOperationException
    * @throws IllegalStateException
    * @throws IllegalArgumentException
    */
    public void fromXml(XmlElement xml)
        {
        throw new UnsupportedOperationException();
        }


    // ----- derivation/modification ----------------------------------------

    /**
    * Get the super of the root.  Assumptions are:
    *   (1) There are methods
    *   (2) There are no fields
    *   (3) There are no interfaces
    *
    * @param loader
    *
    * @return the super of the root component
    */
    public static Component getRootSuper(Loader loader)
            throws ComponentException
        {
        Component cdSuper = new Component(null, COMPONENT, getRootName());
        cdSuper.m_sName     = BLANK;
        cdSuper.m_fReadOnly = true;

        // the root component inherits methods from java/lang/Object;
        Component   cdJCS  = loader.loadSignature(DataType.OBJECT.getClassName());
        StringTable tblJCS = cdJCS  .m_tblBehavior;
        StringTable tblCD  = cdSuper.m_tblBehavior;
        for (Enumeration enmr = tblJCS.keys(); enmr.hasMoreElements(); )
            {
            String sSig = (String) enmr.nextElement();
            if (Behavior.isConstructor(sSig))
                {
                continue;
                }

            Behavior behJCS = (Behavior) tblJCS.get(sSig);
            int nAccess = behJCS.getAccess();
            if (nAccess != ACCESS_PUBLIC && nAccess != ACCESS_PROTECTED)
                {
                continue;
                }

            Behavior behCD = new Behavior(cdSuper, behJCS.getReturnValue().getDataType(),
                    behJCS.getName(), behJCS.isStatic(), nAccess, behJCS.getParameterTypes(),
                    behJCS.getParameterNames(), null);
            try
                {
                behCD.setFinal(behJCS.isFinal(), false);
                behCD.setVisible(VIS_ADVANCED  , false);
                behCD.assignUID();
                }
            catch (PropertyVetoException e)
                {
                throw new IllegalStateException();
                }

            tblCD.put(sSig, behCD);
            }

        cdSuper.validate();
        return cdSuper;
        }

    /**
    * Construct a blank Component from this base.
    *
    * @param parent  the containing Component or Property
    * @param nMode   RESOLVED, DERIVATION or MODIFICATION
    *
    * @return a new blank derived trait of this trait's class with the
    *         specified parent and mode
    */
    protected Trait getBlankDerivedTrait(Trait parent, int nMode)
        {
        return new Component(this, parent, nMode);
        }

    /**
    * Construct a null derivation or modification Trait.  This method is
    * overridden by traits that have a different null derivation/modification
    * from their blank derived trait.  The "this" parameter is the base
    * trait.
    *
    * A null trait derivation or modification is an "r-value" for resolve
    * processing; a null derivation or modification is used when the delta
    * to apply is not present.
    *
    * @param parent  the containing trait or null if the null trait is
    *                not going to be contained by another trait
    * @param nMode   one of DERIVATION or MODIFICATION
    *
    * @return a new null derivation or modification trait of this trait's
    *         class with the specified parent and mode
    */
    protected Trait getNullDerivedTrait(Trait parent, int nMode)
        {
        Component cd = (Component) super.getNullDerivedTrait(parent, nMode);

        // default to update
        cd.setExists(EXISTS_UPDATE);

        // base level is true for derivations, false for modifications
        cd.m_fBaseLevel = (nMode != MODIFICATION);

        return cd;
        }

    /**
    * Apply the Component derivation or modification to this base, resulting
    * in a new Component.
    *
    * @param cdDelta  the Component derivation or modification
    * @param loader   the Loader object for JCS, CIM, and CD dependencies
    * @param errlist  the error list object to log error information to
    *
    * @return the resulting Component
    *
    * @exception ComponentException  thrown only if a fatal error occurs
    */
    public Component resolve(Component cdDelta, Loader loader, ErrorList errlist)
            throws ComponentException
        {
        // validate base and delta component definitions
        if (cdDelta == null)
            {
            throw new IllegalArgumentException(CLASS + ".resolve:  "
                + "Delta Component required!");
            }

        if (m_nType != COMPONENT && m_nType != SIGNATURE)
            {
            throw new IllegalArgumentException(CLASS + ".resolve:  "
                + "Base is not a Component or Java Class Signature!");
            }
        if (this.m_nType != cdDelta.m_nType)
            {
            throw new IllegalArgumentException(CLASS + ".resolve:  "
                + "Base type (" + this.m_nType + ") != Delta type (" + cdDelta.m_nType + ")");
            }

        return (Component) resolve(cdDelta, null, loader, errlist);
        }

    /**
    * Create a derived/modified Trait by combining the information from this
    * Trait with the super or base level's Trait information.  Neither the
    * base ("this") nor the delta may be modified in any way.
    *
    * The delta Component is one of the following:
    * 
    *   1)  Component Derivation - This Component Definition contains the
    *       information to create a new Component from the passed base
    *       Component
    *   2)  Component Modification - This Component Definition contains
    *       information which will alter the passed base Component but
    *       will not result in a new (i.e. different identity) Component
    *   3)  Complex Property Value - This is a stripped-down Component
    *       Modification containing only state (Property) and minimal
    *       identity information
    *
    * The following table illustrates the state changes given the modes of
    * the two inputs (this and base):
    *
    *   base            delta           result
    *   --------------  --------------  -------------
    *   resolved        derivation      resolved
    *   resolved        modification    resolved
    *   derivation      modification    derivation
    *   modification    modification    modification
    *
    * In the above table, any input combination not listed is illegal (and
    * resolved by Trait).  The mode of the base always determines the mode
    * of the result.  This explains why the root Component must be stored
    * in its resolved state, since otherwise it would be impossible to
    * resolve any Component.
    *
    * The resolve method is driven externally by the loader mechanism.
    * It is legal only to resolve a global Component; local (child)
    * Components and complex Property values are automatically resolved
    * recursively by the global Component.
    *
    * There are four fundamental areas of information that are resolved by
    * the Component:
    *
    *   1)  Identity - includes the name of the Component, the interfaces
    *       dispatched and implemented by the Component, the map integrated
    *       by the Component, and other various Component attributes
    *   2)  State - the Properties of the Component
    *   3)  Behavior - the methods and events of the Component; this is the
    *       most dependent section in the Component, since Behaviors can be
    *       the result of integration, implemented/dispatched interfaces,
    *       Property accessors, base/super level Components, and manual
    *       addition
    *   4)  Aggregation - the child Components of this Component
    * 
* * @param traitDelta the Trait derivation or modification * @param parent the Trait which will contain the resulting Trait or * null if the resulting Trait will not be contained * @param loader the Loader object for JCS, CIM, and CD dependencies * @param errlist the error list object to log error information to * * @return the result of applying the specified delta Trait to this Trait * * @exception ComponentException thrown only if a fatal error occurs */ protected Trait resolve(Trait traitDelta, Trait parent, Loader loader, ErrorList errlist) throws ComponentException { Component base = this; Component delta = (Component) resolveDelta(traitDelta, loader, errlist); Component derived = (Component) super.resolve(delta, parent, loader, errlist); // for general use below boolean fComponent = (delta.m_nType == COMPONENT); boolean fSignature = (delta.m_nType == SIGNATURE); // a complex Property value is implemented using the Component // Definition data structure; only some sections of the Component // Definition are applicable for a complex Property value boolean fComplex = (delta.m_nType == COMPLEX); boolean fBaseComplex = (base .m_nType == COMPLEX); // resolve mode int nBaseMode = base.getMode(); boolean fBaseResolved = (nBaseMode == RESOLVED); int nDeltaMode = delta.getMode(); if (nDeltaMode == RESOLVED) { // this can happen when the Component is an INSERT with the // same name as a Component later added to the base nDeltaMode = delta.getExtractMode(base); } int nDerivedMode = derived.getMode(); // ----- identity if (fComplex) { if (fBaseComplex) { derived.m_sSuper = base.m_sSuper; derived.m_sName = base.m_sName; derived.m_nFlags = EXISTS_UPDATE; derived.m_nPrevFlags = base.m_nFlags; } else { derived.m_nType = COMPLEX; derived.m_sSuper = base.getQualifiedName(); derived.m_sName = derived.m_sSuper; derived.m_nFlags = EXISTS_INSERT; } } else { // attributes represented as bit flags int nBaseFlags = base.m_nFlags; int nDeltaFlags = delta.m_nFlags; int nPrevFlags = derived.resolveFlags(nBaseFlags, delta.m_nPrevFlags); int nDerivedFlags = derived.resolveFlags(nPrevFlags, nDeltaFlags); // resolve exists int nExists = EXISTS_UPDATE; if (nDeltaMode == DERIVATION) { // an insert component exists when the base is global and the // delta is a child if (base.getParentTrait() == null && delta.getParentTrait() != null) { nExists = EXISTS_INSERT; } else if ((nDeltaFlags & EXISTS_MASK) == EXISTS_DELETE) { nExists = EXISTS_DELETE; } } else { // a modification of an insert remains an insert, likewise // for deletes int nBaseExists = nBaseFlags & EXISTS_MASK; if (nBaseExists == EXISTS_INSERT || nBaseExists == EXISTS_DELETE) { nExists = nBaseExists; } } nDerivedFlags = nDerivedFlags & ~EXISTS_FULLMASK | nExists; // resolve identity if (nDeltaMode == DERIVATION) { // super and name are copied from base for child updates // otherwise the base is the super for global components and // children added at this level if (parent != null && nExists == EXISTS_UPDATE) { derived.m_sSuper = base.m_sSuper; derived.m_sName = base.m_sName; } else { derived.m_sSuper = base.getQualifiedName(); derived.m_sName = delta.m_sName; } derived.m_fBaseLevel = delta.m_fBaseLevel; } else { // modification keeps the Component identity from the base derived.m_sSuper = base.m_sSuper; derived.m_sName = base.m_sName; // modification results in a Component not at the base level derived.m_fBaseLevel = false; } // store flags derived.m_nPrevFlags = nPrevFlags; derived.m_nFlags = nDerivedFlags; // null derive all Implements/Dispatches interfaces (any delta // interfaces are expanded during behavior resolve processing) for (Enumeration enmr = base.m_tblImplements.elements(); enmr.hasMoreElements(); ) { Interface ifaceBase = (Interface) enmr.nextElement(); Interface ifaceDelta = (Interface) ifaceBase.getNullDerivedTrait(delta, nDeltaMode); Interface ifaceDerived = (Interface) ifaceBase.resolve(ifaceDelta, derived, loader, errlist); derived.m_tblImplements.put(ifaceDerived.getUniqueName(), ifaceDerived); } for (Enumeration enmr = base.m_tblDispatches.elements(); enmr.hasMoreElements(); ) { Interface ifaceBase = (Interface) enmr.nextElement(); Interface ifaceDelta = (Interface) ifaceBase.getNullDerivedTrait(delta, nDeltaMode); Interface ifaceDerived = (Interface) ifaceBase.resolve(ifaceDelta, derived, loader, errlist); derived.m_tblDispatches.put(ifaceDerived.getUniqueName(), ifaceDerived); } } // ----- state, behavior // The act of resolving a Component derivation/modification is // significantly more complex than the extraction of a derivation/ // modification for the following reasons: // // 1) Identity contains interface declarations (integration, // implements, dispatches) which potentially conflict with // Properties and Behaviors present (or reserved) in the base // as well as Behaviors present (or reserved) in this Component // 2) State contains Property declarations (i.e. INSERTs) which // could conflict with the base (either because the Property // already exists or is "reserved") // 3) Behaviors on this could conflict with Behaviors on the base // (either because the Behavior already exists or is "reserved") // // The manner of resolving interfaces, state, and behavior differs // depending on the mode (resolved, derivation, modification) of the // base and delta Components. The most complex scenario is the // resolution of a Component Derivation using a resolved base // Component Definition (i.e. the super Component). The other three // scenarios (modifications) are implemented as subsets of the first // scenario. // // 1) The primary rule is that the base is always correct. The // base is never altered by the resolve of this Component; if // there is a conflict with the base, the information from the // delta Component is discarded or altered. There are three key // groups of information on the base: // a) All interfaces (integration, implements, dispatches) from // the base are visible from this Component (see identity // resolution above) // b) Behaviors on the base fall into one of three categories: // 1) Reserved Behaviors may not be visible from this // Component but cannot be added by (i.e. cannot exist // as INSERTs on) this Component; reserved Behaviors // include case-insensitive conflicts (foo vs. Foo) and // private Behaviors which implement Property accessors // on a super class for Properties with at least one // non-private accessor // 2) In the case of a Component Derivation, Behaviors // which are private on the base Component are not // visible from this Component, but are not by default // reserved so same-named Behaviors can be added to // (i.e. can exist as INSERTs on) this Component // 3) All other Behaviors are modifiable/derivable subject // to the resolve rules implemented by Behavior // c) Properties are very similar to Behaviors (in terms of the // above categorization) with one notable difference: a // Property with at least one non-private accessor is // carried forward to derived Components but may not be // "present" (modifiable) there; it serves as a place-holder // to reserve the Property name // // The implementation of this rule is that all base Behaviors // and Properties are resolved first, since they must exist // on the resulting derived Component. // // 2) The resolve of a derivation includes the expansion of any // interfaces added by the derivation, in the following order: // a) [integration] // b) [implements]* // c) [dispatches]* // Each interface must be able to be expanded fully or the // complete interface is discarded; the act of expanding an // interface is comprised of iterating through the Property/ // Behaviors of the interface and creating an INSERT Property/ // Behavior if one does not already exist (or one is not already // implied) in the list of Properties/Behaviors generated by // step 2 above (note: only integration has Properties) // // 3) Properties and Behaviors added by the delta Component which // were not already accounted for (used for resolving) by steps // one and two are now processed. Each is tested for the // ability to apply (i.e. must not be reserved). // // Component modifications are processed slightly differently: // // 1) Behaviors and Properties from the base are always carried to // the derived, regardless of access (e.g. private Behaviors) // 2) No step 2b or 2c (interface expansion) // // Complex values (components that carry only state) are a special // case. Since Complex values do not have any Behaviors, the // Properties on a Complex cannot determine whether the Property // values are settable or not. To simplify this, only (and all) // settable Properties are kept on a Complex at the point it // resolves against a Component. // // It is expected that, for the overwhelming majority (perhaps about // 99%) of the time, no additional Properties or Behaviors are going // to be added or removed, and no additional interfaces (integration, // implements, and/or dispatches) are implemented; (in fact, many // child Components will probably be null derivations other than at // their insert level). The implementation is optimized based on // this assumption. // // Note: Behaviors are processed before Properties since the // Property implementation uses the existence of accessors to // determine which attributes can be set during resolve processing. // See the use of Property.isValueSettable() in the implementation // of Property.resolve(). // step 1: match and derive base items, deferring any unmatched StringTable tblDeferBehavior; StringTable tblDeferProperty; if (fSignature) { tblDeferBehavior = new StringTable(); tblDeferProperty = new StringTable(); } else { tblDeferBehavior = new StringTable(INSENS); tblDeferProperty = new StringTable(INSENS); } // process Behaviors first (see note above) if (!fComplex) { StringTable tblBase = base.m_tblBehavior; StringTable tblDelta = delta.matchBehaviors(base, true, (nDeltaMode == DERIVATION), errlist); StringTable tblDerived = derived.m_tblBehavior; // empty StringTable tblDefer = tblDeferBehavior; for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements(); ) { String sSig = (String) enmr.nextElement(); Behavior behBase = (Behavior) tblBase .get(sSig); Behavior behDelta = (Behavior) tblDelta.get(sSig); Behavior behDerived = null; // a derived component cannot "see" private behaviors on the // base component, nor do they inherit constructors of JCS'es if (behBase != null) { if (nDeltaMode == DERIVATION && (behBase.getAccess() == ACCESS_PRIVATE || behBase.isConstructor())) { behBase = null; } } if (behBase == null) { // no matching behavior on the base; must defer resolve // of the delta behavior until interface have been // applied tblDefer.put(sSig, behDelta); } else { if (behDelta != null && behBase.isFinal()) { logError(RESOLVE_BEHAVIORFINAL, WARNING, new Object[] {behDelta.getSignature(), behDelta.toPathString()}, errlist); behDelta = null; } // create a null derivation if no delta exists if (behDelta == null) { behDelta = (Behavior) behBase.getNullDerivedTrait(delta, nDeltaMode); // gg: 2003.11.24 Behavior is EXISTS_NOT if the method is not present // in the class represented by the JCS. if (fSignature && nDeltaMode == DERIVATION) { behDelta.setExists(EXISTS_NOT); } } // apply the delta behDerived = (Behavior) behBase.resolve(behDelta, derived, loader, errlist); tblDerived.put(sSig, behDerived); } } } // process State { StringTable tblBase = base.m_tblState; StringTable tblDelta = delta.matchProperties(base, true, (nDeltaMode == DERIVATION), errlist); StringTable tblDerived = derived.m_tblState; // empty StringTable tblDefer = tblDeferProperty; for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements(); ) { String sProp = (String) enmr.nextElement(); Property propBase = (Property) tblBase .get(sProp); Property propDelta = (Property) tblDelta.get(sProp); Property propDerived = null; if (propBase != null) { // only bring across those properties that are // considered to be complex property properties if (fComplex && !fBaseComplex) { if (!propBase.isComplexPropertyProperty()) { propBase = null; } } // a derived component cannot "see" private base Properties or // base Properties that have only private accessors else if (nDeltaMode == DERIVATION && !propBase.isDerivedBySub()) { propBase = null; } } if (propBase == null) { if (fComplex) { if (propDelta != null) { // complex properties must modify a base logError(RESOLVE_PROPERTYORPHANED, WARNING, new Object[] {propDelta.toString(), delta.toPathString()}, errlist); } } else { // no matching Property on the base; must defer resolve // of the delta Property until integration has been applied tblDefer.put(sProp, propDelta); } } else { // static base properties are not derivable (but are carried) if (propDelta != null && nDeltaMode == DERIVATION && propBase.isStatic()) { // in signature's this is okay and the delta carries forward if (!fSignature) { logError(RESOLVE_PROPERTYSTATIC, WARNING, new Object[] {propDelta.getName(), propDelta.toPathString()}, errlist); propDelta = null; } } // create a null derivation if no delta exists if (propDelta == null) { propDelta = (Property) propBase.getNullDerivedTrait(delta, nDeltaMode); } // apply the delta propDerived = (Property) propBase.resolve(propDelta, derived, loader, errlist); tblDerived.put(sProp, propDerived); } } } // step 2a: expand integration // integration, only at the global level if (!fComplex && parent == null) { Integration integrationBase = base .m_integration; Integration integrationDelta = delta.m_integration; if (integrationBase != null || integrationDelta != null) { // Create an empty base Integration for use in resolving if (integrationBase == null) { integrationBase = new Integration(base, (String) null); } // Create an empty delta Integration for use in resolving if (integrationDelta == null) { integrationDelta = (Integration) integrationBase.getNullDerivedTrait(delta, nDeltaMode); } // Resolve the Integration map Integration integrationDerived = integrationBase.resolve(integrationDelta, derived, derived.m_tblBehavior, derived.m_tblState, tblDeferBehavior, tblDeferProperty, loader, errlist); derived.m_integration = integrationDerived; } } // step 2b, 2c: process added interfaces; expand implements and // dispatches only at derivation level // 2001.05.08 cp allow additional interfaces on modifications if (!fComplex) { // implements StringTable tblBase = base .m_tblImplements; StringTable tblDelta = delta .m_tblImplements; StringTable tblDerived = derived.m_tblImplements; for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements(); ) { String sIface = (String) enmr.nextElement(); if (!tblBase.contains(sIface)) { Interface ifaceDelta = (Interface) tblDelta.get(sIface); Interface ifaceDerived = null; if (nDeltaMode == DERIVATION) { // load the JCS for the interface Component cdJCS = loader.loadSignature(sIface); if (cdJCS == null) { // unable to load Java Class Signature for interface logError(RESOLVE_LOADINTERFACE, WARNING, new Object[] {sIface, ATTR_IMPLEMENTS, derived.getQualifiedName()}, errlist); } else { ifaceDerived = new Interface(derived, cdJCS, false); // 2001.05.08 cp fix origin of interfaces if (ifaceDelta.isFromBase()) { ifaceDerived.setFromBase(); } if (derived.isImplementsAddable(ifaceDerived, cdJCS, errlist)) { // expand the interface try { derived.expandInterface(ifaceDerived, cdJCS, tblDeferBehavior, tblDeferProperty, errlist); } catch (PropertyVetoException e) { logError(RESOLVE_EXPANDINTERFACE, ERROR, new Object[] {sIface, ATTR_IMPLEMENTS, derived.getQualifiedName()}, errlist); throw new DerivationException(e.toString()); } // add the interface to the derived Component tblDerived.put(sIface, ifaceDerived); // if we are a signature, also add all interfaces // extended by this interface // 2001.05.22 cp now that JCSs are designable, this // is no longer the case /* if (fSignature) { String [] asExtends = cdJCS.getImplements(); for (int i = 0; i < asExtends.length; ++i) { sIface = asExtends[i]; if (!tblDerived.contains(sIface)) { Interface ifaceJCS = cdJCS.getImplements(sIface); ifaceDerived = new Interface(derived, ifaceJCS); tblDerived.put(sIface, ifaceDerived); } } } */ } else { // unable to expand interface logError(RESOLVE_EXPANDINTERFACE, WARNING, new Object[] {sIface, ATTR_IMPLEMENTS, derived.getQualifiedName()}, errlist); } } } else { ifaceDerived = new Interface(derived, ifaceDelta); tblDerived.put(sIface, ifaceDerived); } } } // dispatches tblBase = base .m_tblDispatches; tblDelta = delta .m_tblDispatches; tblDerived = derived.m_tblDispatches; for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements(); ) { String sIface = (String) enmr.nextElement(); if (!tblBase.contains(sIface)) { Interface ifaceDelta = (Interface) tblDelta.get(sIface); Interface ifaceDerived = null; if (nDeltaMode == DERIVATION) { // load the JCS for the interface Component cdJCS = loader.loadSignature(sIface); if (cdJCS == null) { // unable to load Java Class Signature for interface logError(RESOLVE_LOADINTERFACE, WARNING, new Object[] {sIface, ATTR_DISPATCHES, derived.getQualifiedName()}, errlist); } else { ifaceDerived = new Interface(derived, cdJCS, true); // 2001.05.08 cp fix origin of interfaces if (ifaceDelta.isFromBase()) { ifaceDerived.setFromBase(); } if (derived.isDispatchesAddable(ifaceDerived, cdJCS, errlist)) { // expand the interface try { derived.expandInterface(ifaceDerived, cdJCS, tblDeferBehavior, tblDeferProperty, errlist); } catch (PropertyVetoException e) { logError(RESOLVE_EXPANDINTERFACE, ERROR, new Object[] {sIface, ATTR_DISPATCHES, derived.getQualifiedName()}, errlist); throw new DerivationException(e.toString()); } // add the interface to the derived Component tblDerived.put(sIface, ifaceDerived); } else { // unable to expand interface logError(RESOLVE_EXPANDINTERFACE, WARNING, new Object[] {sIface, ATTR_DISPATCHES, derived.getQualifiedName()}, errlist); } } } else { ifaceDerived = new Interface(derived, ifaceDelta); tblDerived.put(sIface, ifaceDerived); } } } } // step 3: add deferred Behaviors and Properties if (!fComplex) { if (!tblDeferBehavior.isEmpty()) { StringTable tblBase = base.m_tblBehavior; StringTable tblDelta = tblDeferBehavior; StringTable tblDerived = derived.m_tblBehavior; for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements(); ) { String sSig = (String) enmr.nextElement(); Behavior behBase = (Behavior) tblBase .get(sSig); Behavior behDelta = (Behavior) tblDelta.get(sSig); Behavior behDerived = null; // it is an error if the base Behavior exists, because // all matching Behaviors were supposed to be handled // by step 1; however, there are two exceptions. One when // the base behavior is private and the delta is a derivation, // in which case the base Behavior is not visible to (not // carried to) the derived Component. The other is when // there is an identical constructor on a JCS, it is not // inherited forward to the derived JCS. if (behBase != null) { if (!(nDeltaMode == DERIVATION && (behBase.getAccess() == ACCESS_PRIVATE || behBase.isConstructor()))) { throw new IllegalStateException(CLASS + ".resolve: " + "Deferred Behavior has match in base! (" + sSig + ")"); } } if (tblDerived.contains(sSig) || derived.isBehaviorReserved(sSig)) { // discard the delta logError(RESOLVE_BEHAVIORRESERVED, WARNING, new Object[] {behDelta.getSignature(), behDelta.toPathString()}, errlist); } else { // nothing to apply to, just copy the Behavior // information to the derived Component behDerived = new Behavior(derived, behDelta); tblDerived.put(sSig, behDerived); } } } if (!tblDeferProperty.isEmpty()) { StringTable tblBase = base.m_tblState; StringTable tblDelta = tblDeferProperty; StringTable tblDerived = derived.m_tblState; for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements();) { String sProp = (String) enmr.nextElement(); Property propBase = (Property) tblBase .get(sProp); Property propDelta = (Property) tblDelta.get(sProp); Property propDerived = null; // if the delta is a DERIVATION and the base Property // is not carried to derived Components, then it is // as if the base Property does not exist. Otherwise // it is an error since all carried base Properties // were supposed to be handled by step 1 if (propBase != null && !(nDeltaMode == DERIVATION && !propBase.isDerivedBySub())) { throw new IllegalStateException(CLASS + ".resolve: " + "Deferred Property has match in base! (" + sProp + ")"); } // can only determine real conflicts on a DERIVATION if (nDeltaMode == DERIVATION && propDelta.getExists() != EXISTS_INSERT) { // the derived property is discarded logError(RESOLVE_PROPERTYORPHANED, WARNING, new Object[] {propDelta.toString(), delta.toPathString()}, errlist); } else if (Property.isCreatable(derived, propDelta.getDataType(), sProp, propDelta.getIndexed(), propDelta.isStatic(), propDelta.getDirection(), propDelta.isConstant())) { // nothing to apply to, just copy the Property // information to the derived Component propDerived = new Property(derived, propDelta); tblDerived.put(sProp, propDerived); } else { // discard the delta // TODO if the discarded prop is not "from this" // then this is an error condition, right? // it means that something is out of synch // but not at this modification level so // there is no way to fix it! same goes for // behaviors, integration, and interfaces! logError(RESOLVE_PROPERTYRESERVED, WARNING, new Object[] {propDelta.getName(), propDelta.toPathString()}, errlist); } } } } // ----- aggregation if (!fComplex) { // resolve the aggregate categories StringTable tblCategories = derived.m_tblCategories; // all categories from the delta are marked as TRUE Boolean TRUE = Boolean.TRUE; for (Enumeration enmr = delta.m_tblCategories.keys(); enmr.hasMoreElements(); ) { tblCategories.put((String) enmr.nextElement(), TRUE); } // all categories from the base are marked as FALSE // (any categories from the delta that are also in the base are // purposefully overwritten, since the delta is a delta) Boolean FALSE = Boolean.FALSE; for (Enumeration enmr = base.m_tblCategories.keys(); enmr.hasMoreElements(); ) { tblCategories.put((String) enmr.nextElement(), FALSE); } // resolve the child Component derivations/modifications: StringTable tblBase = base.m_tblChildren; StringTable tblDelta = delta.matchChildren(base, true, errlist); StringTable tblDerived = derived.m_tblChildren; // empty for (Enumeration enmr = tblDelta.keys(); enmr.hasMoreElements(); ) { String sChild = (String) enmr.nextElement(); Component cdBase = (Component) tblBase .get(sChild); Component cdDelta = (Component) tblDelta.get(sChild); Component cdDerived = null; // if the delta is an insert child (i.e. no base child) then // resolve it against the global component from which it // derives; (note: the check for if the base is resolved is // used to defer the resolve of the child from the global // until it is the last or "outermost" resolve ... in other // words, all components in the parent/child hierarchy // become resolved at the same time) if (cdBase == null && fBaseResolved && cdDelta.getExists() == EXISTS_INSERT) { // load the global super (which may throw an exception) cdBase = loader.loadComponent(cdDelta.getSuperName(), true, errlist); if (cdBase == null) { // global Component does not exist logError(RESOLVE_CHILDORPHANED, WARNING, new Object[] {cdDelta.toString(), delta.toPathString()}, errlist); } else if (cdBase.isFinal()) { // cannot derive from final global Component logError(RESOLVE_GLOBALFINAL, WARNING, new Object[] {cdDelta.getName(), cdBase.getQualifiedName(), cdDelta.toPathString()}, errlist); cdBase = null; } else if (!derived.isChildSuperLegal(cdBase.getQualifiedName())) { // base Component doesn't fit a category // (aka illegal super) logError(RESOLVE_NOCATEGORY, WARNING, new Object[] {cdDelta.toString(), cdBase.toString(), delta.toPathString()}, errlist); cdBase = null; } } if (cdBase == null) { if (fBaseResolved) { // discard the delta child logError(RESOLVE_CHILDORPHANED, WARNING, new Object[] {cdDelta.toString(), delta.toPathString()}, errlist); } else { // just copy the child derivation/modification to the // derived component; it is expected for modification // levels that most base children will not exist cdDerived = new Component(derived, cdDelta); } } else { int nBaseChildFlags = cdBase.m_nFlags; if (cdDelta != null) { // check if base child is final and if so discard delta if ((nBaseChildFlags & DERIVE_MASK) == DERIVE_FINAL && (cdBase.getMode() == RESOLVED || (nBaseChildFlags & DERIVE_SPECIFIED) != 0)) { logError(RESOLVE_LOCALFINAL, WARNING, new Object[] {cdDelta.getName(), cdDelta.toPathString()}, errlist); cdDelta = null; } } // check if the Component should exist at all - // 1) deriving from a DELETE, result is a NOT // 2) deriving from or modifying a NOT, result is a NOT // 3) allow modification of a DELETE (becomes DELETE with // previous DELETE) in order to carry the DELETE until // something is found to DELETE if ((nBaseChildFlags & EXISTS_MASK) == EXISTS_NOT || (nBaseChildFlags & EXISTS_MASK) == EXISTS_DELETE && nDeltaMode == DERIVATION) { // a blank EXISTS_NOT component just reserves the name cdDerived = (Component) cdBase.getBlankDerivedTrait(derived, cdBase.getMode()); cdDerived.setExists(EXISTS_NOT); } else { // create a null derivation if no delta exists if (cdDelta == null) { cdDelta = (Component) cdBase.getNullDerivedTrait(delta, nDeltaMode); } // apply the delta cdDerived = (Component) cdBase.resolve(cdDelta, derived, loader, errlist); } } if (cdDerived != null) { tblDerived.put(sChild, cdDerived); } } } return derived; } /** * Resolve delta in flags. Components use the following flags: * Exists, Visible, Access (JCS only), Static, Abstract, Final, * Deprecation, Storage, and Distribution. * * implementation note: a flag value is always meaningful if the * Component is resolved; otherwise it is meaningful only if the * specific attribute is specified; for example: * * (fBaseResolved || (nBaseFlags & _SPECIFIED) != 0) * * @param nBaseFlags the flags to use as the base flags * @param nDeltaFlags the flags to use as the delta flags * * @return the derived flags */ protected int resolveFlags(int nBaseFlags, int nDeltaFlags) { // for general use below boolean fSignature = isSignature(); // derived flags always start as the base flags; then the delta flags // are applied int nDerivedFlags = nBaseFlags; // optimization: check for nothing specified if (nDeltaFlags == 0) { return nDerivedFlags; } // flags cannot be changed if the base flags are final boolean fBaseResolved = (getMode() == RESOLVED); if ((fBaseResolved || (nBaseFlags & DERIVE_SPECIFIED) != 0) && (nBaseFlags & DERIVE_MASK) == DERIVE_FINAL) { return nDerivedFlags; } // the visible attribute is flexible if ((nDeltaFlags & VIS_SPECIFIED) != 0) { nDerivedFlags = nDerivedFlags & ~VIS_FULLMASK | nDeltaFlags & VIS_FULLMASK; } // for signatures the access attribute is one-way: private to protected to public if (fSignature) { int nBaseAccess = (nBaseFlags & ACCESS_MASK); int nDeltaAccess = (nDeltaFlags & ACCESS_MASK); int nDerivedAccess = nDeltaAccess; if ((fBaseResolved || (nBaseFlags & ACCESS_SPECIFIED) != 0) && nDeltaAccess != nBaseAccess) { // specified on base and in delta; verify delta is legal switch (nBaseAccess) { case ACCESS_PRIVATE: // from private to protected or public is allowed for // modification only -- otherwise delta is an error // since private behaviors from the super are dropped // altogether in a derivation break; case ACCESS_PROTECTED: // from protected to public is legal if (nDeltaAccess == ACCESS_PUBLIC) { break; } // no break; case ACCESS_PUBLIC: // from public to protected or private is not legal nDerivedAccess = nBaseAccess; break; } } nDerivedFlags = nDerivedFlags & ~ACCESS_MASK | ACCESS_SPECIFIED | nDerivedAccess; } // the scope attribute is one-way from instance to static if ( (nDeltaFlags & SCOPE_SPECIFIED) != 0 && (nDeltaFlags & SCOPE_MASK) == SCOPE_STATIC) { nDerivedFlags = nDerivedFlags & ~SCOPE_FULLMASK | nDeltaFlags & SCOPE_FULLMASK; } // the abstract attribute is flexible if (fSignature || (nDeltaFlags & IMPL_SPECIFIED) != 0) { nDerivedFlags = nDerivedFlags & ~IMPL_FULLMASK | nDeltaFlags & IMPL_FULLMASK; } // the final attribute is one-way if ((fSignature || (nDeltaFlags & DERIVE_SPECIFIED) != 0) && (nDeltaFlags & DERIVE_MASK) == DERIVE_FINAL) { nDerivedFlags = nDerivedFlags & ~DERIVE_FULLMASK | nDeltaFlags & DERIVE_FULLMASK; } // the antiquity (deprecated) attribute is flexible if (fSignature || (nDeltaFlags & ANTIQ_SPECIFIED) != 0) { nDerivedFlags = nDerivedFlags & ~ANTIQ_FULLMASK | nDeltaFlags & ANTIQ_FULLMASK; } // the storage (persistence) attribute is flexible if ((nDeltaFlags & STG_SPECIFIED) != 0) { nDerivedFlags = nDerivedFlags & ~STG_FULLMASK | nDeltaFlags & STG_FULLMASK; } // the distribution (remote) attribute is one-way and is specifiable // only on global Components if ( (nDeltaFlags & DIST_SPECIFIED) != 0 && (nDeltaFlags & DIST_MASK) == DIST_REMOTE) { nDerivedFlags = nDerivedFlags & ~DIST_FULLMASK | nDeltaFlags & DIST_FULLMASK; } if ((nDeltaFlags & MISC_ISINTERFACE) != 0) { nDerivedFlags |= MISC_ISINTERFACE; } if ((nDeltaFlags & MISC_ISTHROWABLE) != 0) { nDerivedFlags |= MISC_ISTHROWABLE; } return nDerivedFlags; } /** * Complete the resolve processing for this Component and its sub-traits. * * @param loader the Loader object for JCS, CIM, and CD dependencies * @param errlist the error list object to log error information to * * @exception ComponentException thrown only if a fatal error occurs */ public synchronized void finalizeResolve(Loader loader, ErrorList errlist) throws ComponentException { super.finalizeResolve(loader, errlist); // remove all "specified" flags m_nFlags &= ~ALL_SPECIFIED; m_nPrevFlags &= ~ALL_SPECIFIED; // resolve sub-traits: Integration if (m_integration != null) { m_integration.finalizeResolve(loader, errlist); } // resolve sub-traits: Implements for (Enumeration enmr = m_tblImplements.elements(); enmr.hasMoreElements(); ) { Interface iface = (Interface) enmr.nextElement(); iface.finalizeResolve(loader, errlist); } // resolve sub-traits: Dispatches for (Enumeration enmr = m_tblDispatches.elements(); enmr.hasMoreElements(); ) { Interface iface = (Interface) enmr.nextElement(); iface.finalizeResolve(loader, errlist); } // resolve sub-traits: Properties for (Enumeration enmr = m_tblState.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); prop.finalizeResolve(loader, errlist); } // resolve sub-traits: Behaviors for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); behavior.finalizeResolve(loader, errlist); } // resolve sub-traits: Children for (Enumeration enmr = m_tblChildren.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); cd.finalizeResolve(loader, errlist); } // discard origin-less Properties for (Enumeration enmr = m_tblState.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); if (prop.isDiscardable()) { m_tblState.remove(prop.getUniqueName()); prop.invalidate(); } } // discard origin-less Behaviors for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); if (behavior.isDiscardable()) { m_tblBehavior.remove(behavior.getUniqueName()); behavior.invalidate(); } } // discard origin-less Children for (Enumeration enmr = m_tblChildren.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); if (cd.isDiscardable()) { m_tblChildren.remove(cd.getUniqueName()); cd.invalidate(); } } // gg: 2002.02.13 Clear UID for global components if (isGlobal() && getUID() != null) { logError(RESOLVE_UIDCHANGE, WARNING, new Object[] {getName(), "Global UID must be null"}, errlist); clearUID(); } validate(); } /** * Determine the mode of extraction assuming the passed base Trait were * being exctracted from this derived Trait. * * This method must be overridden by any Trait which can determine * whether the extraction is for a DERIVATION or MODIFICATION. * (Component is the only trait which can differentiate.) * * @param traitBase the base Trait to extract * * @return DERIVATION or MODIFICATION */ protected int getExtractMode(Trait traitBase) { switch (m_nType) { case COMPONENT: { Component base = (Component) traitBase; if (base.m_sName.length() == 0) { // root component is a derivation if this is not also the root component return (this.m_sName.length() == 0 ? MODIFICATION : DERIVATION); } else if (this.getParent() == null) { // global component is a derivation if super is different // 2001.04.27 cp this appears to have been done in this manner // to support save-as processing; otherwise, it would have been // done as a comparison of qualified component names return (this.m_sSuper.equals(base.m_sSuper) ? MODIFICATION : DERIVATION); } else if (base.getParent() == null) { // child is a derivation if the base is global return DERIVATION; } } break; case SIGNATURE: { // Signatures are always extracted as DERIVATIONs // return DERIVATION; Component base = (Component) traitBase; return this.m_sName.equals(base.m_sName) ? MODIFICATION : DERIVATION; } case COMPLEX: // complex properties are always extracted as MODIFICATIONs return MODIFICATION; } return super.getExtractMode(traitBase); } /** * Create a derivation/modification Component by determining the delta * between the derived Component ("this") and the passed base Component. * * @param cdBase the base Component to extract * @param loader the Loader object for JCS, CIM, and CD dependencies * @param errlist the error list object to log error information to * * @return the delta between this Component and the base Component * * @exception ComponentException thrown only if a fatal error occurs */ public Component extract(Component cdBase, Loader loader, ErrorList errlist) throws ComponentException { // validate base component definition if (cdBase == null) { throw new IllegalArgumentException(CLASS + ".extract: " + "Base Component required!"); } if (this.m_nType != COMPONENT && this.m_nType != SIGNATURE) { throw new IllegalArgumentException(CLASS + ".extract: " + "Derived is not a Component or Java Class Signature!"); } if (this.m_nType != cdBase.m_nType) { throw new IllegalArgumentException(CLASS + ".extract: " + "Base type (" + cdBase.m_nType + ") != Derived type (" + this.m_nType + ")"); } return (Component) extract(cdBase, null, loader, errlist); } /** * Create a derivation/modification Trait by determining the differences * between the derived Trait ("this") and the passed base Trait. Neither * the derived Trait ("this") nor the base may be modified in any way. * * @param traitBase the base Trait to extract * @param parent the Trait which will contain the resulting Trait or * null if the resulting Trait will not be contained * @param loader the Loader object for JCS, CIM, and CD dependencies * @param errlist the error list object to log error information to * * @return the delta between this derived Trait and the base Trait * * @exception ComponentException thrown only if a fatal error occurs */ protected Trait extract(Trait traitBase, Trait parent, Loader loader, ErrorList errlist) throws ComponentException { Component derived = this; Component base = (Component) traitBase; Component delta = (Component) super.extract(base, parent, loader, errlist); // determine if the base is resolved (which means all base attributes // are specified, i.e. have a value) boolean fBaseResolved = (base.getMode() == RESOLVED); // determine if extracting a DERIVATION or MODIFICATION int nDeltaMode = delta.getMode(); // a complex Property value is implemented using the Component // Definition data structure; a complex value is extracted // either from another complex value or from a global Component boolean fComplex = (derived.m_nType == COMPLEX); boolean fBaseComplex = (base .m_nType == COMPLEX); // ----- identity ---------------------------------------------- if (fComplex) { if (fBaseComplex) { delta.m_nFlags = EXISTS_UPDATE; } else { delta.m_nType = COMPLEX; delta.m_nFlags = EXISTS_SPECIFIED | EXISTS_INSERT; } delta.m_sSuper = derived.m_sSuper; delta.m_sName = derived.m_sName; } else { // attributes represented as bit flags; see the length note in the // corresponding section of the extract method in Component.java int nBaseFlags = base .m_nFlags; int nDerivedFlags = derived.m_nFlags; int nDifFlags = nBaseFlags ^ nDerivedFlags; int nDeltaFlags = nDerivedFlags & ~ALL_SPECIFIED; // extract exists int nBaseExists = nBaseFlags & EXISTS_MASK; int nDerivedExists = nDerivedFlags & EXISTS_MASK; int nDeltaExists = EXISTS_UPDATE; if (base.getParentTrait() == null && derived.getParentTrait() != null) { // an insert component exists when the base is global and the // derived component is a child nDeltaExists = EXISTS_SPECIFIED | EXISTS_INSERT; } else if (nDerivedExists == EXISTS_DELETE && (nBaseExists == EXISTS_INSERT || nBaseExists == EXISTS_UPDATE)) { // derived component deletes the base nDeltaExists = EXISTS_SPECIFIED | EXISTS_DELETE; } nDeltaFlags = nDeltaFlags & ~EXISTS_FULLMASK | nDeltaExists; // visible if ((nDifFlags & VIS_MASK) != 0 && (fBaseResolved || (nBaseFlags & VIS_SPECIFIED) != 0)) { nDeltaFlags |= VIS_SPECIFIED; } // scope if ((nDifFlags & SCOPE_MASK) != 0 && (fBaseResolved || (nBaseFlags & SCOPE_SPECIFIED) != 0)) { nDeltaFlags |= SCOPE_SPECIFIED; } // abstract if ((nDifFlags & IMPL_MASK) != 0 && (fBaseResolved || (nBaseFlags & IMPL_SPECIFIED) != 0)) { nDeltaFlags |= IMPL_SPECIFIED; } // final if ((nDifFlags & DERIVE_MASK) != 0 && (fBaseResolved || (nBaseFlags & DERIVE_SPECIFIED) != 0)) { nDeltaFlags |= DERIVE_SPECIFIED; } // antiquity if ((nDifFlags & ANTIQ_MASK) != 0 && (fBaseResolved || (nBaseFlags & ANTIQ_SPECIFIED) != 0)) { nDeltaFlags |= ANTIQ_SPECIFIED; } // storage if ((nDifFlags & STG_MASK) != 0 && (fBaseResolved || (nBaseFlags & STG_SPECIFIED) != 0)) { nDeltaFlags |= STG_SPECIFIED; } // distribution if ((nDifFlags & DIST_MASK) != 0 && (fBaseResolved || (nBaseFlags & DIST_SPECIFIED) != 0)) { nDeltaFlags |= DIST_SPECIFIED; } // extract identity if (nDeltaMode == DERIVATION) { if (parent == null || nDeltaExists == (EXISTS_SPECIFIED | EXISTS_INSERT)) { // derives from a global component delta.m_sSuper = base.getQualifiedName(); delta.m_sName = derived.m_sName; } else { // derives from a local component delta.m_sSuper = base.m_sSuper; delta.m_sName = base.m_sName; } // integration only happens at a global derivation level Integration integrationBase = base.m_integration; Integration integrationDerived = derived.m_integration; Integration integrationDelta = null; // We only have to bother if the derived has integration // (since integration can not be removed) if (integrationDerived != null) { // Check if this is the first integration applied // to this component tree if (integrationBase == null) { // It is, just copy it across integrationDelta = new Integration(base, integrationDerived); } else { // extract the delta integrationDelta = (Integration) integrationDerived.extract(integrationBase, delta, loader, errlist); } } delta.m_integration = integrationDelta; delta.m_fBaseLevel = true; } else { // modification keeps the Component identity from the base delta.m_sSuper = base.m_sSuper; delta.m_sName = base.m_sName; // modification means not at the base level // (modification cannot integrate) delta.m_fBaseLevel = false; } // store flags delta.m_nFlags = nDeltaFlags; delta.m_nPrevFlags = 0; // determine the interfaces which are implemented/dispatched by // the derived but not the base Component // (most common case: the sets of interfaces are identical // or (for modifications) that the derived has no interfaces) // extract Implements // 2001.05.08 cp removed "DERIVATION" check to allow // modifications to add interfaces StringTable tblBase = base .m_tblImplements; StringTable tblDerived = derived.m_tblImplements; StringTable tblDelta = delta .m_tblImplements; if (!tblDerived.isEmpty() && !tblDerived.keysEquals(tblBase)) { for (Enumeration enmr = tblDerived.keys(); enmr.hasMoreElements(); ) { String sIface = (String) enmr.nextElement(); if (!tblBase.contains(sIface)) { // get the interface that was added Interface iface = (Interface) tblDerived.get(sIface); // copy it to the delta component tblDelta.put(sIface, new Interface(delta, iface)); } } } // extract Dispatches tblBase = base .m_tblDispatches; tblDerived = derived.m_tblDispatches; tblDelta = delta .m_tblDispatches; if (!tblDerived.isEmpty() && !tblDerived.keysEquals(tblBase)) { for (Enumeration enmr = tblDerived.keys(); enmr.hasMoreElements(); ) { String sIface = (String) enmr.nextElement(); if (!tblBase.contains(sIface)) { // get the interface that was added Interface iface = (Interface) tblDerived.get(sIface); // copy it to the delta component tblDelta.put(sIface, new Interface(delta, iface)); } } } } // ----- state { StringTable tblBase = base.m_tblState; StringTable tblDerived = derived.matchProperties(base, false, (nDeltaMode == DERIVATION), errlist); StringTable tblDelta = delta.m_tblState; // empty for (Enumeration enmr = tblDerived.keys(); enmr.hasMoreElements(); ) { String sProp = (String) enmr.nextElement(); Property propBase = (Property) tblBase .get(sProp); Property propDerived = (Property) tblDerived.get(sProp); Property propDelta = null; if (propDerived != null && ( propDerived.getExists() == EXISTS_NOT || propDerived.getExists() == EXISTS_DELETE)) { continue; } if (propBase != null) { // only bring across those properties that are // considered to be complex property properties if (fComplex && !fBaseComplex) { if (!propBase.isComplexPropertyProperty()) { propBase = null; } } // a derived component cannot "see" private constants or // properties that have all private accessors on the base // component else if (nDeltaMode == DERIVATION && !propBase.isDerivedBySub()) { propBase = null; } } if (propBase == null) { if (fComplex) { if (propDelta != null) { // complex properties must modify a base logError(RESOLVE_PROPERTYORPHANED, WARNING, new Object[] {propDelta.toString(), delta.toPathString()}, errlist); } } else if (nDeltaMode == DERIVATION && propDerived.getExists() != EXISTS_INSERT) { // the derived property is discarded logError(EXTRACT_PROPERTYORPHANED, WARNING, new Object[] {propDerived.toString(), derived.toPathString()}, errlist); } else { // just copy the property derivation/modification to // the delta component propDelta = new Property(delta, propDerived); // allow properties to initialize the extract process, this is // specifically to allow properties to extract base components // from any complex property values stored in the property // note that this must be done with a loader that can load // completely resolved components for the extraction performed // against the complex property values // see Property.java header comments related to complex property // support if (nDeltaMode == DERIVATION) { propDelta.initializeExtract(loader, errlist); } } } // only extract delta if the super property is not static else if (propDerived != null && !(nDeltaMode == DERIVATION && propBase.isStatic())) { // extract the delta propDelta = (Property) propDerived.extract(propBase, delta, loader, errlist); } if (propDelta != null) { tblDelta.put(sProp, propDelta); } } } // ----- behavior if (!fComplex) { StringTable tblBase = base.m_tblBehavior; StringTable tblDerived = derived.matchBehaviors(base, false, (nDeltaMode == DERIVATION), errlist); StringTable tblDelta = delta.m_tblBehavior; // empty for (Enumeration enmr = tblDerived.keys(); enmr.hasMoreElements(); ) { String sSig = (String) enmr.nextElement(); Behavior behBase = (Behavior) tblBase .get(sSig); Behavior behDerived = (Behavior) tblDerived.get(sSig); Behavior behDelta = null; // a derived component cannot "see" private behaviors on the // base component, nor constructors on JCS if (behBase != null && nDeltaMode == DERIVATION && (behBase.getAccess() == ACCESS_PRIVATE || behBase.isConstructor())) { behBase = null; } if (behBase == null) { if (nDeltaMode == DERIVATION && behDerived.getExists() != EXISTS_INSERT) { // the derived behavior is discarded logError(EXTRACT_BEHAVIORORPHANED, WARNING, new Object[] {behDerived.toString(), derived.toPathString()}, errlist); } else { // just copy the behavior derivation/modification to // the delta component behDelta = new Behavior(delta, behDerived); } } // only extract delta if the base behavior is not final else if (behDerived != null && !behBase.isFinal()) { // extract the delta behDelta = (Behavior) behDerived.extract(behBase, delta, loader, errlist); } if (behDelta != null) { tblDelta.put(sSig, behDelta); } } } // ----- aggregation if (!fComplex) { // extract Categories StringTable tblBase = base .m_tblCategories; StringTable tblDerived = derived.m_tblCategories; StringTable tblDelta = delta .m_tblCategories; if (!tblDerived.isEmpty() && !tblDerived.keysEquals(tblBase)) { Boolean TRUE = Boolean.TRUE; for (Enumeration enmr = tblDerived.keys(); enmr.hasMoreElements(); ) { String sCat = (String) enmr.nextElement(); if (!tblBase.contains(sCat)) { tblDelta.put(sCat, TRUE); } } } // extract the child Component derivations/modifications; // at the derivation level, all children are either extracted as // derivations or discarded; at modification levels, matching // children between the base and derived components are extracted // as modifications, but non matching children are copied, // potentially remaining derivations (which implies that they // were added at a modification level) tblBase = base.m_tblChildren; tblDerived = derived.matchChildren(base, false, errlist); tblDelta = delta.m_tblChildren; // empty for (Enumeration enmr = tblDerived.keys(); enmr.hasMoreElements(); ) { String sChild = (String) enmr.nextElement(); Component cdBase = (Component) tblBase .get(sChild); Component cdDerived = (Component) tblDerived.get(sChild); Component cdDelta = null; // if the derived is an insert child (i.e. no base child) // then extract the global component from which it derives; if (cdBase == null && nDeltaMode == DERIVATION && cdDerived.getExists() == EXISTS_INSERT) { // load the global super (which may throw an exception) cdBase = loader.loadComponent(cdDerived.getSuperName(), true, errlist); if (cdBase == null) { // global Component does not exist logError(EXTRACT_CHILDORPHANED, WARNING, new Object[] {cdDerived.toString(), derived.toPathString()}, errlist); } else if (cdBase.isFinal()) { // cannot derive from final global Component logError(EXTRACT_GLOBALFINAL, WARNING, new Object[] {cdBase.toString(), derived.toPathString()}, errlist); cdBase = null; } else if (!derived.isChildSuperLegal(cdBase.getQualifiedName())) { // base Component doesn't fit a category // (aka illegal super) logError(EXTRACT_NOCATEGORY, WARNING, new Object[] {cdDerived.toString(), cdBase.toString(), derived.toPathString()}, errlist); cdBase = null; } } if (cdBase == null) { if (nDeltaMode == DERIVATION) { // the derived child is discarded logError(EXTRACT_CHILDORPHANED, WARNING, new Object[] {cdDerived.toString(), derived.toPathString()}, errlist); } else { // just copy the child derivation/modification to the // delta component cdDelta = new Component(delta, cdDerived); } } else { if (cdDerived != null) { // check if base child is final and if so discard // the derived child int nBaseChildFlags = cdBase.m_nFlags; if ((nBaseChildFlags & DERIVE_MASK) == DERIVE_FINAL && (cdBase.getMode() == RESOLVED || (nBaseChildFlags & DERIVE_SPECIFIED) != 0)) { // this is not an error on extract, although it // is possible that information is being lost; // when a final child exists, it is resolved // with a null derivation, so when it extracts // it will be a null derivation (assuming no // concurrency/transactional issues) cdDerived = null; } // discard all derivations and modifications from // DELETEs and NOTs else if ((nBaseChildFlags & EXISTS_MASK) == EXISTS_NOT || (nBaseChildFlags & EXISTS_MASK) == EXISTS_DELETE) { // for the reasons above, this is not an error cdDerived = null; } } if (cdDerived != null) { // extract the delta cdDelta = (Component) cdDerived.extract(cdBase, delta, loader, errlist); } } if (cdDelta != null) { tblDelta.put(sChild, cdDelta); } } } return delta; } /** * Finalize the extract process. This means that this trait will not * be asked to extract again. A trait is considered persistable after * it has finalized the extract process. * * @param loader the Loader object for JCS, CIM, and CD dependencies * @param errlist the error list object to log error information to * * @exception ComponentException thrown only if a fatal error occurs */ public synchronized void finalizeExtract(Loader loader, ErrorList errlist) throws ComponentException { // root component (at base level) does not finalize extraction if (getMode() == RESOLVED && m_sSuper == BLANK) { return; } // gg: 2002.02.13 Clear UID for global components if (isGlobal()) { clearUID(); } super.finalizeExtract(loader, errlist); // extract sub-traits: Integration if (m_integration != null) { m_integration.finalizeExtract(loader, errlist); } // resolve sub-traits: Implements for (Enumeration enmr = m_tblImplements.elements(); enmr.hasMoreElements(); ) { Interface iface = (Interface) enmr.nextElement(); iface.finalizeExtract(loader, errlist); } // resolve sub-traits: Dispatches for (Enumeration enmr = m_tblDispatches.elements(); enmr.hasMoreElements(); ) { Interface iface = (Interface) enmr.nextElement(); iface.finalizeExtract(loader, errlist); } // resolve sub-traits: Properties for (Enumeration enmr = m_tblState.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); prop.finalizeExtract(loader, errlist); } // resolve sub-traits: Behaviors for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); behavior.finalizeExtract(loader, errlist); } // resolve sub-traits: Children for (Enumeration enmr = m_tblChildren.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); cd.finalizeExtract(loader, errlist); } // discard blank Implements for (Enumeration enmr = m_tblImplements.elements(); enmr.hasMoreElements(); ) { Interface iface = (Interface) enmr.nextElement(); if (iface.isDiscardable()) { m_tblImplements.remove(iface.getUniqueName()); iface.invalidate(); } } // discard blank Dispatches for (Enumeration enmr = m_tblDispatches.elements(); enmr.hasMoreElements(); ) { Interface iface = (Interface) enmr.nextElement(); if (iface.isDiscardable()) { m_tblDispatches.remove(iface.getUniqueName()); iface.invalidate(); } } // discard blank Properties for (Enumeration enmr = m_tblState.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); if (prop.isDiscardable()) { m_tblState.remove(prop.getUniqueName()); prop.invalidate(); } } // discard blank Behaviors for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); if (behavior.isDiscardable()) { m_tblBehavior.remove(behavior.getUniqueName()); behavior.invalidate(); } } // discard blank Children for (Enumeration enmr = m_tblChildren.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); if (cd.isDiscardable()) { m_tblChildren.remove(cd.getUniqueName()); cd.invalidate(); } } } /** * Match up the Properties from the base and this Component. Return a * StringTable of Properties to resolve or extract from the base. The * returned StringTable must not be modified. * * The returned table may have null values which imply null derivations. * * The returned table may have additional Properties that were added by * the delta or derived Component. * * (Neither the base nor this Component are modified by this method.) * * @param base the super or base level Component * @param fResolve true if being RESOLVED * @param fDerive true if extracting/resolving a DERIVATION * @param errlist the error list to log any mismatches to * * @exception DerivationException */ protected StringTable matchProperties(Component base, boolean fResolve, boolean fDerive, ErrorList errlist) throws DerivationException { StringTable tblThis = this.m_tblState; StringTable tblBase = base.m_tblState; StringTable tblResult = tblThis; // most common case for extract: exact match if (tblThis.keysEquals(tblBase)) { return tblResult; } // create results table (since we cannot change the "this" table); tblResult = new StringTable(); // most common for resolve: no properties in the delta if (tblThis.isEmpty()) { // copy keys from base (but leave Properties null to signify null // derivations) for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); if (!fDerive || prop.isDerivedBySub()) { tblResult.put(prop.getUniqueName(), null); } } return tblResult; } // build look up tables by UID and unique name // this extended processing will only happen at levels which add, // remove, or modify Properties (considered to be rare) Hashtable tblByUID = new Hashtable(); StringTable tblByName = new StringTable(); for (Enumeration enmr = tblThis.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); UID uid = prop.getUID(); if (uid != null) { tblByUID.put(uid, prop); } tblByName.put(prop.getUniqueName(), prop); } // look up by UID; remove each one found from the name look up table if (!tblByUID.isEmpty()) { for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Property propBase = (Property) enmr.nextElement(); UID uid = propBase.getUID(); if (uid != null) { Property propThis = (Property) tblByUID.get(uid); if (propThis != null && (!fDerive || propBase.isDerivedBySub())) { tblResult.put(propBase.getUniqueName(), propThis); tblByName.remove(propThis.getUniqueName()); } } } } // look up by name for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Property propBase = (Property) enmr.nextElement(); if (!fDerive || propBase.isDerivedBySub()) { String sProp = propBase.getUniqueName(); if (!tblResult.contains(sProp)) { // find the Property on this Component with the same name; // whether or not one exists, reserve the name in the result Property propThis = (Property) tblByName.get(sProp); tblResult.put(sProp, propThis); // only leave unmatched Properties in tblByName // (so they can be added to the results or discarded) if (propThis != null) { tblByName.remove(sProp); } } } } // keep additional Properties (but discard any conflicting ones) for (Enumeration enmr = tblByName.elements(); enmr.hasMoreElements(); ) { Property prop = (Property) enmr.nextElement(); String sProp = prop.getUniqueName(); // check for conflict (this happens when a base Property is // renamed which conflicts if another Property was added at // this level and coincidentally has the same name) if (tblResult.contains(sProp)) { String sCode = (fResolve ? RESOLVE_PROPERTYDISCARDED : EXTRACT_PROPERTYDISCARDED); logError(sCode, WARNING, new Object[] {sProp, toPathString()}, errlist); } else { tblResult.put(sProp, prop); } } return tblResult; } /** * Match up the behaviors from the base and this Component. Return a * StringTable of behaviors to resolve or extract from the base. The * returned StringTable must not be modified. * * The returned table may have null values which imply null derivations. * * The returned table may have additional behaviors that were added by * the delta or derived Component. * * (Neither the base nor this Component are modified by this method.) * * @param base the super or base level Component * @param fResolve true if being RESOLVED * @param fDerive true if extracting/resolving a DERIVATION * @param errlist the error list to log any mismatches to * * @return a const StringTable mapping ... * * @exception DerivationException */ protected StringTable matchBehaviors(Component base, boolean fResolve, boolean fDerive, ErrorList errlist) throws DerivationException { StringTable tblThis = this.m_tblBehavior; StringTable tblBase = base.m_tblBehavior; StringTable tblResult = tblThis; // most common case for extract: exact match if (tblThis.keysEquals(tblBase)) { return tblResult; } // create results table (since we cannot change the "this" table); tblResult = new StringTable(); // most common for resolve: no behaviors in the delta if (tblThis.isEmpty()) { // copy keys from base (but leave behaviors null to signify null // derivations) for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); if (!(fDerive && (behavior.getAccess() == ACCESS_PRIVATE || behavior.isConstructor()))) { tblResult.put(behavior.getUniqueName(), null); } } return tblResult; } // build look up tables by UID and unique name (aka signature) // this extended processing will only happen at levels which add, // remove, or modify behaviors (considered to be rare) Hashtable tblByUID = new Hashtable(); StringTable tblByName = new StringTable(); for (Enumeration enmr = tblThis.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); UID uid = behavior.getUID(); if (uid != null) { tblByUID.put(uid, behavior); } tblByName.put(behavior.getUniqueName(), behavior); } // look up by UID; remove each one found from the name look up table if (!tblByUID.isEmpty()) { for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Behavior behBase = (Behavior) enmr.nextElement(); UID uid = behBase.getUID(); if (uid != null) { Behavior behThis = (Behavior) tblByUID.get(uid); if (behThis != null && !(fDerive && (behBase.getAccess() == ACCESS_PRIVATE || behBase.isConstructor()))) { tblResult.put(behBase.getUniqueName(), behThis); tblByName.remove(behThis.getUniqueName()); } } } } // look up by name for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Behavior behBase = (Behavior) enmr.nextElement(); if (!(fDerive && (behBase.getAccess() == ACCESS_PRIVATE || behBase.isConstructor()))) { String sSig = behBase.getUniqueName(); if (!tblResult.contains(sSig)) { // find the Behavior on this Component with the same name; // whether or not one exists, reserve the name in the result Behavior behThis = (Behavior) tblByName.get(sSig); tblResult.put(sSig, behThis); // only leave unmatched Behaviors in tblByName // (so they can be added to the results or discarded) if (behThis != null) { tblByName.remove(sSig); } } } } // keep additional Behaviors (but discard any conflicting ones) for (Enumeration enmr = tblByName.elements(); enmr.hasMoreElements(); ) { Behavior behavior = (Behavior) enmr.nextElement(); String sSig = behavior.getUniqueName(); // check for conflict (this happens when a base Behavior is // renamed which conflicts if another Behavior was added at // this level and coincidentally has the same name) if (tblResult.contains(sSig)) { String sCode = (fResolve ? RESOLVE_BEHAVIORDISCARDED : EXTRACT_BEHAVIORDISCARDED); logError(sCode, WARNING, new Object[] {sSig, toPathString()}, errlist); } else { tblResult.put(sSig, behavior); } } return tblResult; } /** * Match up the children from the base and this Component. Return a * StringTable of children to resolve or extract from the base. The * returned StringTable must not be modified. * * The returned table may have null values which imply null derivations. * * The returned table may have additional children that were added by * the delta or derived Component. * * (Neither the base nor this Component are modified by this method.) * * @param base the super or base level Component * @param fResolve true if being RESOLVED * @param errlist the error list to log any mismatches to * * @exception DerivationException */ protected StringTable matchChildren(Component base, boolean fResolve, ErrorList errlist) throws DerivationException { StringTable tblThis = this.m_tblChildren; StringTable tblBase = base.m_tblChildren; StringTable tblResult = tblThis; // most common case overall: no children (i.e. "leaf nodes") // most common case for extract: exact match if (tblThis.keysEquals(tblBase)) { return tblResult; } // most common for resolve: no children in the delta if (tblThis.isEmpty()) { // copy keys from base (but leave children null to signify null // derivations) tblResult = (StringTable) tblBase.clone(); for (Enumeration enmr = tblResult.keys(); enmr.hasMoreElements(); ) { tblResult.put((String) enmr.nextElement(), null); } return tblResult; } // create results table (since we cannot change the "this" table); // this extended processing will only happen at levels which add, // remove, or modify children (considered to be rare) tblResult = new StringTable(); // build look up tables by UID and name Hashtable tblByUID = new Hashtable(); StringTable tblByName = new StringTable(); for (Enumeration enmr = tblThis.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); UID uid = cd.getUID(); if (uid != null) { tblByUID.put(uid, cd); } tblByName.put(cd.getUniqueName(), cd); } // look up by UID; remove each one found from the name look up table if (!tblByUID.isEmpty()) { for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); ) { Component cdBase = (Component) enmr.nextElement(); UID uid = cdBase.getUID(); if (uid != null) { Component cdThis = (Component) tblByUID.get(uid); if (cdThis != null) { tblResult.put(cdBase.getUniqueName(), cdThis); tblByName.remove(cdThis.getUniqueName()); } } } } // look up by name for (Enumeration enmr = tblBase.keys(); enmr.hasMoreElements(); ) { String sChild = (String) enmr.nextElement(); if (!tblResult.contains(sChild)) { // find the Component on this behavior with the same name; // whether or not one exists, reserve the name in the result Component cd = (Component) tblByName.get(sChild); tblResult.put(sChild, cd); // only leave unmatched Components in tblByName // (so they can be added to the results or discarded) if (cd != null) { tblByName.remove(sChild); } } } // keep additional Components (but discard any conflicting ones) for (Enumeration enmr = tblByName.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); String sChild = cd.getUniqueName(); // check for conflict (this happens when a base Component is // renamed which conflicts if another Component was added at // this level and coincidentally has the same name) if (tblResult.contains(sChild)) { String sCode = (fResolve ? RESOLVE_CHILDDISCARDED : EXTRACT_CHILDDISCARDED); logError(sCode, WARNING, new Object[] {sChild, toPathString()}, errlist); } else { tblResult.put(sChild, cd); } } return tblResult; } /** * Determine if the trait can be discarded. This has two uses: *
    *
  • Determining if a resolved trait should not exist; for example * a trait without an origin *
  • An extracted trait that contains no information (i.e. a "null * derivation") is often discardable *
* For a resolved trait, this request is only legal after the * finalizeResolve call. Likewise, for a derivation/modification * trait, this request is only legal after the finalizeExtract call. * * @return true if the trait is discardable */ protected boolean isDiscardable() { int nMode = getMode(); switch (nMode) { case RESOLVED: // a resolved component is never discardable return false; case DERIVATION: case MODIFICATION: // check for delta information if ( (m_nFlags & ALL_SPECIFIED) != 0 // any attributes || (!isComplex() && getParent() == null && nMode == DERIVATION) // global derivation || (m_integration != null && !m_integration.isDiscardable()) // integration || !m_tblImplements.isEmpty() // added interface || !m_tblDispatches.isEmpty() ) // added event { return false; } break; } return super.isDiscardable(); } /** * Determine whether this trait contains information that would cause * generation of a class that would operate differently than the class * generated from the information maintained by the super trait. * * @param base the base (i.e. the super) Trait to compare to * * @return true if a delta between this trait and its super trait means * that class generation should generate the class corresponding * to this trait, otherwise false */ protected boolean isClassDiscardable(Trait base) { Component that = (Component) base; if (that == null) { return false; } if (isGlobal()) { // global components are never optimized out return false; } else if (isStatic()) { // cp 2000.04.03 static children are not discardable if they or a // parent of theirs is an insert; this ensures that a static child // has its correct "full local identity" available by parsing its // getClass().getName(); this is intended for situations in which // the child is instantiated by something other than its parent, // e.g. JSP tags Component cd = getParent(); while (cd != null) { if ((cd.m_nFlags & EXISTS_MASK) == EXISTS_INSERT) { return false; } cd = cd.getParent(); } } // existence int nExistsThis = (this.m_nFlags & EXISTS_MASK); int nExistsThat = (that.m_nFlags & EXISTS_MASK); if (nExistsThis != nExistsThat) { boolean fThisExists = (nExistsThis == EXISTS_INSERT || nExistsThis == EXISTS_UPDATE); boolean fThatExists = (nExistsThat == EXISTS_INSERT || nExistsThat == EXISTS_UPDATE); if (fThisExists != fThatExists) { return false; } } // interfaces if ((this.m_integration != null && !this.m_integration.isDiscardable()) || !this.m_tblImplements.keysEquals(that.m_tblImplements) || !this.m_tblDispatches.keysEquals(that.m_tblDispatches)) { return false; } // attributes if (((this.m_nFlags ^ that.m_nFlags) & CLASSGEN_FLAGS) != 0) { return false; } // properties StringTable tblStateThis = this.m_tblState; StringTable tblStateThat = that.m_tblState; for (Enumeration enmr = tblStateThis.keys(); enmr.hasMoreElements(); ) { String s = (String) enmr.nextElement(); Property propThis = (Property) tblStateThis.get(s); Property propThat = (Property) tblStateThat.get(s); if (!propThis.isClassDiscardable(propThat)) { return false; } } // behavior StringTable tblBehaviorThis = this.m_tblBehavior; StringTable tblBehaviorThat = that.m_tblBehavior; for (Enumeration enmr = tblBehaviorThis.keys(); enmr.hasMoreElements(); ) { String s = (String) enmr.nextElement(); Behavior behThis = (Behavior) tblBehaviorThis.get(s); Behavior behThat = (Behavior) tblBehaviorThat.get(s); if (!behThis.isClassDiscardable(behThat)) { return false; } } // categories if (!this.m_tblCategories.keysEquals(that.m_tblCategories)) { return false; } // note: children are not checked; it is implicit that if a child // is not discardable, then neither is its parent return super.isClassDiscardable(base); } // ----- miscellaneous Trait methods ------------------------------------ /** * Determine if the component is modifiable. Components cannot be * modified if the super component (for derivation) or base (for * modification) is final. Signatures are only modifiable during * resolution. * * @return true if changes are permitted to the component */ public boolean isModifiable() { if (m_fReadOnly) { return false; } if (m_nType == COMPONENT && (m_nPrevFlags & DERIVE_MASK) != DERIVE_DERIVABLE) { return false; } return super.isModifiable(); } /** * Mark the component as read-only or modifiable. Marking the component * as modifiable may not make it modifiable, since other reasons may exist * that prevent it from being modifiable. * * @param fModifiable true to make the component modifiable, false to * make the component read-only */ protected void setModifiable(boolean fModifiable) { m_fReadOnly = !fModifiable; } /** * Determine all traits contained by this Component. * * @return the an enumeration of traits contained by this trait */ protected Enumeration getSubTraits() { ChainedEnumerator enmr = new ChainedEnumerator(); if (m_integration != null) { enmr.addEnumeration(new SimpleEnumerator(new Object[] {m_integration})); } enmr.addEnumeration(m_tblImplements.elements()); enmr.addEnumeration(m_tblDispatches.elements()); enmr.addEnumeration(m_tblState .elements()); enmr.addEnumeration(m_tblBehavior .elements()); enmr.addEnumeration(m_tblChildren .elements()); return enmr; } /** * Reset state, discarding all information. */ protected synchronized void invalidate() { super.invalidate(); m_sName = null; m_sSuper = null; m_integration = null; m_tblImplements = null; m_tblDispatches = null; m_tblBehavior = null; m_tblState = null; m_tblCategories = null; m_tblChildren = null; } /** * The Component's name is its unique string identifier (i.e. corresponds * to its UID). * * @return the Component name */ protected String getUniqueName() { return m_sName; } /** * Determine the unique description for this trait. * * All traits must be uniquely identifiable by a "description string". * This enables the origin implementation built into Trait to use the * description string to differentiate between Trait origins. * * @return the description string for the trait */ protected String getUniqueDescription() { return DESCRIPTORS[m_nType] + ' ' + getUniqueName(); } /** * Determine whether the trait was added at this level or at a previous * level. This is equivalent to "isNotFromSuperOrBase", whether or not * additional origins (manual, traits) exist at this level. * * @return true if the trait was added at this level */ public boolean isDeclaredAtThisLevel() { Trait trait = getParentTrait(); if (trait != null && trait instanceof Component) { // child of a component is "declared at this level" // if it was inserted at this level return getExists() == EXISTS_INSERT && m_fBaseLevel; } else { return super.isDeclaredAtThisLevel(); } } /** * Determine if the trait existed at a base level. This means that the * trait is the result of modification (but not the result of derivation). * * @return true if the trait existed at a base level (but did not exist * at a super level) */ public boolean isFromBase() { Trait trait = getParentTrait(); if (trait != null && trait instanceof Component) { // child of a component is "from base" if it was inserted // at a base level return getExists() == EXISTS_INSERT && !m_fBaseLevel; } else { return super.isFromBase(); } } /** * Determine if the trait existed at a super level. This means that * the trait is the result of derivation. * * @return true if the trait existed at a super level */ public boolean isFromSuper() { Trait trait = getParentTrait(); if (trait != null && trait instanceof Component) { // child of a component is "from super" if it is not an insert return getExists() != EXISTS_INSERT; } else { return super.isFromSuper(); } } // ----- component accessors: identity --------------------------------- // ----- categorization /** * Determine if this is a Component Definition. This class (Component) * is used for Component Definitions, Complex Property values, and Java * Class Signatures. * * @return true if this is a Component Definition */ public boolean isComponent() { return m_nType == COMPONENT; } /** * Determine if the Component is a global (not contained) Component. * * @return true if the Component is global */ public boolean isGlobal() { return getParentTrait() == null; } /** * Get the Component parent of this Component Definition. * * @return this Component Definition's parent or null if this Component * Definition is not aggregated * * @exception ClassCastException if the component is a complex property */ public Component getParent() { return (Component) getParentTrait(); } /** * Get the topmost (global) Component parent of this Component Definition. * * @return the topmost Component Definition's parent * * @exception ClassCastException if the component is a complex property */ public Component getGlobalParent() { Component cdParent = this; while (!cdParent.isGlobal()) { cdParent = cdParent.getParent(); } return cdParent; } /** * Determine if this is a complex Property value. This class (Component) * is used for Component Definitions, complex Property values, and Java * Class Signatures. * * @return true if this is a Component Definition */ public boolean isComplex() { return m_nType == COMPLEX; } /** * Get the Property parent of this complex property value. * * @return the Property which contains this complex property value * * @exception ClassCastException if the component is a Component Definition */ public Property getComplex() { return (Property) getParentTrait(); } /** * Determine if this is a Java Class Signature (JCS). This class * (Component) is used for Component Definitions, complex Property * values, and Java Class Signatures. * * @return true if this is a JCS */ public boolean isSignature() { return m_nType == SIGNATURE; } /** * Determine if this is a Java Class Signature (JCS) that represents a * Java class. * * @return true if this is a JCS for a Java class */ public boolean isClass() { return m_nType == SIGNATURE && (m_nFlags & MISC_ISINTERFACE) == 0; } /** * Determine if this is a Java Class Signature (JCS) that represents a * Java interface. * * @return true if this is a JCS for a Java interface */ public boolean isInterface() { return m_nType == SIGNATURE && (m_nFlags & MISC_ISINTERFACE) != 0; } /** * Determine if this is a Java Class Signature (JCS) that represents a * class deriving from java.lang.Throwable. * * @return true if this is a throwable JCS */ public boolean isThrowable() { return m_nType == SIGNATURE && (m_nFlags & MISC_ISTHROWABLE) != 0; } // ----- name /** * Get the simple Component Definition name. * * @return the name (not fully qualified) of the Component Definition */ public String getName() { return m_sName; } /** * Get fully qualified name. * * @return fully qualified name of the Component, Complex property, * or Java Class Signature */ public String getQualifiedName() { String sName = m_sName; if (isComponent()) { Component cdParent = getParent(); if (cdParent != null) { return new StringBuffer() .append(cdParent.getQualifiedName()) .append(LOCAL_ID_DELIM) .append(sName) .toString(); } String sSuper = m_sSuper; if (sSuper.length() > 0) { // JavaC BUG! // return sSuper + GLOBAL_ID_DELIM + sName; return new StringBuffer() .append(sSuper) .append(GLOBAL_ID_DELIM) .append(sName) .toString(); } } return sName; } /** * Get the local portion of this component name. For example, * if the qualified name is X.Y$A$B, the local portion is A$B. * * @return the local portion of the component name, or null if the * component name is global */ public String getLocalName() { return getLocalName(getQualifiedName()); } /** * Get the name of the super Component of this component * * @return fully qualified name of the super Component */ public String getSuperName() { // child components not inserted at this level have a super component // which is the same-named child on the parent's super if (isComponent() && getParent() != null && getExists() != EXISTS_INSERT) { return new StringBuffer() .append(getParent().getSuperName()) .append(LOCAL_ID_DELIM) .append(m_sName) .toString(); } return m_sSuper; } /** * Get the global super Component Definition name. * * @return fully qualified name of the global super Component */ public String getGlobalSuperName() { return m_sSuper; } /** * Checks whether this component or any of its children * derive from the global component with a specified name * * @param sName name of the "impacted by" component * * @return true if the component itself or one of its children derive * from the specified global component; false otherwise */ public boolean isImpactedBy(String sName) { if (isDerivedFrom(getGlobalSuperName(), sName)) { return true; } String[] asChildren = getChildren(); for (int i = 0; i < asChildren.length; i++) { Component child = getChild(asChildren[i]); if (child != null && child.isImpactedBy(sName)) { return true; } } return false; } /** * Determine if the Component name can be set. The name cannot be * changed if the Component is the result of a modification or if * the Component is a child not inserted at this level. * * @return true if the Component name can be set */ public boolean isNameSettable() { // component must be modifiable if (!isComponent() || !isModifiable()) { return false; } if (getParent() != null) { // child must have been added at this level return isDeclaredAtThisLevel(); } // for global cd's name to change the component // must not be result of modification return m_fBaseLevel; } /** * Determine if the specified Component name is legal. * * @return true if the specified name is legal */ public boolean isNameLegal(String sName) { if (isComponent()) { Component cdParent = getParent(); if (cdParent == null) { return isSimpleNameLegal(sName, true) && m_sSuper != BLANK; // cannot rename root } else { return isSimpleNameLegal(sName, false) && (sName.equalsIgnoreCase(m_sName) // allow case change || !cdParent.isChild(sName)); // check if the name is already taken } } return false; } /** * Set the Component name. * * @param sName the new name for the Component * * @exception PropertyVetoException if the new attribute value is not * accepted */ public void setName(String sName) throws PropertyVetoException { setName(sName, true); } /** * Set the Component name. * * @param sName the new name for the Component * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the new attribute value is not * accepted */ protected synchronized void setName(String sName, boolean fVetoable) throws PropertyVetoException { String sPrev = m_sName; if (sName.equals(sPrev)) { return; } if (fVetoable) { if (!isNameSettable()) { readOnlyAttribute(ATTR_NAME, sPrev, sName); } if (!isNameLegal(sName)) { illegalAttributeValue(ATTR_NAME, sPrev, sName); } fireVetoableChange(ATTR_NAME, sPrev, sName); } m_sName = sName; if (getParent() != null) { getParent().renameChild(sPrev, sName); } firePropertyChange(ATTR_NAME, sPrev, sName); } // ----- Exists /** * Get the exists flag for this Component. * * @return the exists flag for this Component */ protected int getExists() { return m_nFlags & EXISTS_MASK; } /** * Set the exists flag for this Component. * * @param nExists the exists flag for this Component */ protected void setExists(int nExists) { m_nFlags = m_nFlags & ~EXISTS_MASK | nExists; } // ----- attribute: Visibility /** * Get the component visibility attribute. * * @return the value of the visbility attribute as defined by * Constants * * @see com.tangosol.dev.component.Constants#VIS_SYSTEM * @see com.tangosol.dev.component.Constants#VIS_HIDDEN * @see com.tangosol.dev.component.Constants#VIS_ADVANCED * @see com.tangosol.dev.component.Constants#VIS_VISIBLE */ public int getVisible() { return m_nFlags & VIS_MASK; } /** * Determine whether the Visible attribute of the Component Definition * can be set. * * @return true if the Visible attribute can set with a valid value */ public boolean isVisibleSettable() { return isComponent() && isModifiable(); } /** * Determine whether the Visible attribute of the Component Definition can * be set to the specified value. The Visible attribute of the component * is flexible. * * @param nVis the new value of the visibility attribute * * @return true if the specified value is acceptable * * @see com.tangosol.dev.component.Constants#VIS_SYSTEM * @see com.tangosol.dev.component.Constants#VIS_HIDDEN * @see com.tangosol.dev.component.Constants#VIS_ADVANCED * @see com.tangosol.dev.component.Constants#VIS_VISIBLE */ public boolean isVisibleLegal(int nVis) { switch (nVis) { case VIS_SYSTEM: case VIS_HIDDEN: case VIS_ADVANCED: case VIS_VISIBLE: return true; default: return false; } } /** * Set the visible attribute of the Component. * * @param nVis the new visibility value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener * * @see com.tangosol.dev.component.Constants#VIS_SYSTEM * @see com.tangosol.dev.component.Constants#VIS_HIDDEN * @see com.tangosol.dev.component.Constants#VIS_ADVANCED * @see com.tangosol.dev.component.Constants#VIS_VISIBLE */ public void setVisible(int nVis) throws PropertyVetoException { setVisible(nVis, true); } /** * Set the visible attribute of the Component. * * @param nVis the new visibility value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void setVisible(int nVis, boolean fVetoable) throws PropertyVetoException { int nPrevVis = getVisible(); if (nVis == nPrevVis) { return; } Integer prev = Integer.valueOf(nPrevVis); Integer value = Integer.valueOf(nVis); if (fVetoable) { if (!isVisibleSettable()) { readOnlyAttribute(ATTR_VISIBLE, prev, value); } if (!isVisibleLegal(nVis)) { illegalAttributeValue(ATTR_VISIBLE, prev, value); } fireVetoableChange(ATTR_VISIBLE, prev, value); } m_nFlags = m_nFlags & ~VIS_MASK | nVis; firePropertyChange(ATTR_VISIBLE, prev, value); } // ----- Access /** * Determine the current accessibility of the component/class signature. * Components are always public. * * @return one of ACCESS_PUBLIC, ACCESS_PROTECTED, ACCESS_PRIVATE, or * ACCESS_PACKAGE */ public int getAccess() { return m_nType == SIGNATURE ? m_nFlags & ACCESS_MASK : ACCESS_PUBLIC; } // ----- attribute: Static /** * Get the component scope attribute. * * @return true if the component is static (single instance) */ public boolean isStatic() { return (m_nFlags & SCOPE_MASK) == SCOPE_STATIC; } /** * Determine whether the scope attribute of the Component Definition can * be set. Since the scope attribute is expressed as a boolean, this * method doubles for both the "is settable" and "is legal" questions. * For global components, the scope attribute of the component is one-way * from insance to static. A static global component is a singleton, * which means that one and only one will exist. If a global component * is marked as static, all components under it will inherit that static * attribute, and only one component in that tree will be instantiable * at runtime. * * A local component that is marked as static is not auto-instantiated. * That allows a local component to be used for several very convenient * types of solutions, such as being designed to be the result of a * "factory". Consider a "tree" data structure that contains a type * of "node". There will be zero or more nodes, but those nodes may * only be applicable within the design of the tree. The solution is * that the tree is a global component and the node is a static child * thereof. By implementing a factory method (which will eventually * be autogenerated) the tree can virtually instantiate the node * component any number of times, and the design of the node is contained * inside the design of the tree, helping to keep things neat. * * @return true if the scope attribute can set */ public boolean isStaticSettable() { if (isComponent() && isModifiable()) { // cp 2001.03.30 allow child to be changed from instance to // static at the insert level only; do not allow // change from static to instance if the super or // base is static if (getParent() == null || isDeclaredAtThisLevel()) { return (m_nPrevFlags & SCOPE_MASK) == SCOPE_INSTANCE; } } return false; } /** * Set the scope attribute of the Component. * * @param fStatic the new scope value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public void setStatic(boolean fStatic) throws PropertyVetoException { setStatic(fStatic, true); } /** * Set the scope attribute of the Component. * * @param fStatic the new scope value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void setStatic(boolean fStatic, boolean fVetoable) throws PropertyVetoException { boolean fPrevStatic = isStatic(); if (fStatic == fPrevStatic) { return; } Boolean prev = toBoolean(fPrevStatic); Boolean value = toBoolean(fStatic); if (fVetoable) { if (!isStaticSettable()) { readOnlyAttribute(ATTR_STATIC, prev, value); } fireVetoableChange(ATTR_STATIC, prev, value); } m_nFlags = m_nFlags & ~SCOPE_MASK | (fStatic ? SCOPE_STATIC : SCOPE_INSTANCE); firePropertyChange(ATTR_STATIC, prev, value); } // ----- attribute: Abstract /** * Get the component implementation attribute. * * @return true if the component is abstract */ public boolean isAbstract() { return (m_nFlags & IMPL_MASK) == IMPL_ABSTRACT; } /** * Determine whether the implementation attribute of the Component can * be set. Since the implementation attribute is expressed as a boolean, * this method doubles for both the "is settable" and "is legal" * questions. The implementation attribute of the component is flexible. * * @return true if the implementation attribute can set */ public boolean isAbstractSettable() { return isComponent() && isModifiable(); } /** * Set the Component's implementation attribute. * * @param fAbstract the new implementation attribute value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public void setAbstract(boolean fAbstract) throws PropertyVetoException { setAbstract(fAbstract, true); } /** * Set the Component's implementation attribute. * * @param fAbstract the new implementation attribute value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void setAbstract(boolean fAbstract, boolean fVetoable) throws PropertyVetoException { boolean fPrevAbstract = isAbstract(); if (fAbstract == fPrevAbstract) { return; } Boolean prev = toBoolean(fPrevAbstract); Boolean value = toBoolean(fAbstract); if (fVetoable) { if (!isAbstractSettable()) { readOnlyAttribute(ATTR_ABSTRACT, prev, value); } fireVetoableChange(ATTR_ABSTRACT, prev, value); } m_nFlags = m_nFlags & ~IMPL_MASK | (fAbstract ? IMPL_ABSTRACT : IMPL_CONCRETE); firePropertyChange(ATTR_ABSTRACT, prev, value); } /** * Determine if the Component contains any abstract Behaviors. * * @return true if the Component contains any abstract Behaviors */ public boolean isResultAbstract() { return isAbstract() || hasAbstractBehavior() || containsAbstractComponent(); } /** * Determine if the resulting Java class(es) for the Component are * instatiable. The classes would not be instantiable if the Component * were abstract, contains any abstract Behaviors, or . * * @return true if the Component contains any abstract Behaviors */ public boolean hasAbstractBehavior() { for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { if (((Behavior) enmr.nextElement()).isAbstract()) { return true; } } return false; } /** * Determine if the Component contains any abstract child Components. * * @return true if the Component contains any abstract child Components */ public boolean containsAbstractComponent() { for (Enumeration enmr = m_tblChildren.elements(); enmr.hasMoreElements(); ) { if (((Component) enmr.nextElement()).isResultAbstract()) { return true; } } return false; } // ----- attribute: Final /** * Get the component derivable attribute. * * @return the value of the derivable attribute */ public boolean isFinal() { return (m_nFlags & DERIVE_MASK) == DERIVE_FINAL; } /** * Determine whether the derivable attribute of the Component Definition * can be set. Since the derivable attribute is expressed as a boolean, * this method doubles for both the "is settable" and "is legal" * questions. The derivable attribute of the component is one-way from * derivable to final. * * @return true if the derivable attribute can be set */ public boolean isFinalSettable() { // the implementation of isModifiable verifies the super/base is not // already final return isComponent() && isModifiable(); } /** * Set the finality attribute of the Component. * * @param fFinal the new finality value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public void setFinal(boolean fFinal) throws PropertyVetoException { setFinal(fFinal, true); } /** * Set the finality attribute of the Component. * * @param fFinal the new finality value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void setFinal(boolean fFinal, boolean fVetoable) throws PropertyVetoException { boolean fPrevFinal = isFinal(); if (fFinal == fPrevFinal) { return; } Boolean prev = toBoolean(fPrevFinal); Boolean value = toBoolean(fFinal); if (fVetoable) { if (!isFinalSettable()) { readOnlyAttribute(ATTR_FINAL, prev, value); } fireVetoableChange(ATTR_FINAL, prev, value); } m_nFlags = m_nFlags & ~DERIVE_MASK | (fFinal ? DERIVE_FINAL : DERIVE_DERIVABLE); firePropertyChange(ATTR_FINAL, prev, value); } // ----- attribute: Deprecated /** * Get the component antiquity attribute. * * @return true if the component is deprecated */ public boolean isDeprecated() { return (m_nFlags & ANTIQ_MASK) == ANTIQ_DEPRECATED; } /** * Determine whether the antiquity attribute of the Component can be set. * Since the antiquity attribute is expressed as a boolean, this method * doubles for both the "is settable" and "is legal" questions. The * antiquity attribute of the component is flexible. * * @return true if the antiquity attribute can set */ public boolean isDeprecatedSettable() { return isComponent() && isModifiable(); } /** * Set the antiquity attribute of the Component. * * @param fDeprecated the new antiquity attribute value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public void setDeprecated(boolean fDeprecated) throws PropertyVetoException { setDeprecated(fDeprecated, true); } /** * Set the antiquity attribute of the Component. * * @param fDeprecated the new antiquity attribute value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void setDeprecated(boolean fDeprecated, boolean fVetoable) throws PropertyVetoException { boolean fPrevDeprecated = isDeprecated(); if (fDeprecated == fPrevDeprecated) { return; } Boolean prev = toBoolean(fPrevDeprecated); Boolean value = toBoolean(fDeprecated); if (fVetoable) { if (!isDeprecatedSettable()) { readOnlyAttribute(ATTR_DEPRECATED, prev, value); } fireVetoableChange(ATTR_DEPRECATED, prev, value); } m_nFlags = m_nFlags & ~ANTIQ_MASK | (fDeprecated ? ANTIQ_DEPRECATED : ANTIQ_CURRENT); firePropertyChange(ATTR_DEPRECATED, prev, value); } // ----- attribute: Persistent /** * Get the component persistence attribute. * * @return true if the component is persistent */ public boolean isPersistent() { return (m_nFlags & STG_MASK) == STG_PERSIST; } /** * Determine whether the persistence attribute of the Component can be * set. Since the persistence attribute is expressed as a boolean, this * method doubles for both the "is settable" and "is legal" questions. The * persistence attribute of the component is flexible. * * @return true if the persistence attribute can set */ public boolean isPersistentSettable() { return isComponent() && isModifiable(); } /** * Set the persistence attribute of the Component. * * @param fPersistent the new persistence attribute value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public void setPersistent(boolean fPersistent) throws PropertyVetoException { setPersistent(fPersistent, true); } /** * Set the persistence attribute of the Component. * * @param fPersistent the new persistence attribute value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void setPersistent(boolean fPersistent, boolean fVetoable) throws PropertyVetoException { boolean fPrevPersistent = isPersistent(); if (fPersistent == fPrevPersistent) { return; } Boolean prev = toBoolean(fPrevPersistent); Boolean value = toBoolean(fPersistent); if (fVetoable) { if (!isPersistentSettable()) { readOnlyAttribute(ATTR_PERSISTENT, prev, value); } fireVetoableChange(ATTR_PERSISTENT, prev, value); } m_nFlags = m_nFlags & ~STG_MASK | (fPersistent ? STG_PERSIST : STG_TRANSIENT); firePropertyChange(ATTR_PERSISTENT, prev, value); } // ----- attribute: Remote /** * Get the component distribution attribute. * * @return true if the component is remotable */ public boolean isRemote() { return (m_nFlags & DIST_MASK) == DIST_REMOTE; } /** * Determine whether the distribution attribute of the Component can be * set. Since the distribution attribute is expressed as a boolean, this * method doubles for both the "is settable" and "is legal" questions. * * The distribution attribute of the Component is one-way local to remote. * The distribution attribute can only be set for global Components; local * Components are remote if and only if they derive from a remote global * Component. * * @return true if the distribution attribute can set */ public boolean isRemoteSettable() { return isComponent() && isGlobal() && isModifiable() && (m_nPrevFlags & DIST_MASK) != DIST_REMOTE; } /** * Set the Component's distribution attribute. * * @param fRemote the new distribution attribute value * * @exception PropertyVetoException if the new attribute value is not * accepted */ public void setRemote(boolean fRemote) throws PropertyVetoException { setRemote(fRemote, true); } /** * Set the Component's distribution attribute. * * @param fRemote the new distribution attribute value * @param fVetoable true if the setter can veto the value * * @exception PropertyVetoException if the new attribute value is not * accepted */ protected synchronized void setRemote(boolean fRemote, boolean fVetoable) throws PropertyVetoException { boolean fPrevRemote = isRemote(); if (fRemote == fPrevRemote) { return; } Boolean prev = toBoolean(fPrevRemote); Boolean value = toBoolean(fRemote); if (fVetoable) { if (!isRemoteSettable()) { readOnlyAttribute(ATTR_REMOTE, prev, value); } fireVetoableChange(ATTR_REMOTE, prev, value); } m_nFlags = m_nFlags & ~DIST_MASK | (fRemote ? DIST_REMOTE : DIST_LOCAL); if (fPrevRemote) { for(Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { ((Behavior) enmr.nextElement()).setRemote(false, false); } } firePropertyChange(ATTR_REMOTE, prev, value); } // ----- attribute: Integration /** * Get the integration trait for this component * * @return the integration trait */ public Integration getIntegration() { return m_integration; } /** * Determine whether the Integration attribute of the Component Definition * can be set. * * @return true if the Integration attribute can be set with a valid value */ public boolean isIntegrationSettable() { return isComponent() && getParent() == null && m_fBaseLevel && isModifiable(); } /** * Determine whether the Integration attribute of the Component Definition * can be set to the specified Java Class Signature. * * @param cdJCS the Java Class Signature to use in Integration * * @return true if the Integration attribute can be set to the specified * Java Class Signature */ public boolean isIntegrationLegal(Component cdJCS) { return isIntegrationLegal(cdJCS, null); } /** * Determine whether the Integration attribute of the Component Definition * can be set to the specified Java Class Signature. * * @param cdJCS the Java Class Signature to use in Integration * @param errlist the ErrorList object to log integration errors to * * @return true if the Integration attribute can be set to the specified * Java Class Signature. */ public boolean isIntegrationLegal(Component cdJCS, ErrorList errlist) { Integration map = m_integration; // check if integration already exists if (map != null) { if (cdJCS == null) { // allow integration to be cleared only if this // integration level is the start of integration // for this Component heirarchy. return map.getPreviousSignature().length() == 0; } return map.isSignatureLegal(cdJCS.getQualifiedName()); } // Otherwise, anything goes... return true; } /** * Use the specified Java Class Signature for Integration. * * @param cdJCS the Java Class Signature to use with Integration * @param errlist the error list object to log warnings and errors to * * @exception PropertyVetoException if the new attribute value is not * accepted */ public void setIntegration(Component cdJCS, ErrorList errlist) throws PropertyVetoException { setIntegration(cdJCS, errlist, true); } /** * Use the specified Java Class Signature for Integration. * * @param cdJCS the Java Class Signature to use with Integration * @param errlist the error list object to log warnings and errors to * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the new attribute value is not * accepted */ protected synchronized void setIntegration(Component cdJCS, ErrorList errlist, boolean fVetoable) throws PropertyVetoException { Integration mapPrev = m_integration; if (mapPrev != null && cdJCS != null) { mapPrev.setSignature(cdJCS.getQualifiedName(), fVetoable); return; } Integration mapNew = (cdJCS == null ? null : new Integration(this, cdJCS.getQualifiedName())); // assume no changes if integrates names are identical // (note: if assumption is not true, then pass a null map to clear // the integrates attribute then call again with the desired map) if (mapNew == null ? mapPrev == null : mapNew.equals(mapPrev)) { return; } if (fVetoable) { if (!isIntegrationSettable()) { readOnlyAttribute(ATTR_INTEGRATION, mapPrev, mapNew); } if (!isIntegrationLegal(cdJCS, errlist)) { illegalAttributeValue(ATTR_INTEGRATION, mapPrev, mapNew); } fireVetoableChange(ATTR_INTEGRATION, mapPrev, mapNew); } // store new integration m_integration = mapNew; if (mapNew != null) { mapNew.validate(); } firePropertyChange(ATTR_INTEGRATION, mapPrev, mapNew); if (mapPrev != null) { mapPrev.invalidate(); } } // ----- attribute: Implements /** * Get the list of Java interfaces implemented by this component. * * @return an array of Java interface names */ public String[] getImplements() { return m_tblImplements.strings(); } /** * Get the implemented interface information for the specified name. * * @param sIface a Java interface name * * @return the Interface object for the specified name (or null) */ public Interface getImplements(String sIface) { return (Interface) m_tblImplements.get(sIface); } /** * Determine whether the specified Java interface can be added to the * Implements attribute of the Component Definition. * * @param cdJCS the Java Class Signature to implement * * @return true if the specified JCS can be added to this Component * Definition */ public boolean isImplementsAddable(Component cdJCS) { return isImplementsAddable(cdJCS, null); } /** * Determine whether the specified Java interface can be added to the * Implements attribute of the Component Definition. * * @param cdJCS the Java Class Signature to implement * @param errlist the ErrorList to log errors to * * @return true if the specified JCS can be added to this Component * Definition */ public boolean isImplementsAddable(Component cdJCS, ErrorList errlist) { Interface iface; try { iface = new Interface(this, cdJCS, false); } catch (IllegalArgumentException e) { // cdJCS is not a valid Java interface return false; } return isImplementsAddable(iface, cdJCS, errlist); } /** * Determine whether the specified Java interface can be added to the * Implements attribute of the Component Definition. * * @param iface the Interface to implement * @param cdJCS the Java Class Signature to implement * @param errlist the ErrorList to log errors to * * @return true if the specified Interface can be implemented */ protected boolean isImplementsAddable(Interface iface, Component cdJCS, ErrorList errlist) { // the JCS must be an interface if (iface == null) { return false; } // this must be modifiable if (!isModifiable()) { return false; } // and it must be either a component or a JCS switch (m_nType) { case COMPONENT: case SIGNATURE: break; default: return false; } // short-cut: this Component already implements or dispatches the // interface String sIface = iface.getName(); if (m_tblImplements.contains(sIface) || m_tblDispatches.contains(sIface)) { return true; } // short-cut: tag-only interfaces (e.g. Serializable) if (!iface.getBehaviors().hasMoreElements()) { return true; } return isInterfaceExpandable(iface, cdJCS, errlist); } /** * Add the Java interface to the Component Definition. * * @param cdJCS the Java Class Signature to implement * * @exception PropertyVetoException if the new attribute value is not * accepted */ public void addImplements(Component cdJCS) throws PropertyVetoException { addImplements(cdJCS, true); } /** * Add the Java interface to the Component Definition. * * @param cdJCS the Java Class Signature to implement * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the new attribute value is not * accepted */ protected synchronized void addImplements(Component cdJCS, boolean fVetoable) throws PropertyVetoException { // check for redundant change String sIface = cdJCS.getName(); if (m_tblImplements.contains(sIface)) { return; } // create the interface object Interface iface = null; try { iface = new Interface(this, cdJCS, false); } catch (IllegalArgumentException e) { subNotAddable(ATTR_IMPLEMENTS, sIface); } if (fVetoable) { // verify the interface can be implemented if (!isImplementsAddable(iface, cdJCS, null)) { subNotAddable(ATTR_IMPLEMENTS, sIface); } // notify veto listeners fireVetoableChange(ATTR_IMPLEMENTS, null, iface); } // add the interface m_tblImplements.put(sIface, iface); // expand the interface expandInterface(iface, cdJCS, null, null, null); // notify listeners iface.validate(); firePropertyChange(ATTR_IMPLEMENTS, null, iface); } /** * Determine whether a implemented Java interface can be removed from this * Component Definition. * * @param sIface the name of the interface * * @return true if the specified interface can be removed from the * Implements attribute */ public boolean isImplementsRemovable(String sIface) { // check for redundant change Interface iface = (Interface) m_tblImplements.get(sIface); return iface != null && isModifiable() && iface.isDeclaredAtThisLevel(); } /** * Remove the Java interface from the list of implemented interfaces. * * @param sIface fully qualified name of the Java interface * * @exception PropertyVetoException if removal of the interface * fails. */ public void removeImplements(String sIface) throws PropertyVetoException { removeImplements(sIface, true); } /** * Remove the Java interface from the list of implemented interfaces. * This will only succeed if the interface is specified at this * Component Definition's modification level. * * @param sIface fully qualified name of the Java interface * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if removal of the interface * fails. */ protected synchronized void removeImplements(String sIface, boolean fVetoable) throws PropertyVetoException { // check for redundant change Interface iface = (Interface) m_tblImplements.get(sIface); if (iface == null) { return; } if (fVetoable) { // verify the interface is removable if (!isImplementsRemovable(sIface)) { subNotRemovable(ATTR_IMPLEMENTS, iface); } // notify veto listeners fireVetoableChange(ATTR_IMPLEMENTS, iface, null); } // remove the interface m_tblImplements.remove(sIface); // remove origin from associated Behaviors and remove any associated // Behaviors that are left origin-less for (Enumeration enmr = iface.getBehaviors(); enmr.hasMoreElements(); ) { String sBehavior = (String) enmr.nextElement(); Behavior behavior = (Behavior) m_tblBehavior.get(sBehavior); // as of Java 8, an interface may contain static "extension methods" if (behavior != null) { behavior.removeOriginTrait(iface); if (behavior.isDiscardable()) { removeBehavior(behavior, false); } } } // notify listeners firePropertyChange(ATTR_IMPLEMENTS, iface, null); iface.invalidate(); } // ----- attribute: Dispatches /** * Get the list of Java interfaces dispatched by this component. * * @return an array of Java interface names */ public String[] getDispatches() { return m_tblDispatches.strings(); } /** * Get the dispatched interface information for the specified name. * * @param sIface a Java interface name * * @return the Interface object for the specified name (or null) */ public Interface getDispatches(String sIface) { return (Interface) m_tblDispatches.get(sIface); } /** * Determine whether the specified Java interface can be added to the * Dispatches attribute of the Component Definition. * * @param cdJCS the Java Class Signature to dispatch * * @return true if the specified JCS can be added to this Component * Definition */ public boolean isDispatchesAddable(Component cdJCS) { return isDispatchesAddable(cdJCS, null); } /** * Determine whether the specified Java interface can be added to the * Dispatches attribute of the Component Definition. * * @param cdJCS the Java Class Signature to dispatch * @param errlist the ErrorList to log errors to * * @return true if the specified JCS can be added to this Component * Definition */ public boolean isDispatchesAddable(Component cdJCS, ErrorList errlist) { Interface iface; try { iface = new Interface(this, cdJCS, true); } catch (IllegalArgumentException e) { // cdJCS is not a valid Java interface return false; } return isDispatchesAddable(iface, cdJCS, errlist); } /** * Determine whether the specified Java interface can be added to the * Dispatches attribute of the Component Definition. * * @param iface the Interface to dispatch * @param cdJCS the Java Class Signature to dispatch * @param errlist the ErrorList to log errors to * * @return true if the specified Interface can be dispatched */ protected boolean isDispatchesAddable(Interface iface, Component cdJCS, ErrorList errlist) { // interface required if (iface == null) { return false; } // this must be modifiable if (!isModifiable()) { return false; } // and it must be either a component or a JCS switch (m_nType) { case COMPONENT: case SIGNATURE: break; default: return false; } // short-cut: this Component already dispatches the interface String sIface = iface.getName(); if (m_tblDispatches.contains(sIface)) { return true; } // check interface naming conventions if (!sIface.endsWith("Listener")) { return false; } // if add/remove listener Behaviors exist, they must be from this // level String sClass = DataType.getClassType(sIface).getTypeString(); String sSig = sIface.substring(sIface.lastIndexOf('.') + 1) + '(' + sClass + ')'; Behavior behAdd = (Behavior) m_tblBehavior.get("add" + sSig); Behavior behRemove = (Behavior) m_tblBehavior.get("remove" + sSig); if (behAdd != null && behAdd .isFromSuper() || behRemove != null && behRemove.isFromSuper() ) { return false; } return isInterfaceExpandable(iface, cdJCS, errlist); } /** * Add the Java interface to the Component Definition. * * @param cdJCS the Java Class Signature to dispatch * * @exception PropertyVetoException if the new attribute value is not * accepted */ public void addDispatches(Component cdJCS) throws PropertyVetoException { addDispatches(cdJCS, true); } /** * Add the Java interface to the Component Definition. * * @param cdJCS the Java Class Signature to dispatch * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the new attribute value is not * accepted */ protected synchronized void addDispatches(Component cdJCS, boolean fVetoable) throws PropertyVetoException { // check for redundant change String sIface = cdJCS.getName(); if (m_tblDispatches.contains(sIface)) { return; } // create the interface object Interface iface = null; try { iface = new Interface(this, cdJCS, true); } catch (IllegalArgumentException e) { subNotAddable(ATTR_DISPATCHES, sIface); } if (fVetoable) { // verify the interface can be dispatched if (!isDispatchesAddable(iface, cdJCS, null)) { subNotAddable(ATTR_DISPATCHES, sIface); } // notify veto listeners fireVetoableChange(ATTR_DISPATCHES, null, iface); } // add the interface m_tblDispatches.put(sIface, iface); // expand the interface expandInterface(iface, cdJCS, null, null, null); // notify listeners iface.validate(); firePropertyChange(ATTR_DISPATCHES, null, iface); } /** * Determine whether a dispatched Java interface can be removed from this * Component Definition. * * @param sIface the name of the interface * * @return true if the specified interface can be removed from the * Dispatches attribute */ public boolean isDispatchesRemovable(String sIface) { // check for redundant change Interface iface = (Interface) m_tblDispatches.get(sIface); return iface != null && isModifiable() && iface.isDeclaredAtThisLevel(); } /** * Remove the Java interface from the list of dispatched interfaces. * * @param sIface fully qualified name of the Java interface * * @exception PropertyVetoException if removal of the interface * fails. */ public void removeDispatches(String sIface) throws PropertyVetoException { removeDispatches(sIface, true); } /** * Remove the Java interface from the list of dispatched interfaces. * This will only succeed if the interface is specified at this * Component Definition's modification level. * * @param sIface fully qualified name of the Java interface * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if removal of the interface * fails. */ protected synchronized void removeDispatches(String sIface, boolean fVetoable) throws PropertyVetoException { // check for redundant change Interface iface = (Interface) m_tblDispatches.get(sIface); if (iface == null) { return; } if (fVetoable) { // verify the interface is removable if (!isDispatchesRemovable(sIface)) { subNotRemovable(ATTR_DISPATCHES, iface); } // notify veto listeners fireVetoableChange(ATTR_DISPATCHES, iface, null); } // remove the interface m_tblDispatches.remove(sIface); // remove origin from associated Behaviors and remove any associated // Behaviors that are left origin-less for (Enumeration enmr = iface.getBehaviors(); enmr.hasMoreElements(); ) { String sBehavior = (String) enmr.nextElement(); Behavior behavior = (Behavior) m_tblBehavior.get(sBehavior); behavior.removeOriginTrait(iface); if (behavior.isDiscardable()) { removeBehavior(behavior, false); } } // notify listeners firePropertyChange(ATTR_DISPATCHES, iface, null); iface.invalidate(); } // ----- helpers for Implements and Dispatches attributes /** * Determine whether the specified Java interface can be added to this * Component Definition (i.e. the Implements or Dispatches attributes). * * @param iface the Java Interface to implement/dispatch * @param cdJCS the Java Class Signature for the interface * @param errlist the error list to log errors to * * @return true if the specified Java interface can be added to this * Component Definition */ protected boolean isInterfaceExpandable(Interface iface, Component cdJCS, ErrorList errlist) { boolean fExpandable = true; String sAttribute = (iface.getType() == Interface.DISPATCHES ? ATTR_DISPATCHES : ATTR_IMPLEMENTS); try { StringTable tblMethod = cdJCS.m_tblBehavior; StringTable tblBehavior = this.m_tblBehavior; for (Enumeration enmr = iface.getBehaviors(); enmr.hasMoreElements(); ) { String sSignature = (String) enmr.nextElement(); Behavior method = (Behavior) tblMethod .get(sSignature); Behavior behavior = (Behavior) tblBehavior.get(sSignature); if (behavior == null) { // if no such Behavior signature already exists, make // sure that the signature is not reserved if (isBehaviorReserved(sSignature)) { fExpandable = false; logError(IFACE_RESERVEDBEHAVIOR, WARNING, new Object[] {sAttribute, iface.getName(), getQualifiedName(), sSignature}, errlist); } continue; } // add/remove listener methods are implied; assume defaults DataType dtMethodRet = DataType.VOID; String sMethodParamDirs = "I"; if (method != null) { // method exists dtMethodRet = method.getReturnValue().getDataType(); sMethodParamDirs = method.getParameterDirections(); } // certain behavior attributes that must match cannot be // modified (fixed) if the behavior has non-manual origin boolean fFixable = !behavior.isFromNonManual(); int nSeverity = (fFixable ? INFO : WARNING); // as of Java 8 interface methods could be static if (isComponent() && behavior.isStatic()) { fExpandable = fExpandable && fFixable; logError(IFACE_SCOPEMISMATCH, nSeverity, new Object[] {sAttribute, iface.getName(), getQualifiedName(), sSignature}, errlist); } // verify that the return value type matches if (dtMethodRet != behavior.getReturnValue().getDataType()) { if (isSignature()) { // The return types differ, but since this is a // signature (and thus represents a valid Java class), // this is a co-variant return (the base definition // narrows the return type of the method defined on the // interface). Treat the behavior as if it were // declared at this level. } else { fExpandable = fExpandable && fFixable; logError(IFACE_RETURNMISMATCH, nSeverity, new Object[] {sAttribute, iface.getName(), getQualifiedName(), sSignature, behavior.getReturnValue().getDataType().toString(), dtMethodRet.toString()}, errlist); } } // verify that the parameter directions match if (!sMethodParamDirs.equals(behavior.getParameterDirections())) { fExpandable = fExpandable && fFixable; logError(IFACE_DIRECTIONMISMATCH, nSeverity, new Object[] {sAttribute, iface.getName(), getQualifiedName(), sSignature}, errlist); } // as of Java 8 interfaces could have non-public methods if (isComponent() && behavior.getAccess() != ACCESS_PUBLIC) { fExpandable = fExpandable && fFixable; logError(IFACE_BEHAVIORACCESS, nSeverity, new Object[] {sAttribute, iface.getName(), getQualifiedName(), sSignature}, errlist); } } } catch (DerivationException e) { // thrown only if error list fills up } return fExpandable; } /** * Apply the passed interface to this Component Definition. There are two * possible results: *
    *   1)  The interface conflicts with existing Behaviors of the Component
    *       Definition, in which case the Component Definition is unchanged
    *       and a ComponentException is thrown; there are several scenarios
    *       for each Behavior that could cause a conflict that would prevent
    *       then interface from being applied, specifically if the Behavior
    *       signature already exists and the associated Behavior:
    *       1)  Has a different return value
    *       2)  Is static
    *       3)  Does not match parameter directions (i.e. in/out or out)
    *       4)  Is reserved (e.g. by a Property)
    *       5)  Is not supposed to exist:  if a resolved Component has a
    *           Property derived from a super level and an applicable
    *           accessor does not exist, then the accessor was private at
    *           its declaration level
    *
    *   2)  The interface does not conflict with any existing Behaviors and
    *       is applied fully to this Component Definition; there are two
    *       possible scenarios for each Behavior specified in the interface:
    *       1)  If the Behavior signature does not already exist, it is added
    *           to the Component Definition as a resolved INSERT with the
    *           interface as the origin
    *       2)  If the Behavior signature already exists on the Component
    *           Definition, the interface is added as a Behavior origin;
    *           additionally, the exceptions declared for the interface are
    *           merged with the existing Behavior's exceptions, leaving only
    *           the common subset of exceptions between them
    * 
* Note: This Component Definition can be of any mode (RESOLVED, * DERIVATION, MODIFICATION). * * @param iface the interface object * @param cdJCS the Java Class Signature for the interface * @param tblDeferBehavior the Behaviors which didn't exist in the * base but may include interface Behaviors * @param tblDeferProperty the Properties which didn't exist in the * base but may include interface Properties * @param errlist the error list to log errors to * * @exception PropertyVetoException thrown if the interface cannot be * expanded due to conflicts (should never be thrown if * isInterfaceExpandable returned true) */ protected void expandInterface(Interface iface, Component cdJCS, StringTable tblDeferBehavior, StringTable tblDeferProperty, ErrorList errlist) throws PropertyVetoException { StringTable tblMethod = cdJCS.m_tblBehavior; StringTable tblBehavior = this.m_tblBehavior; for (Enumeration enmr = iface.getBehaviors(); enmr.hasMoreElements(); ) { String sSig = (String) enmr.nextElement(); Behavior method = (Behavior) tblMethod .get(sSig); Behavior behavior = (Behavior) tblBehavior.get(sSig); if (method != null && method.isStatic() && isComponent()) { // as of Java 8, an interface may contain static "extension methods" // no need to expand them into the component continue; } // search for a Behavior in the "defer" list and use it // if possible instead of creating a Behavior from scratch if (behavior == null && tblDeferBehavior != null) { behavior = (Behavior) tblDeferBehavior.get(sSig); if (behavior != null) { // un-defer it tblDeferBehavior.remove(sSig); // copy the behavior to this component behavior = new Behavior(this, behavior); // the Behavior is new at this level behavior.setExists(EXISTS_INSERT); // add it to this level tblBehavior.put(sSig, behavior); } } // if no such Behavior signature already exists, create // one based on the method if (behavior == null) { if (method == null) { // implied add/remove listener behavior behavior = new Behavior(this, iface, sSig); } else { behavior = new Behavior(this, iface, method); } addBehavior(behavior, false); } else { // resolve any differences between the existing Behavior // and the interface method if (method != null && behavior.getReturnValue().getDataType() != method.getReturnValue().getDataType()) { // this is a covariant return (the base definition narrows the // return type of the method defined on the interface). Treat // the behavior as if it were declared at this level. } else { behavior.setDeclaredByInterface(iface, method); } } // 2001.05.08 cp fix origin of interfaces if (iface.isFromBase() && behavior.isDeclaredAtThisLevel()) { behavior.setFromBase(); } } if (isSignature()) { StringTable tblField = cdJCS.m_tblState; StringTable tblProperty = this.m_tblState; for (Enumeration enmr = iface.getProperties(); enmr.hasMoreElements(); ) { String sProp = (String) enmr.nextElement(); Property field = (Property) tblField .get(sProp); Property property = (Property) tblProperty.get(sProp); // search for a Property in the "defer" list and skip // it here and instead add it the version from the // class itself if (property == null && tblDeferProperty != null) { property = (Property) tblDeferProperty.get(sProp); if (property != null) { continue; } } // if no such Property name already exists, create // one based on the field if (property == null) { property = new Property(this, field, iface); addProperty(property, false); } else { // check if the current property is also // flagged as being from an interface if (property.getExists() == EXISTS_NOT) { // resolve any differences between the existing Behavior // and the interface method property.mergeJCSFields(field); property.addOriginTrait(iface); } } // 2001.05.23 cp fix origin of interfaces if (iface.isFromBase() && property.isDeclaredAtThisLevel()) { property.setFromBase(); } } } } // ----- component accessors: state ------------------------------------ /** * Get the list of properties within this Component Definition. * * @return an array of property names */ public String[] getProperty() { return m_tblState.strings(); } /** * Enumerate the properties within this Component Definition. * * @return an enumeration of properties */ public Enumeration getProperties() { return m_tblState.elements(); } /** * Get a specific property based on its name. * * @param sProp the name of the property * * @return the specified property or null if the property does not exist */ public Property getProperty(String sProp) { return (Property) m_tblState.get(sProp); } /** * Determine the number of properties within this Component Definition. * * @return the count of properties */ public int getPropertyCount() { return m_tblState.getSize(); } /** * Determine if the specified Java constant Property can be added to the * Component Definition. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE or PROP_INDEXED * @param fStatic true if the Java constant is static (static final) * @param nAccess accessibility of the Java constant * * @return true if the specified Property can be added */ public boolean isJavaConstantAddable(DataType dt, String sName, int nIndexed, boolean fStatic, int nAccess) { return Property.isJavaConstantCreatable(this, dt, sName, nIndexed, fStatic, nAccess); } /** * Create a Java constant Property. A constant field is generated in the * Java class that results from the Component Definition that declares the * constant. The Property is declared as "persistent final out" and the * resulting Java field is "final". * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE or PROP_INDEXED * @param fStatic true if the Java constant is static (static final) * @param nAccess accessibility of the Java constant * * @exception PropertyVetoException if the property cannot be added as * specified or was veto'd by a property listener */ public Property addJavaConstant(DataType dt, String sName, int nIndexed, boolean fStatic, int nAccess) throws PropertyVetoException { if (!isJavaConstantAddable(dt, sName, nIndexed, fStatic, nAccess)) { subNotAddable(ATTR_PROPERTY, sName); } Property property = Property.createJavaConstant(this, dt, sName, nIndexed, fStatic, nAccess); property.setFromManual(); addProperty(property, true); return property; } /** * Determine if the specified virtual constant Property can be added to * the Component Definition. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param nAccess accessibility of the virtual constant * * @return true if the specified Property can be added */ public boolean isVirtualConstantAddable(DataType dt, String sName, int nIndexed, int nAccess) { return Property.isVirtualConstantCreatable(this, dt, sName, nIndexed, nAccess); } /** * Create a virtual constant Property, The property is declared as * "persistent instance derivable out" and no Java field results. No * accessor Behavior(s) corresponding to the virtual constant are * declared, but they are reserved. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param nAccess accessibility of the virtual constant * * @exception PropertyVetoException if the property cannot be added as * specified or was veto'd by a property listener */ public Property addVirtualConstant(DataType dt, String sName, int nIndexed, int nAccess) throws PropertyVetoException { if (!isVirtualConstantAddable(dt, sName, nIndexed, nAccess)) { subNotAddable(ATTR_PROPERTY, sName); } Property property = Property.createVirtualConstant(this, dt, sName, nIndexed, nAccess); property.setFromManual(); addProperty(property, true); return property; } /** * Determine if the specified calculated Property can be added to the * Component Definition. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param fStatic true if the Java constant is static (static final) * * @return true if the specified Property can be added */ public boolean isCalculatedPropertyAddable(DataType dt, String sName, int nIndexed, boolean fStatic) { return Property.isCalculatedPropertyCreatable(this, dt, sName, nIndexed, fStatic); } /** * Create a calculated Property. A calculated Property is declared as * "transient out", which means no corresponding Java field is generated. * A calculated Property is implemented by the developer to calculate some * value based on, perhaps, other Properties. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param fStatic true if the Java constant is static (static final) * * @exception PropertyVetoException if the property cannot be added as * specified or was veto'd by a property listener */ public Property addCalculatedProperty(DataType dt, String sName, int nIndexed, boolean fStatic) throws PropertyVetoException { if (!isCalculatedPropertyAddable(dt, sName, nIndexed, fStatic)) { subNotAddable(ATTR_PROPERTY, sName); } Property property = Property.createCalculatedProperty(this, dt, sName, nIndexed, fStatic); property.setFromManual(); addProperty(property, true); return property; } /** * Determine if the specified functional Property can be added to the * Component Definition. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param fStatic true if the Java constant is static (static final) * * @return true if the specified Property can be added */ public boolean isFunctionalPropertyAddable(DataType dt, String sName, int nIndexed, boolean fStatic) { return Property.isFunctionalPropertyCreatable(this, dt, sName, nIndexed, fStatic); } /** * Create a functional Property. Properties which are settable-only * (declared as "in") are considered to be functional. A functional * Property is implemented by the developer and has no corresponding Java * field. Functional Properties are not gettable, but they do appear in * the property sheet at design time, they are persisted in the Component * Definition, and they are initialized (which invokes the setter). * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param fStatic true if the Java constant is static (static final) * * @exception PropertyVetoException if the property cannot be added as * specified or was veto'd by a property listener */ public Property addFunctionalProperty(DataType dt, String sName, int nIndexed, boolean fStatic) throws PropertyVetoException { if (!isFunctionalPropertyAddable(dt, sName, nIndexed, fStatic)) { subNotAddable(ATTR_PROPERTY, sName); } Property property = Property.createFunctionalProperty(this, dt, sName, nIndexed, fStatic); property.setFromManual(); addProperty(property, true); return property; } /** * Determine if the specified standard Property can be added to the * Component Definition. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param fStatic true if the Java constant is static (static final) * @param fPersist true if the resulting Java field should be serialized * by the Java serialization mechanism * * @return true if the specified Property can be added */ public boolean isPropertyAddable(DataType dt, String sName, int nIndexed, boolean fStatic, boolean fPersist) { return Property.isPropertyCreatable(this, dt, sName, nIndexed, fStatic, fPersist); } /** * Create a standard Property. Standard Properties are declared as * "inout". A Java field is generated for standard Properties if storage * is required. Java methods are auto-generated for non-private standard * Properties if they are declared but not implemented; the value of a * private standard Property can be accessed using a get or set field * operation if the corresponding accessor is not implemented. * * @param dt the data type of the Property * @param sName the name of the Property * @param nIndexed specifies whether the Property is indexed, one of * PROP_SINGLE, PROP_INDEXED, or PROP_INDEXEDONLY * @param fStatic true if the Java constant is static (static final) * @param fPersist true if the resulting Java field should be serialized * by the Java serialization mechanism * * @exception PropertyVetoException if the property cannot be added as * specified or was veto'd by a property listener */ public Property addProperty(DataType dt, String sName, int nIndexed, boolean fStatic, boolean fPersist) throws PropertyVetoException { if (!isPropertyAddable(dt, sName, nIndexed, fStatic, fPersist)) { subNotAddable(ATTR_PROPERTY, sName); } Property property = Property.createProperty(this, dt, sName, nIndexed, fStatic, fPersist); property.setFromManual(); addProperty(property, true); return property; } /** * Add the passed Property to the Component Definition. * * @param property the property to add * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the property cannot be added as * specified or was veto'd by a property listener */ protected synchronized void addProperty(Property property, boolean fVetoable) throws PropertyVetoException { try { if (!isSignature()) { property.assignUID(); } if (fVetoable) { // notify veto listeners fireVetoableSubChange(property, SUB_ADD); } // add property m_tblState.put(property.getName(), property); // notify listeners property.validate(); fireSubChange(property, SUB_ADD); } catch (PropertyVetoException e) { property.invalidate(); throw e; } } /** * Determine if a property can be removed from the Component Definition. * * @param sProp the name of the property * * @return true if it is possible to remove the specified property */ public boolean isPropertyRemovable(String sProp) { Property property = getProperty(sProp); return property != null && property.isDeclaredAtThisLevel() && isModifiable() && !property.isFromNonManual(); } /** * Remove the specified property from the Component Definition. * * @param sProp the name of the property * * @exception PropertyVetoException if removal is illegal or if removal * is vetoed */ public void removeProperty(String sProp) throws PropertyVetoException { // verify that the property can be removed if (!isPropertyRemovable(sProp)) { subNotRemovable(ATTR_PROPERTY, sProp); } removeProperty(getProperty(sProp), true); } /** * Remove the specified property from the Component Definition. * * @param property the property to remove * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if removal is illegal or if removal * is vetoed */ protected synchronized void removeProperty(Property property, boolean fVetoable) throws PropertyVetoException { if (fVetoable) { // notify veto listeners fireVetoableSubChange(property, SUB_REMOVE); } // remove related accessor behaviors Behavior[] aBehavior = property.getAccessors(); int cBehavior = aBehavior.length; for (int i = 0; i < cBehavior; ++i) { Behavior behavior = aBehavior[i]; if (behavior != null) { if (property.isAccessorRemovable(i)) { property.removeAccessor(i); } else { // ! TODO prop should do this on invalidate! //behavior.setFromProperty(false); } } } // remove property m_tblState.remove(property.getName()); // notify listeners fireSubChange(property, SUB_REMOVE); // discard property property.invalidate(); } /** * Update the reference to a property when the property name changes. * This method is used internally by the Component Definition. * * @param sOld the old property name * @param sNew the new property name */ protected void renameProperty(String sOld, String sNew) { m_tblState.put(sNew, m_tblState.remove(sOld)); } // ----- component accessors: behavior --------------------------------- /** * Get the list of behavior signatures within this Component Definition. * * @return an array of behavior signatures */ public String[] getBehavior() { return m_tblBehavior.strings(); } /** * Enumerate the behaviors within this Component Definition. * * @return an enumeration of behaviors */ public Enumeration getBehaviors() { return m_tblBehavior.elements(); } /** * Get a specific behavior based on its signature. * * @param sSig the signature of the behavior * * @return the specified behavior signature or null if the behavior * signature is not within this Component Definition */ public Behavior getBehavior(String sSig) { return (Behavior) m_tblBehavior.get(sSig); } /** * Get all behaviors with the specified name. * * @param sName the name of the behavior * * @return an enumeration of behaviors that have the specified name */ public Enumeration getBehaviors(String sName) { StringTable tblBehavior = m_tblBehavior; String[] asSig = tblBehavior.stringsStartingWith(sName + '('); int cSigs = asSig.length; if (cSigs == 0) { return NullImplementation.getEnumeration(); } Behavior[] aBeh = new Behavior[cSigs]; for (int i = 0; i < cSigs; ++i) { aBeh[i] = (Behavior) tblBehavior.get(asSig[i]); } return new SimpleEnumerator(aBeh); } /** * Determine the number of behaviors within this Component Definition. * * @return the count of behaviors */ public int getBehaviorCount() { return m_tblBehavior.getSize(); } /** * Determine if a Behavior can be added to the Component Definition. The * behavior must not conflict with an existing behavior or property. * * @param sName the behavior name * * @return true if it is possible to add the behavior as specified */ public boolean isBehaviorAddable(DataType dtRet, String sName, DataType[] adtParam) { String sSig = Behavior.getSignature(sName, adtParam); return isModifiable() && !m_tblBehavior.contains(sSig) && !isBehaviorReserved(sSig); } /** * Add the specified Behavior to the Component Definition. * * @param dtRet the return value type * @param sName the behavior name * @param adtParam the parameter data types * @param fStatic the behavior's scope (static or instance) * @param nAccess the behavior's accessibility * * @return the new behavior * * @exception PropertyVetoException if the behavior cannot be added as * specified or was veto'd by a property listener */ public Behavior addBehavior(DataType dtRet, String sName, DataType[] adtParam, boolean fStatic, int nAccess) throws PropertyVetoException { if (!isBehaviorAddable(dtRet, sName, adtParam)) { subNotAddable(ATTR_BEHAVIOR, sName); } // create behavior Behavior behavior = new Behavior(this, dtRet, sName, fStatic, nAccess, adtParam, null, null); behavior.setFromManual(); addBehavior(behavior, true); return behavior; } /** * Add the passed Behavior to the Component Definition. * * @param behavior the behavior to add * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the behavior cannot be added as * specified or was veto'd by a property listener */ protected synchronized void addBehavior(Behavior behavior, boolean fVetoable) throws PropertyVetoException { try { if (!isSignature()) { // set UID behavior.assignUID(); } if (fVetoable) { // notify veto listeners fireVetoableSubChange(behavior, SUB_ADD); } // add behavior m_tblBehavior.put(behavior.getSignature(), behavior); // notify listeners behavior.validate(); fireSubChange(behavior, SUB_ADD); } catch (PropertyVetoException e) { behavior.invalidate(); throw e; } } /** * Determine if a behavior can be removed from the Component Definition. * * @param sSig the signature of the behavior * * @return true if it is possible to remove the specified behavior */ public boolean isBehaviorRemovable(String sSig) { Behavior behavior = getBehavior(sSig); return isModifiable() && behavior != null && behavior.isDeclaredAtThisLevel() && !behavior.isFromNonManual(); } /** * Remove the specified behavior from the Component Definition. * * @param sSig the signature of the behavior * * @exception PropertyVetoException if removal is illegal or if removal * is vetoed */ public synchronized void removeBehavior(String sSig) throws PropertyVetoException { if (!isBehaviorRemovable(sSig)) { subNotRemovable(ATTR_BEHAVIOR, sSig); } removeBehavior(getBehavior(sSig), true); } /** * (Internal) Remove the passed Behavior from the Component Definition. * * @param behavior the behavior to add * @param fVetoable pass as false for unconditional addition of behavior * * @exception PropertyVetoException if the behavior removal is veto'd by * a property listener */ protected synchronized void removeBehavior(Behavior behavior, boolean fVetoable) throws PropertyVetoException { if (fVetoable) { // notify veto listeners fireVetoableSubChange(behavior, SUB_REMOVE); } // remove behavior m_tblBehavior.remove(behavior.getSignature()); // notify listeners fireSubChange(behavior, SUB_REMOVE); // discard behavior behavior.invalidate(); } /** * Update the reference to an behavior when the behavior signature * changes. This method is used internally by the Component Definition. * * @param sOld the old behavior signature * @param sNew the new behavior signature */ protected void renameBehavior(String sOld, String sNew) { m_tblBehavior.put(sNew, m_tblBehavior.remove(sOld)); } /** * Determine if the Behavior signature is reserved. * * @param sSig the Behavior signature * * @return true if the signature is reserved */ protected boolean isBehaviorReserved(String sSig) { return Behavior.isSignatureReserved(this, sSig); } // ----- component accessors: aggregation declaration ------------------ /** * Get the list of aggregate categories within this Component Definition. * * @return an array of category names */ public String[] getCategories() { return m_tblCategories.strings(); } /** * Determine whether the set of aggregate categories contains the * specified category. * * @return true if the the set of aggregate categories contains the * specified category */ public boolean isCategory(String sCategory) { return m_tblCategories.contains(sCategory); } /** * Determine whether the specified category can be added to the set of * aggregate categories on this Component Definition. * * @param sCategory fully qualified Component Definition name for the * aggregate declaration * * @return true if the specified category can be added to this Component * Definition */ public boolean isCategoryAddable(String sCategory) { return isModifiable() && sCategory != null && isGlobalNameLegal(sCategory) && !m_tblCategories.contains(sCategory); } /** * Add an aggregation category. An aggregation category is a Component * Definition name which acts as a type declaration, allowing the * aggregation of instances of that Component Definition or derived * Component Definitions. * * @param sCategory fully qualified name of the Component Definition * * @exception PropertyVetoException if the new attribute value is not * accepted */ public void addCategory(String sCategory) throws PropertyVetoException { addCategory(sCategory, true); } /** * Add an aggregation category. An aggregation category is a Component * Definition name which acts as a type declaration, allowing the * aggregation of instances of that Component Definition or derived * Component Definitions. * * @param sCategory fully qualified name of the Component Definition * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the new attribute value is not * accepted */ protected synchronized void addCategory(String sCategory, boolean fVetoable) throws PropertyVetoException { // check if the category already exists if (m_tblCategories.contains(sCategory)) { return; } if (fVetoable) { // verify that the category can be added if (!isCategoryAddable(sCategory)) { subNotAddable(ATTR_CATEGORY, sCategory); } // notify veto listeners fireVetoableChange(ATTR_CATEGORY, null, sCategory); } m_tblCategories.put(sCategory, Boolean.TRUE); firePropertyChange(ATTR_CATEGORY, null, sCategory); } /** * Determine whether an aggregate category can be removed from this * Component Definition. * * @return true if the specified category can be removed from the * Component Definition */ public boolean isCategoryRemovable(String sCategory) { return isModifiable() && m_tblCategories.contains(sCategory) && ((Boolean) m_tblCategories.get(sCategory)).booleanValue(); } /** * Remove the aggregate category from the list of declared categories. * This will only succeed if the category is specified at this * Component Definition's modification level. * * @param sCategory fully qualified name of the aggregate category * * @exception PropertyVetoException if removal of the category * fails. */ public void removeCategory(String sCategory) throws PropertyVetoException { removeCategory(sCategory, true); } /** * Remove the aggregate category from the list of declared categories. * This will only succeed if the category is specified at this * Component Definition's modification level. * * @param sCategory fully qualified name of the aggregate category * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if removal of the category * fails. */ protected synchronized void removeCategory(String sCategory, boolean fVetoable) throws PropertyVetoException { // check that the category exists if (!m_tblCategories.contains(sCategory)) { return; } if (fVetoable) { // verify that the category can be removed if (!isCategoryRemovable(sCategory)) { subNotRemovable(ATTR_CATEGORY, sCategory); } // notify veto listeners fireVetoableChange(ATTR_CATEGORY, sCategory, null); } m_tblCategories.remove(sCategory); // remove any children that were of that category NextChild: for (Enumeration enmr = m_tblChildren.elements(); enmr.hasMoreElements(); ) { Component cd = (Component) enmr.nextElement(); if (isDerivedFrom(cd.getSuperName(), sCategory)) { // make sure the child is not legal by any other category // (don't lose any children that are still legal) for (Enumeration enmrCat = m_tblCategories.keys(); enmrCat.hasMoreElements(); ) { if (isDerivedFrom(cd.getSuperName(), (String) enmrCat.nextElement())) { continue NextChild; } } // (if it must be removed, then it may be removed, since // otherwise the child would not be here) if (cd.getExists() == EXISTS_INSERT && cd.m_fBaseLevel) { removeChild(cd, false); } } } // notify listeners firePropertyChange(ATTR_CATEGORY, sCategory, null); } /** * Determine what is the aggregatee category on a parent component * that this Component Definition belongs to. * * @return the parent's aggregatee category * * Note: there could be many categories that the child component * belongs to. In that case we return the first one. */ public String getCategory() { if (isGlobal()) { throw new IllegalStateException("Component is not child"); } Component cdParent = getParent(); String[] asCategory = cdParent.getCategories(); for (int i = 0; i < asCategory.length; i++) { String sCategory = asCategory[i]; if (this.isDerivedFrom(sCategory)) { return sCategory; } } throw new IllegalStateException("Missing category for " + getQualifiedName()); } // ----- component accessors: aggregation definition ------------------- /** * Get the list of all aggregated (child) components within this Component * Definition. This list includes children that have been removed. * * @return an array of child component names */ public String[] getChildren() { return m_tblChildren.strings(); } /** * Determine if the specified child name is taken. * * @return true if the specified name is taken */ public boolean isChild(String sName) { return m_tblChildren.contains(sName); } /** * Get a named aggregated component within this Component Definition. * * @param sChild the unqualified name of the child Component Definition * * @return the specified child Component Definition or null if the specified * child has been removed or does not exist */ public Component getChild(String sChild) { Component cd = (Component) m_tblChildren.get(sChild); if (cd != null) { int nState = cd.m_nFlags & EXISTS_MASK; if (nState == EXISTS_INSERT || nState == EXISTS_UPDATE) { return cd; } } return null; } /** * Get a component relative to this Component Definition. * * @param sLocal the "local id" that maps from this component to the desired * child component * * @return the specified child Component Definition or null if the specified * child has been removed or does not exist */ public Component getLocal(String sLocal) { Component cd = this; String[] asSimple = parseDelimitedString(sLocal, LOCAL_ID_DELIM); for (int i = 0, c = asSimple.length; i < c; ++i) { cd = cd.getChild(asSimple[i]); if (cd == null) { break; } } return cd; } /** * Determine whether additional child components can be added to this * Component Definition. * * @param cdSuper super Component of the proposed child * @param sChild proposed child name (local Component name) * * @return true if additional child components are allowed */ public boolean isChildAddable(Component cdSuper, String sChild) { return isModifiable() && isSimpleNameLegal(sChild, false) && !m_tblChildren.contains(sChild) // cp 2001.03.21 ensure that the super is global && cdSuper.isGlobal() && !cdSuper.isFinal() // cp 2000.03.21 disallow addition of child that inherits from // a static global // gg 2001.03.30 belay that order (but the child must stay static) // && !cdSuper.isStatic() && isChildSuperLegal(cdSuper.getQualifiedName()); } /** * Determine whether the specified super is in a legal category. * * @param sSuper fully qualified global Component Definition identity * * @return true if super is of a declared category */ public boolean isChildSuperLegal(String sSuper) { // check if the super component for the proposed child derives // from a component specified in the aggregate declaration do { if (m_tblCategories.contains(sSuper)) { return true; } int ofLastDot = sSuper.lastIndexOf(GLOBAL_ID_DELIM); if (ofLastDot < 0) { return false; } sSuper = sSuper.substring(0, ofLastDot); } while (true); } /** * Add a child Component Definition to this Component Definition. * * @param sChild the unqualified local name for the child * @param cdSuper the Component Definition that the child will derive from * * @return the new child component * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public Component addChild(Component cdSuper, String sChild) throws ComponentException, PropertyVetoException { return addChild(cdSuper, sChild, true); } /** * Add a child Component Definition to this Component Definition. * * @param sChild the unqualified local name for the child * @param cdSuper the Component Definition that the child will derive from * @param fVetoable true if the method can veto the change * * @return the new child component * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected Component addChild(Component cdSuper, String sChild, boolean fVetoable) throws ComponentException, PropertyVetoException { // check if a child can be added if (fVetoable && (cdSuper == null || cdSuper.getMode() != RESOLVED || !isChildAddable(cdSuper, sChild))) { subNotAddable(ATTR_CHILD, sChild); } // create a child derivation from the specified super Component cdDelta = (Component) cdSuper.getNullDerivedTrait(this, DERIVATION); cdDelta.m_sSuper = cdSuper.getQualifiedName(); cdDelta.m_sName = sChild; cdDelta.setExists(EXISTS_INSERT); cdDelta.assignUID(); // create the new child Loader loader = new NullStorage(); ErrorList errlist = new ErrorList(); Component cdChild = (Component) cdSuper.resolve(cdDelta, this, loader, errlist); cdChild.finalizeResolve(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".addChild: " + "Serious errors occurred during resolution!"); } // add the child return addChild(cdChild, fVetoable); } /** * Add a child Component Definition to this Component Definition. * * @param cdChild the child component * @param fVetoable true if the method can veto the change * * @return the new child component * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized Component addChild(Component cdChild, boolean fVetoable) throws ComponentException, PropertyVetoException { try { cdChild.assignUID(); if (fVetoable) { // notify veto listeners fireVetoableSubChange(cdChild, SUB_ADD); } // add the new child m_tblChildren.put(cdChild.getName(), cdChild); // notify listeners cdChild.validate(); fireSubChange(cdChild, SUB_ADD); } catch (PropertyVetoException e) { cdChild.invalidate(); throw e; } return cdChild; } /** * Determine whether the specified child component can be removed from * this Component Definition. * * @param sChild the unqualified local name of the child * * @return true if the child can be removed */ public boolean isChildRemovable(String sChild) { // component definition must be modifiable, child must exist Component cd = (Component) m_tblChildren.get(sChild); if (isModifiable() && cd != null) { int nState = cd.m_nFlags & EXISTS_MASK; if (nState == EXISTS_INSERT || nState == EXISTS_UPDATE) { return true; } } return false; } /** * Remove the specified child from the Component Definition. * * @param sChild the unqualified local name of the child * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public void removeChild(String sChild) throws PropertyVetoException { // verify child can be removed if (!isChildRemovable(sChild)) { subNotRemovable(ATTR_CHILD, sChild); } removeChild((Component) m_tblChildren.get(sChild), true); } /** * Remove the specified child from the Component Definition. * * @param cd the child component * @param fVetoable true if the method can veto the change * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized void removeChild(Component cd, boolean fVetoable) throws PropertyVetoException { if (fVetoable) { // notify veto listeners fireVetoableSubChange(cd, SUB_REMOVE); } // cd.m_fBaseLevel same as: // (cd.m_nPrevFlags & EXISTS_MASK) != EXISTS_INSERT // except that root Component is an EXISTS_INSERT so if it // were added as a child prev would be EXISTS_INSERT even // at the modification level it was inserted boolean fDestroy = cd.isDeclaredAtThisLevel(); if (fDestroy) { // the child was added at this level so just discard it m_tblChildren.remove(cd.getName()); } else { // the child was added at a previous level so mark it removed cd.m_nFlags = (cd.m_nFlags & ~EXISTS_MASK) | EXISTS_DELETE; } // notify listeners fireSubChange(cd, SUB_REMOVE); if (fDestroy) { // discard the component cd.invalidate(); } } /** * Determine if this component and that component are part of the "same" * component. * * @param that the other component * * @return true if this and that are descendents (containment-wise) of * the same component */ public boolean isRelative(Component that) { return this.getGlobalParent() == that.getGlobalParent(); } /** * Determine if the specified component can be copied to this component. * * @param cdSuper the super of the child being copied * @param sChild the name to give the child * @param cdChild the child component to copy to this component * * @return true if the specified child component can be copied to this * component */ public boolean isChildCopyable(Component cdSuper, String sChild, Component cdChild) { if (cdSuper == null || sChild == null || cdChild == null) { return false; } // child must derive from the provided super if (!cdChild.isDerivedFrom(cdSuper.getQualifiedName())) { return false; } // child must be addable to its new location if (!this.isChildAddable(cdSuper, sChild)) { return false; } return true; } /** * Create a copy of the specified child under this Component. * * @param cdSuper the super of the child being copied * @param sChild the name to give the child * @param cdChild the child component to adopt * @param loader the loader to use if other information is required * @param errlist the error list to log errors to (optional) * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public Component copyChild(Component cdSuper, String sChild, Component cdChild, Loader loader, ErrorList errlist) throws ComponentException, PropertyVetoException { return copyChild(cdSuper, sChild, cdChild, loader, errlist, true); } /** * Create a copy of the specified child under this Component. * * @param cdSuper the super of the child being copied * @param sChild the name to give the child * @param cdChild the child component to adopt * @param loader the loader to use if other information is required * @param errlist the error list to log errors to (optional) * @param fVetoable true if the method can veto the change * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected Component copyChild(Component cdSuper, String sChild, Component cdChild, Loader loader, ErrorList errlist, boolean fVetoable) throws ComponentException, PropertyVetoException { // verify legality of operation if (fVetoable && !isChildCopyable(cdSuper, sChild, cdChild)) { subNotAddable(ATTR_CHILD, sChild); } // for debugging purposes, make sure there is an error list if (errlist == null) { errlist = new ErrorList(); } // extract the child derivation Component cdDelta = (Component) cdChild.extract(cdSuper, this, loader, errlist); cdDelta.finalizeExtract(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".copyChild: " + "Serious errors occurred during extraction!"); } // it is a copy; nix the old UID cdDelta.clearUID(); // same set-up processing as in addChild() cdDelta.m_sSuper = cdSuper.getQualifiedName(); cdDelta.m_sName = sChild; cdDelta.setExists(EXISTS_INSERT); cdDelta.assignUID(); // create the copy of the child cdChild = (Component) cdSuper.resolve(cdDelta, this, loader, errlist); cdChild.finalizeResolve(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".copyChild: " + "Serious errors occurred during resolution!"); } // add the child to this Component return addChild(cdChild, fVetoable); } /** * Determine if the specified component can be moved to this component. * * @param cdSuper the super of the child being adopted * @param sChild the name to give the child * @param cdChild the child component to move to this component * * @return true if specified child component can be moved to this * component */ public boolean isChildMoveable(Component cdSuper, String sChild, Component cdChild) { // child must be copyable if (!isChildCopyable(cdSuper, sChild, cdChild)) { return false; } // child must be a "relative", since it will be moved from its // current location if (!isRelative(cdChild)) { return false; } // child is only movable if it was added at this level if (!cdChild.isDeclaredAtThisLevel()) { return false; } // child must be removable from its current location Component cdParent = cdChild.getParent(); if (cdParent == null || !cdParent.isChildRemovable(cdChild.getName())) { return false; } return true; } /** * Move the specified child under this Component. * * @param cdSuper the super of the child being moved * @param sChild the name to give the child * @param cdChild the child component to adopt * @param loader the loader to use if other information is required * @param errlist the error list to log errors to (optional) * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public Component moveChild(Component cdSuper, String sChild, Component cdChild, Loader loader, ErrorList errlist) throws ComponentException, PropertyVetoException { return moveChild(cdSuper, sChild, cdChild, loader, errlist, true); } /** * Move the specified child under this Component. * * @param cdSuper the super of the child being moved * @param sChild the name to give the child * @param cdChild the child component to adopt * @param loader the loader to use if other information is required * @param errlist the error list to log errors to (optional) * @param fVetoable true if the method can veto the change * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected Component moveChild(Component cdSuper, String sChild, Component cdChild, Loader loader, ErrorList errlist, boolean fVetoable) throws ComponentException, PropertyVetoException { // verify legality of operation if (fVetoable && !isChildMoveable(cdSuper, sChild, cdChild)) { subNotAddable(ATTR_CHILD, sChild); } // for debugging purposes, make sure there is an error list if (errlist == null) { errlist = new ErrorList(); } // extract the child derivation Component cdDelta = (Component) cdChild.extract(cdSuper, this, loader, errlist); cdDelta.finalizeExtract(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".moveChild: " + "Serious errors occurred during extraction!"); } // same set-up processing as in addChild() (except do not change UID) cdDelta.m_sSuper = cdSuper.getQualifiedName(); cdDelta.m_sName = sChild; cdDelta.setExists(EXISTS_INSERT); // create the copy of the child Component cdNewChild = (Component) cdSuper.resolve(cdDelta, this, loader, errlist); cdNewChild.finalizeResolve(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".moveChild: " + "Serious errors occurred during resolution!"); } // remove the child from the other Component cdChild.getParent().removeChild(cdChild, fVetoable); // add the child to this Component return addChild(cdNewChild, fVetoable); } /** * Determine whether the specified child component can be un-removed from * this Component Definition. Note that the use of the term un-removable * means that a removal has already occurred and the removal can be * undone (i.e. the component can be un-removed); it does not mean that * the component cannot be removed (i.e. the component is unremovable). * * @param sChild the unqualified local name of the child * * @return true if the child can be un-removed */ public boolean isChildUnremovable(String sChild) { // component definition must be modifiable, child must have been // removed at this level Component cd = (Component) m_tblChildren.get(sChild); return isModifiable() && cd != null && (cd.m_nFlags & EXISTS_MASK) == EXISTS_DELETE; } /** * Un-remove the specified child from the Component Definition. * * @param sChild the unqualified local name of the child * * @return the component that was un-removed * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public Component unremoveChild(String sChild) throws PropertyVetoException { // verify child is un-removable if (!isChildUnremovable(sChild)) { subNotUnremovable(ATTR_CHILD, sChild); } return unremoveChild((Component) m_tblChildren.get(sChild), true); } /** * Un-remove the specified child from the Component Definition. * * @param cd the child component * @param fVetoable true if the method can veto the change * * @return the component that was un-removed * * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ protected synchronized Component unremoveChild(Component cd, boolean fVetoable) throws PropertyVetoException { // check if there is nothing to do if ((cd.m_nFlags & EXISTS_MASK) != EXISTS_DELETE) { return cd; } if (fVetoable) { // notify veto listeners fireVetoableSubChange(cd, SUB_UNREMOVE); } // the child was added at a previous level and removed at this level, // so to un-remove it we just mark it as updated at this level cd.m_nFlags = (cd.m_nFlags & ~EXISTS_MASK) | EXISTS_UPDATE; // notify listeners fireSubChange(cd, SUB_UNREMOVE); return cd; } /** * Update the reference to a child when the child name changes. * This method is used internally by the Component Definition. * * @param sOld the old child name * @param sNew the new child name */ protected void renameChild(String sOld, String sNew) { m_tblChildren.put(sNew, m_tblChildren.remove(sOld)); } /** * Replace the super compoenent of the specified child. * * @param sChild the name of the child component * @param cdOldSuper the super of the child being modified * @param cdNewSuper the new super component for the child component * @param loader the loader to use if other information is required * @param errlist the error list to log errors to (optional) * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public Component replaceChildSuper(String sChild, Component cdOldSuper, Component cdNewSuper, Loader loader, ErrorList errlist) throws ComponentException, PropertyVetoException { return replaceChildSuper(sChild, cdOldSuper, cdNewSuper, loader, errlist, true); } /** * Replace the super compoenent of the specified child. * * @param sChild the name of the child component * @param cdOldSuper the super of the child being modified * @param cdNewSuper the new super component for the child component * @param loader the loader to use if other information is required * @param errlist the error list to log errors to (optional) * * @exception ComponentException * @exception PropertyVetoException if the property cannot be set as * specified or was vetoed by a property listener */ public Component replaceChildSuper(String sChild, Component cdOldSuper, Component cdNewSuper, Loader loader, ErrorList errlist, boolean fVetoable) throws ComponentException, PropertyVetoException { Component cdChild = (Component) m_tblChildren.get(sChild); // verify legality of operation if (fVetoable) { // child must be removable from its current location // child must derive from the provided super if (!isChildRemovable(sChild) || !cdChild.isDeclaredAtThisLevel() || !cdChild.isDerivedFrom(cdOldSuper.getQualifiedName())) { subNotRemovable(ATTR_CHILD, sChild); } if (cdOldSuper == null || cdNewSuper == null || cdNewSuper.getMode() != RESOLVED) { subNotAddable(ATTR_CHILD, sChild); } // notify veto listeners fireVetoableSubChange(cdChild, SUB_CHANGE); } // for debugging purposes, make sure there is an error list if (errlist == null) { errlist = new ErrorList(); } // extract the child derivation Component cdDelta = (Component) cdChild.extract(cdOldSuper, this, loader, errlist); cdDelta.finalizeExtract(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".replaceChildSuper: " + "Serious errors occurred during extraction!"); } if (!cdDelta.m_sName.equals(sChild) || !cdDelta.getUID().equals(cdChild.getUID()) || cdDelta.getExists() != EXISTS_INSERT) { throw new ComponentException(CLASS + ".replaceChildSuper: " + "Critical attributes have changed during extraction!"); } // replace the super name cdDelta.m_sSuper = cdNewSuper.getQualifiedName(); // resolve against the new super cdChild = (Component) cdNewSuper.resolve(cdDelta, this, loader, errlist); cdChild.finalizeResolve(loader, errlist); if (errlist.isSevere()) { errlist.print(); throw new ComponentException(CLASS + ".replaceChildSuper: " + "Serious errors occurred during resolution!"); } // replace the child m_tblChildren.put(sChild, cdChild); fireSubChange(cdChild, SUB_CHANGE); return cdChild; } // ----- JCS helpers ---------------------------------------------------- /** * Add Java and JASM implementations to the JCS. * * @param clz the ClassFile to create a signature from * @param sJava the Java source code */ public void addJcsImplementations(ClassFile clz, String sJava) { if (!isSignature()) { throw new IllegalStateException(); } Map map = Collections.EMPTY_MAP; if (sJava != null && sJava.length() > 0) { ScriptParser parser = new ScriptParser(); map = parser.parse(sJava); } for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { Behavior beh = (Behavior) enmr.nextElement(); String sLang = null; String sScript = null; if (!map.isEmpty()) { // look up the source code for the behavior StringBuffer sb = new StringBuffer(getName()); sb.append('.') .append(beh.getName()) .append('('); DataType[] adt = beh.getParameterTypes(); for (int i = 0, c = adt.length; i < c; ++i) { if (i > 0) { sb.append(','); } sb.append(toSimpleSignature(adt[i].getType())); } sb.append(')'); sLang = "Java (Original)"; sScript = (String) map.get(sb.toString()); } if (sScript == null && clz != null) { // create the JASM for the behavior String sSig = beh.getName() + beh.getJVMSignature(); Method method = clz.getMethod(sSig); if (method != null) { CodeAttribute code = (CodeAttribute) method.getAttribute( com.tangosol.dev.assembler.Constants.ATTR_CODE); if (code != null) { sLang = "Jasm (Original)"; sScript = code.toJasm(); // gg 2001.08.24 to improve readability... String sClass = getName(); String sSuper = getSuperName(); int ofPkg = sClass.lastIndexOf('.'); sScript = replace(sScript, ' ' + sSuper + '.', " super."); if (ofPkg > 0) { String sPackage = sClass.substring(0, ofPkg + 1); sScript = replace(sScript, ' ' + sPackage, " "); } } } } if (sScript != null) { beh.setJcsImplementation(sLang, sScript); } } } protected static String toSimpleSignature(Type type) { if (type instanceof ArrayType) { return toSimpleSignature(((ArrayType) type).getElementType()) + "[]"; } else if (type instanceof ClassType) { return ((ClassType) type).getShortName(); } else { return type.toString(); } } /** * Undo the effects of addJcsImplementations. */ public void removeJcsImplementations() { if (!isSignature()) { throw new IllegalStateException(); } for (Enumeration enmr = m_tblBehavior.elements(); enmr.hasMoreElements(); ) { Behavior beh = (Behavior) enmr.nextElement(); beh.removeJcsImplementation(); } } // ----- compile plan --------------------------------------------------- /** * Determine what child classes must be created and what their supers will * be. This method is only valid against a global (no parent) component. * * @param loader the Loader to load super components from * * @return a CompilePlan */ public CompilePlan getCompilePlan(Loader loader) throws ComponentException { return getCompilePlan(loader, false); } /** * Determine what child classes must be created and what their supers will * be. This method is only valid against a global (no parent) component. * * @param loader the Loader to load super components from * @param fDebug true if building a compile plan for a debug compile * * @return a CompilePlan */ public CompilePlan getCompilePlan(Loader loader, boolean fDebug) throws ComponentException { if (!isGlobal()) { throw new IllegalStateException("Component is not global"); } if (fDebug) { StringTable tbl = new StringTable(); buildDebugSuperMap(tbl); return new CompilePlan(getQualifiedName(), tbl, tbl); } // determine what components will be present at this level StringTable tblDelta = new StringTable(); Hashtable tblCache = new Hashtable(); buildDeltaMap(tblDelta, loader, tblCache); // determine the supers of each local component StringTable tblSuper = new StringTable(); Hashtable tblDeltas = new Hashtable(); resolveSuperMap(tblSuper, loader, tblCache, tblDeltas); return new CompilePlan(getQualifiedName(), tblSuper, tblDelta); } /** * Build the default super map. */ private void buildDebugSuperMap(StringTable tbl) { String[] asChildren = getChildren(); for (int i = 0; i < asChildren.length; i++) { Component child = getChild(asChildren[i]); if (child != null) { tbl.put(child.getLocalName(), child.getSuperName()); child.buildDebugSuperMap(tbl); } } } /** * Build a table of all child (local) names that have deltas that would * require classes to be generated. * * @param tblDelta the table into which the local names of delta children * will be placed * @param loader the loader to use to load components not found in cache * @param tblCache a Hashtable (optional) used to cache loaded components * * @return true if the component has a delta * * @throws ComponentException if the requested component cannot be located * and successfully loaded */ private boolean buildDeltaMap(StringTable tblDelta, Loader loader, Hashtable tblCache) throws ComponentException { boolean fDelta = false; // determine what children have deltas String[] asChildren = getChildren(); for (int i = 0; i < asChildren.length; i++) { Component child = (Component) m_tblChildren.get(asChildren[i]); if (child != null) { switch (child.m_nFlags & EXISTS_MASK) { case EXISTS_INSERT: case EXISTS_UPDATE: if (child.buildDeltaMap(tblDelta, loader, tblCache) // cp 2000.03.20 always gen child at insert level || (child.m_nFlags & EXISTS_MASK) == EXISTS_INSERT) { // child has a delta, so add it to the delta table tblDelta.add(child.getLocalName()); fDelta = true; } break; case EXISTS_DELETE: // child deleted at this derivation level fDelta = true; break; case EXISTS_NOT: // child does not exist break; default: throw new IllegalStateException(); } } } if (!fDelta) { fDelta = !isClassDiscardable(getComponent(getSuperName(), loader, tblCache)); } return fDelta; } /** * Build a table of all child (local) names and their supers. * * @param tblSuper the table into which the local names of children * will be placed, mapping to their actual supers * @param loader the loader to use to load components not found in cache * @param tblCache a Hashtable used to cache loaded components * @param tblDeltas a Hashtable used to cache delta maps * * @throws ComponentException if the requested component cannot be located * and successfully loaded */ private void resolveSuperMap(StringTable tblSuper, Loader loader, Hashtable tblCache, Hashtable tblDeltas) throws ComponentException { String[] asChildren = getChildren(); for (int i = 0; i < asChildren.length; i++) { Component child = getChild(asChildren[i]); if (child != null) { tblSuper.put(child.getLocalName(), child.resolveSuper(loader, tblCache, tblDeltas)); child.resolveSuperMap(tblSuper, loader, tblCache, tblDeltas); } } } /** * Determine the super for the specified component. * * @param loader the loader to use to load components not found in cache * @param tblCache a Hashtable used to cache loaded components * @param tblDeltas a Hashtable used to cache component delta tables * * @return fully qualified name of the super component * * @throws ComponentException if a necessary component cannot be located and * successfully loaded */ private String resolveSuper(Loader loader, Hashtable tblCache, Hashtable tblDeltas) throws ComponentException { // global supers always exist String sSuper = getSuperName(); if (isGlobal(sSuper)) { return sSuper; } String sSuperGlobal = getGlobalName(sSuper); Component cdSuperGlobal = getComponent(sSuperGlobal, loader, tblCache); // get the delta map for the super to see if a local super has a delta StringTable tblDelta = (StringTable) tblDeltas.get(sSuperGlobal); if (tblDelta == null) { tblDelta = new StringTable(); cdSuperGlobal.buildDeltaMap(tblDelta, loader, tblCache); tblDeltas.put(sSuperGlobal, tblDelta); } String sSuperLocal = getLocalName(sSuper); if (tblDelta.contains(sSuperLocal)) { return sSuper; } // the expected super did not have a delta, so the super of this component is // the super of the previously-expected super Component cdSuperLocal = cdSuperGlobal.getLocal(sSuperLocal); return cdSuperLocal.resolveSuper(loader, tblCache, tblDeltas); } /** * Load the specified component definition. * * @param sName fully qualified name of the component to load * @param loader the loader to use to load components not found in cache * @param tblCache a Hashtable (optional) used to cache loaded components * * @return the requested component (never null) * * @throws ComponentException if the requested component cannot be located and * successfully loaded */ private static Component getComponent(String sName, Loader loader, Hashtable tblCache) throws ComponentException { String sGlobal = getGlobalName(sName); Component cd = null; if (tblCache != null) { // check the cache cd = (Component) tblCache.get(sGlobal); } if (cd == null) { ErrorList errlist = new ErrorList(); try { // use the loader to find the component cd = loader.loadComponent(sGlobal, true, errlist); } catch (ComponentException e) { out("Exception loading component " + sGlobal + ":"); out(e); throw e; } finally { if (!errlist.isEmpty()) { out("Errors encountered loading component " + sGlobal + ":"); errlist.print(); } } // update the cache if (tblCache != null && cd != null) { tblCache.put(sGlobal, cd); } } // if local, find the child if (!isGlobal(sName)) { cd = cd.getLocal(getLocalName(sName)); } // expected not to return null if (cd == null) { throw new ComponentException("Component " + sName + " does not exist"); } return cd; } // ----- Object methods ------------------------------------------------- /** * Compares this Component to another Object for equality. * * @param obj the other Object to compare to this * * @return true if this Component equals that Object */ public boolean equals(Object obj) { if (obj instanceof Component) { Component that = (Component) obj; return this == that || ( this.m_nType == that.m_nType && this.m_nVersion == VERSION && this.m_nFlags == that.m_nFlags && this.m_nPrevFlags == that.m_nPrevFlags && this.m_fBaseLevel == that.m_fBaseLevel && this.m_sName .equals(that.m_sName ) && this.m_sSuper .equals(that.m_sSuper) && (this.m_integration == null ? that.m_integration == null : this.m_integration .equals(that.m_integration) ) && this.m_tblImplements.equals(that.m_tblImplements) && this.m_tblDispatches.equals(that.m_tblDispatches) && this.m_tblState .equals(that.m_tblState ) && this.m_tblBehavior .equals(that.m_tblBehavior ) && this.m_tblCategories.equals(that.m_tblCategories) && this.m_tblChildren .equals(that.m_tblChildren ) && super.equals(that) ); } return false; } /** * Creates a cloned copy of this Component, including its sub-traits. * * @return a cloned copy of this Component * * @exception CloneNotSupportedException if the Component is not global */ public Object clone() throws CloneNotSupportedException { // cannot clone a child component if (getParentTrait() != null) { throw new CloneNotSupportedException(); } // use copy constructor (with no parent) Component cd = new Component(null, this); if (cd.getMode() == RESOLVED) { cd.validate(); } return cd; } // ----- debug methods -------------------------------------------------- /** * Provide the entire set of trait information in a printed format. * * @param out PrintWriter object to dump the information to * @param sIndent a string used to indent each line of dumped information */ public void dump(PrintWriter out, String sIndent) { dump(out, sIndent, true); } /** * Provide the entire set of trait information in a printed format. * * @param out PrintWriter object to dump the information to * @param sIndent a string used to indent each line of dumped information * @param fIndentFirstLine false to suppress first line indention */ public void dump(PrintWriter out, String sIndent, boolean fIndentFirstLine) { toXml().writeXml(out, true); /* boolean fDerOrMod = (getMode() == MODIFICATION || getMode() == DERIVATION); int nSpecable = EXISTS_SPECIFIED | VIS_SPECIFIED | SCOPE_SPECIFIED | IMPL_SPECIFIED | DERIVE_SPECIFIED | ANTIQ_SPECIFIED | STG_SPECIFIED | DIST_SPECIFIED; if (isSignature()) { nSpecable |= MISC_ISINTERFACE | MISC_ISTHROWABLE | ACCESS_SPECIFIED; } if (fIndentFirstLine) { out.print(sIndent); } switch (m_nType) { case COMPLEX: out.print("complex property value of type "); // no break; case COMPONENT: out.print("component " + m_sName); break; case SIGNATURE: out.print("Java Class Signature (JCS) " + m_sName); break; default: out.print(" " + m_sName); break; } out.print (" derives from " + (m_sSuper == null || m_sSuper.length() == 0 ? "" : m_sSuper)); out.println(" (base level=" + m_fBaseLevel + ')'); out.println(sIndent + "qualified=" + getQualifiedName()); // trait attributes super.dump(out, sIndent); // integration if (m_integration != null) { out.println(sIndent + "integration " + m_integration.getUniqueName()); m_integration.dump(out, nextIndent(sIndent)); } // implements dump(out, sIndent, m_tblImplements, "interfaces implemented"); // dispatches dump(out, sIndent, m_tblDispatches, "interfaces dispatched"); // flags out.print (sIndent + "flags=0x" + toHexString(m_nFlags, 8)); out.println(" (" + flagsDescription(m_nFlags, nSpecable, fDerOrMod) + ')'); // previous flags out.print (sIndent + "prev flags=0x" + toHexString(m_nPrevFlags, 8)); out.println(" (" + flagsDescription(m_nPrevFlags, nSpecable, fDerOrMod) + ')'); // state dump(out, sIndent, m_tblState, "properties"); // behavior dump(out, sIndent, m_tblBehavior, "behaviors"); // aggregate categories out.println(sIndent + "aggregates " + arrayDescription(m_tblCategories.strings())); // children dump(out, sIndent, m_tblChildren, "children"); */ } // ----- helpers -------------------------------------------------------- /** * Get the name of the root Component Definition. * * @return the name of the root Component Definition */ public static String getRootName() { return "Component"; } /** * Determine if the passed string is a legal simple (unqualified) name * for a Component Definition. * * According to section 7.1 of the Java Language Specification, * Second Edition, it is illegal for a package to contain a class * or interface type and a subpackage with the same name. * To inforce this rule, all global Component Definitions have names * that start with an upper case letter and the corresponding packages * just have this first letter lower-cased. * * @param sName the string containing the unqualified name * param fGlobal if true, check the global name, otherwise local * * @return true if the specified name is legal, false otherwise * * @see com.tangosol.dev.component.ComponentType#getComponentPackage(Component) */ public static boolean isSimpleNameLegal(String sName, boolean fGlobal) { return sName != null && sName.indexOf(GLOBAL_ID_DELIM) < 0 && sName.indexOf(LOCAL_ID_DELIM) < 0 && (!fGlobal || Character.isUpperCase(sName.charAt(0))) && ClassHelper.isSimpleNameLegal(sName); } /** * Determine if the passed string is a legal fully qualified Component * Definition name. * * @param sName the string containing the qualified name * * @return true if a legal identifier, false otherwise */ public static boolean isQualifiedNameLegal(String sName) { String sRoot = getRootName(); // check for obvious problems (blank, doesn't start with root component name) if (sName == null || sName.length() == 0 || !sName.startsWith(sRoot)) { return false; } // check for the name of the root component int cchName = sName.length(); int cchRoot = sRoot.length(); if (cchName == cchRoot) { return true; } try { // check for delimiter following root name char ch = sName.charAt(cchRoot); if (ch != GLOBAL_ID_DELIM && ch != LOCAL_ID_DELIM) { return false; } // check for illegal identifier or qualification in the name (A.B$c$d) int ofStart = 0; boolean fGlobal = true; while (true) { int ofEnd = sName.indexOf(GLOBAL_ID_DELIM, ofStart); if (ofEnd > 0) { if (!isSimpleNameLegal(sName.substring(ofStart, ofEnd), fGlobal)) { return false; } ofStart = ofEnd + 1; } else { break; } } while (true) { int ofEnd = sName.indexOf(LOCAL_ID_DELIM, ofStart); if (ofEnd > 0) { if (!isSimpleNameLegal(sName.substring(ofStart, ofEnd), fGlobal)) { return false; } ofStart = ofEnd + 1; fGlobal = false; } else { break; } } if (!isSimpleNameLegal(sName.substring(ofStart), fGlobal)) { return false; } } catch (StringIndexOutOfBoundsException e) { return false; } return true; } /** * Determine if the passed string is a global qualified name (not local). * * @param sName the string containing the name * * @return true if a qualified global Component Definition name */ public static boolean isGlobalNameLegal(String sName) { return isQualifiedNameLegal(sName) && sName.indexOf(LOCAL_ID_DELIM) < 0; } /** * Determine if the fully qualifed component name is a global name. * * @param sName fully qualified name * * @return true if a global name */ public static boolean isGlobal(String sName) { return sName.indexOf(LOCAL_ID_DELIM) < 0; } /** * Determine the global portion of a fully qualifed component name. * For example, if the qualified name is "X.Y$A$B", the global name is "X.Y". * * @param sName fully qualified name to get a global name of * * @return the global name */ public static String getGlobalName(String sName) { int of = sName.indexOf(LOCAL_ID_DELIM); return of < 0 ? sName : sName.substring(0, of); } /** * Determine the simple local portion of a fully qualifed component name. * For example, if the qualified name is X.Y$A$B, the simple local name is B. * * @param sName fully qualified name to get a simple name of * * @return the simple local name, or null if the component name * is global */ public static String getSimpleName(String sName) { int of = sName.lastIndexOf(LOCAL_ID_DELIM); return of < 0 ? null : sName.substring(of + 1); } /** * Determine the local portion of a fully qualifed component name. * For example, if the qualified name is X.Y$A$B, the local portion is A$B. * * @param sName fully qualified name to get a local name of * * @return the local portion of the component name, or null if the * component name is global */ public static String getLocalName(String sName) { int of = sName.indexOf(LOCAL_ID_DELIM); return of < 0 ? null : sName.substring(of + 1); } /** * Determine if the first qualified global name denotes a Component * Definition that derives from the Component Definition denoted by * the second qualified global name. * * @param sSub the sub in question * @param sSuper the super in question * * @return true if the sub derives, directly or indirectly, from the super */ public static boolean isDerivedFrom(String sSub, String sSuper) { return isGlobalNameLegal(sSub) && (sSub.equals(sSuper) || sSub.startsWith(sSuper + '.')); } /** * Determine if this Component derives from a Component with the specified * (fully qualified) name, assuming that such a Component does exist. * * @param sSuperName the qulified name of the super-component in question * * @return true if this Component derives from the Component */ public boolean isDerivedFrom(String sSuperName) { String sThisName = this.getQualifiedName(); String sThatName = sSuperName; if (isGlobal()) { return isDerivedFrom(sThisName, sThatName); } // could be same component if (sThisName.equals(sThatName)) { return true; } // that could be a global name if (isGlobalNameLegal(sThatName)) { return isDerivedFrom(this.getGlobalSuperName(), sThatName); } // both are children int iPos = sThisName.lastIndexOf(LOCAL_ID_DELIM); String sThisLocalName = sThisName.substring(iPos + 1); String sThisGlobalName = sThisName.substring(0, iPos); iPos = sThatName.lastIndexOf(LOCAL_ID_DELIM); String sThatLocalName = sThatName.substring(iPos + 1); String sThatGlobalName = sThatName.substring(0, iPos); return sThisLocalName.equals(sThatLocalName) && isDerivedFrom(sThisGlobalName, sThatGlobalName); } /** * Determine if this Component derives from the specified Component. * * @param cdSuper the super-component in question * * @return true if this Component derives from the passed Component */ public boolean isDerivedFrom(Component cdSuper) { final Component that = cdSuper; // could be same component String sThisName = this.getQualifiedName(); String sThatName = that.getQualifiedName(); if (sThisName.equals(sThatName)) { return true; } // this could be a child Component cdThisParent = this.getParent(); Component cdThatParent = that.getParent(); if (cdThisParent != null) { if (cdThatParent == null) { // other component is not a child ... so this child's global // super must derive from the other component in order for // this child to derive from the other component sThisName = getGlobalSuperName(); } else { // both components are children ... this child derives // from that child iff this child's name is the same as // that child's name and this child's parent derives // from that child's parent return this.getName().equals(that.getName()) && cdThisParent.isDerivedFrom(cdThatParent); } } // both sThisName and sThatName are fully qualified global names return sThisName.equals(sThatName) || sThisName.startsWith(sThatName + '.'); } /** * Get the default collator used for keeping identifiers unique etc. * * @return a case-insensitive collator based on the English character set */ protected static Collator getDefaultScriptingCollator() { Collator collator = Collator.getInstance(Locale.ENGLISH); // gg 2001.03.23 changed the PRIMARY strength to SECONDARY // since the PRIMARY strength collator ignores the white space // so strings "abc", "ab c" and "a b c" are considered equal collator.setStrength(Collator.SECONDARY); return new CacheCollator(collator); } // ----- unit test ------------------------------------------------------ /** * Output a given CDB file in binary or XML format to the opposite format. * * Usage: Component [CBD or XML input file] (output file) */ public static void main(String[] asArg) { int cArg = asArg.length; if (cArg < 1) { usage(); return; } File fileIn = new File(asArg[0]); if (!fileIn.isFile()) { usage(); return; } InputStream in = null; OutputStream out = null; try { // determine the input CDB format based upon the file extension boolean fBin = fileIn.getName().toLowerCase().endsWith(".cdb"); // create the input and output streams in = new FileInputStream(fileIn); if (cArg > 1) { File fileOut = new File(asArg[1]); if (fileOut.exists()) { err("Cannot overwrite existing file: " + fileOut); return; } out = new FileOutputStream(fileOut); } else { out = System.out; } // create the Component from the input stream Component cd = fBin ? new Component(new DataInputStream(in)) : new Component(XmlHelper.loadXml(in)); // output the Component to the oposite format if (fBin) { cd.dump(new PrintWriter(out, true), BLANK); } else { cd.save(new DataOutputStream(out)); } } catch (Exception e) { err("Error processing: " + fileIn); err(e); } finally { if (in != null) { try { in.close(); } catch (IOException e) {} } if (out != null) { try { out.close(); } catch (IOException e) {} } } } /** * Output command line usage. */ public static void usage() { out("Usage: Component [CBD or XML input file] (output file)"); } // ----- public constants ----------------------------------------------- /** * The Name attribute name. */ public static final String ATTR_NAME = "Name"; /** * The Visible attribute name. */ public static final String ATTR_VISIBLE = "Visible"; /** * The Static attribute name. */ public static final String ATTR_STATIC = "Static"; /** * The Abstract attribute name. */ public static final String ATTR_ABSTRACT = "Abstract"; /** * The Final attribute name. */ public static final String ATTR_FINAL = "Final"; /** * The Deprecated attribute name. */ public static final String ATTR_DEPRECATED = "Deprecated"; /** * The Persistent attribute name. */ public static final String ATTR_PERSISTENT = "Persistent"; /** * The Remote attribute name. */ public static final String ATTR_REMOTE = "Remote"; /** * The Integration attribute name. */ public static final String ATTR_INTEGRATION = "Integration"; /** * The Implements interface attribute name. */ public static final String ATTR_IMPLEMENTS = "Implements"; /** * The Dispatches event interface attribute name. */ public static final String ATTR_DISPATCHES = "Dispatches"; /** * The Property attribute name. */ public static final String ATTR_PROPERTY = "Property"; /** * The Behavior attribute name. */ public static final String ATTR_BEHAVIOR = "Behavior"; /** * The Category attribute name. */ public static final String ATTR_CATEGORY = "Category"; /** * The Child attribute name. */ public static final String ATTR_CHILD = "Child"; // ----- private constants ---------------------------------------------- /** * The name of this class. */ private static final String CLASS = "Component"; /** * The Component's descriptor string. */ protected static final String DESCRIPTOR_COMPONENT = CLASS; /** * Complex property's descriptor string. */ protected static final String DESCRIPTOR_COMPLEX = "Complex"; /** * Java Class Signature's descriptor string. */ protected static final String DESCRIPTOR_SIGNATURE = "Signature"; /** * Category: Component Definition */ protected static final int COMPONENT = 0; /** * Category: Complex Property value */ protected static final int COMPLEX = 1; /** * Category: Java Class Signature (JCS) */ protected static final int SIGNATURE = 2; /** * The descriptor strings indexed by the interface type. */ private String[] DESCRIPTORS = {DESCRIPTOR_COMPONENT, DESCRIPTOR_COMPLEX, DESCRIPTOR_SIGNATURE}; /** * The attributes that can affect class generation. */ private static final int CLASSGEN_FLAGS = ACCESS_MASK | // gg: 2002.09.17 commented out // VIS_MASK | // ANTIQ_MASK | SCOPE_MASK | IMPL_MASK | DERIVE_MASK | STG_MASK | DIST_MASK; /** * The default attribute values. */ private static final int DEFAULTS = ACCESS_PUBLIC | VIS_VISIBLE | SCOPE_INSTANCE | IMPL_CONCRETE | DERIVE_DERIVABLE | ANTIQ_CURRENT | STG_TRANSIENT | DIST_LOCAL; /** * Token representing a reachable base trait. * (Temporary used during resolve) */ private static final Object BASE_EXISTS = new Object(); /** * Token representing an unreachable base trait. * (Temporary used during resolve) */ private static final Object BASE_HIDDEN = new Object(); /** * Token representing a reserved base trait. * (Temporary used during resolve) */ private static final Object BASE_RESERVED = new Object(); /** * Token representing an insert trait at this level. * (Temporary used during resolve) */ private static final Object THIS_INSERT = new Object(); /** * Token representing an update trait at this level. * (Temporary used during resolve) */ private static final Object THIS_UPDATE = new Object(); // ----- data members --------------------------------------------------- /** * Components that are loaded from a persistent storage could have versions * that are older that the current one. The "equals()" operation always considers * the older versions of components as "not equal" to newer ones. * * Notes: immutable * * @see #equals(Object) */ private transient int m_nVersion = VERSION; /** * The Component class has several purposes: * 1. Component Definition * 2. Complex Property value * 3. Java Class Signature (JCS) * This field identifies which this Component instance is. * * Notes: immutable * * @see #COMPONENT * @see #COMPLEX * @see #SIGNATURE */ private int m_nType; /** * True if the component is read only. */ private transient boolean m_fReadOnly; /** * Component Definition/Complex: The global super Component name. * * Java Class Signature: The fully qualified class name which this * JCS extends. * * Notes: immutable */ private String m_sSuper = BLANK; /** * Component Definition/Complex: The Component's name. * * Java Class Signature: The fully qualified class name. * * Notes: immutable for global components */ private String m_sName; /** * Component Definition attribute: If this Component Definition is the * result of a modification, then m_fBaseLevel is false. Integration, * interface implementation, and interface dispatch cannot occur except * at the base level. * * Complex/Java Class Signature: Not used. */ private boolean m_fBaseLevel; /** * Component Definition attribute: The Component Definition may integrate * an "external" Java class, Javabean, CORBA interface, or other "model". * This is the trait which maps the integration to any integrated * Properties and Behaviors. * * Complex/Java Class Signature: Not used. */ private Integration m_integration; /** * Component Definition/Java Class Signature: The component implements * Java interfaces. The key of the string table is the interface name. * The corresponding value is the Interface which maps to any Behaviors. * * Complex: Not used. */ private StringTable m_tblImplements; /** * Component Definition attribute: The component may dispatch various * JavaBean events. The key of the string table is the interface name. * The value is the interface which maps to any dispatched Behaviors. * * Complex/Java Class Signature: Not used. */ private StringTable m_tblDispatches; /** * Component Definition/Complex/Java Class Signature: This Component * Definition has various attributes which are represented by bit flags: * Exists, Visible, Access (JCS only), Static, Abstract, Final, * Deprecation, Storage, and Distribution. * * @see com.tangosol.dev.component.Constants */ private int m_nFlags; /** * Component Definition/Complex: The legal ranges for this Component * Definition's attribute flags may be dependent on the super (in the case * of derivation) or base (in the case of modification) Component * Definition; those values are stored here for reference. * * Java Class Signature: Not used. */ private int m_nPrevFlags; /** * Component Definition/Complex: The declared and/or defined set of * component properties. * * Java Class Signature: Class fields (public/protected). */ private StringTable m_tblState; /** * Component Definition Behavior: The declared and/or defined set of * component behaviors. * * Complex: Not used. * * Java Class Signature: Class methods (public/protected). */ private StringTable m_tblBehavior; /** * Component Definition Aggregate Declaration section: The declared set * of aggregate categories. Each category is named and has an associated * Component type which specifies what components can be aggregated. The * associated value is a boolean true if the category was added at this * level. * * Complex/Java Class Signature: Not used. */ private StringTable m_tblCategories; /** * Component Definition Aggregate Definition section: The aggregated * Component Definitions, accessed by name. The associated value is the * child Component Definition instance. * * Complex/Java Class Signature: Not used. */ private StringTable m_tblChildren; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy