com.tangosol.dev.component.Component Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* 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;
}