com.tangosol.dev.component.Behavior 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.Method;
import com.tangosol.util.ClassHelper;
import com.tangosol.util.ErrorList;
import com.tangosol.util.StringTable;
import com.tangosol.util.UID;
import com.tangosol.util.ChainedEnumerator;
import com.tangosol.util.SimpleEnumerator;
import com.tangosol.run.xml.XmlElement;
import java.beans.PropertyVetoException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.CollationKey;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;
import java.util.List;
import java.util.Iterator;
/**
* A Behavior represents the set of information that describes a component's
* method or event handler declaration and definition.
*
* A Behavior and its contained hierarchy are kept or discarded as a unit.
* This allows any level that has any information specified at that level to
* recover the entire Behavior if the super/base level discards the Behavior.
*
* @version 0.50, 11/11/97
* @version 1.00, 08/17/98
* @author Cameron Purdy
*/
public class Behavior
extends Trait
{
// ----- construction ---------------------------------------------------
/**
* Construct a behavior. This is the "default" constructor.
*
* @param cd the containing Component Definition
* @param dtRet the return value's data type
* @param sName the name of the behavior
* @param fStatic the behavior's scope (static or instance)
* @param nAccess the behavior's accessibility
* @param adtParam the behavior's parameter data types
* @param asParam the parameter names (or null for defaults)
* @param anDir the parameter directions (or null for defaults)
*/
protected Behavior(Component cd,
DataType dtRet, String sName, boolean fStatic, int nAccess,
DataType[] adtParam, String[] asParam, int[] anDir)
{
super(cd, RESOLVED);
m_nFlags |= EXISTS_INSERT | nAccess | (fStatic ? SCOPE_STATIC : SCOPE_INSTANCE);
m_nPrevFlags |= EXISTS_NOT | ACCESS_PRIVATE | SCOPE_INSTANCE;
m_sName = sName;
m_retval = new ReturnValue(this, dtRet);
if (adtParam != null)
{
int c = adtParam.length;
for (int i = 0; i < c; ++i)
{
DataType dt = adtParam[i];
String sParam = (asParam == null ? "Param_" + i : asParam[i]);
int nDir = (anDir == null ? DIR_IN : anDir [i]);
Parameter param = new Parameter(this, dt, sParam, nDir);
m_vectParam.addElement(param);
}
}
updateSignature();
// all INSERT behaviors for non-Signatures are assigned UID's
if (!cd.isSignature())
{
assignUID();
}
}
/**
* Construct a Behavior for an integration method.
*
* @param cd containing Component
* @param map the Integration trait
* @param sName Behavior name that the method mapped to (allowing
* name collisions to be resolved)
* @param method interface method to integrate
*/
protected Behavior(Component cd, Integration map, String sName, Behavior method)
{
this(cd, method.m_retval.getDataType(), sName, method.isStatic(), method.getAccess(),
method.getParameterTypes(), method.getParameterNames(), null);
this.addOriginTrait(map);
// copy exceptions
for (Enumeration enmr = method.m_tblExcept.elements(); enmr.hasMoreElements(); )
{
Throwee except = (Throwee) enmr.nextElement();
Throwee throwee = new Throwee(this, except.getDataType());
throwee.addOriginTrait(map);
m_tblExcept.put(throwee.getUniqueName(), throwee);
}
}
/**
* Construct a Behavior for an interface (implements/dispatches) method.
*
* @param cd containing Component (or JCS)
* @param iface declaring interface
* @param method interface method
*/
protected Behavior(Component cd, Interface iface, Behavior method)
{
this(cd, method.m_retval.getDataType(), method.m_sName, method.isStatic(), method.getAccess(),
method.getParameterTypes(), method.getParameterNames(), null);
this.addOriginTrait(iface);
// for a JCS of an interface that implements an interface,
// the resulting methods are abstract unless it's a default method (Java 8)
if (cd.isInterface() && method.isAbstract())
{
m_nFlags = m_nFlags & ~IMPL_MASK | IMPL_ABSTRACT;
}
// copy exceptions
for (Enumeration enmr = method.m_tblExcept.elements(); enmr.hasMoreElements(); )
{
Throwee except = (Throwee) enmr.nextElement();
Throwee throwee = new Throwee(this, except.getDataType());
throwee.addOriginTrait(iface);
m_tblExcept.put(throwee.getUniqueName(), throwee);
}
}
/**
* Construct a Behavior for event registration.
*
* @param cd containing Component
* @param iface event interface
* @param sSig behavior signature
*/
protected Behavior(Component cd, Interface iface, String sSig)
{
this(cd, DataType.VOID, Interface.getDispatchesVerb(sSig) +
Interface.getDispatchesName(sSig) + "Listener", false,
ACCESS_PUBLIC, new DataType[] {DataType.getClassType(iface.getName())},
EVENT_REG_PARAM, null);
addOriginTrait(iface);
}
/**
* Construct a Java Class Signature (JCS) Behavior from a JASM method.
*
* @param cdJCS the containing JCS
* @param method the method object
* @param mapParam a Map that may contain String[] of param names per signature
*/
protected Behavior(Component cdJCS, Method method, Map mapParam)
{
super(cdJCS, RESOLVED);
// convert method information to Behavior flags
int nFlags = EXISTS_INSERT | DIST_LOCAL;
// access, visible
if (method.isPublic())
{
nFlags |= ACCESS_PUBLIC | VIS_VISIBLE;
}
else if (method.isProtected())
{
nFlags |= ACCESS_PROTECTED | VIS_VISIBLE;
}
else if (method.isPackage())
{
nFlags |= ACCESS_PACKAGE | VIS_VISIBLE;
}
else if (method.isPrivate())
{
nFlags |= ACCESS_PRIVATE | VIS_VISIBLE;
}
// mark synthetic methods as "advanced"
if (method.isSynthetic())
{
nFlags |= VIS_ADVANCED;
}
nFlags |= (method.isDeprecated() ? ANTIQ_DEPRECATED : ANTIQ_CURRENT );
nFlags |= (method.isStatic() ? SCOPE_STATIC : SCOPE_INSTANCE );
nFlags |= (method.isSynchronized() ? SYNC_MONITOR : SYNC_NOMONITOR );
nFlags |= (method.isAbstract() ? IMPL_ABSTRACT : IMPL_CONCRETE );
nFlags |= (method.isFinal() ? DERIVE_FINAL : DERIVE_DERIVABLE);
if (method.isBridge() && method.isSynthetic())
{
// use the ISINTERFACE bit for behaviors to indicate the generated
// nature of the method (generated by a compiler or tool)
nFlags |= MISC_ISINTERFACE;
}
// to allow modification of final JCS methods
// the last line has to be commented out
// initialize Behavior info
m_sName = method.getName();
m_nFlags = nFlags;
String[] asTypes = method.getTypes();
String[] asNames = method.getNames();
// Return Value
m_retval = new ReturnValue(this, DataType.getJVMType(asTypes[0]));
// Parameters
int cParams = asTypes.length - 1;
Vector vect = m_vectParam;
vect.setSize(cParams);
for (int i = 1; i <= cParams; ++i)
{
DataType dt = DataType.getJVMType(asTypes[i]);
String sName = "Param_" + i;
if (asNames[i] != null)
{
sName = asNames[i];
}
vect.setElementAt(new Parameter(this, dt, sName, DIR_IN), i - 1);
}
updateSignature();
// 2002-07-22 cp - fill in parameter names
if (!mapParam.isEmpty())
{
// look up the source code for the behavior
StringBuffer sb = new StringBuffer(getComponent().getName());
sb.append('.')
.append(getName())
.append('(');
DataType[] adt = getParameterTypes();
for (int i = 0, c = adt.length; i < c; ++i)
{
if (i > 0)
{
sb.append(',');
}
sb.append(Component.toSimpleSignature(adt[i].getType()));
}
sb.append(')');
String[] asParam = (String[]) mapParam.get(sb.toString());
if (asParam != null)
{
for (int i = 0, c = Math.min(asParam.length, getParameterCount()); i < c; ++i)
{
Parameter param = getParameter(i);
String sOldName = param.getName();
String sNewName = asParam[i];
if (sNewName != null && sNewName.length() > 0 && sOldName.startsWith("Param_"))
{
try
{
param.setName(sNewName, false);
}
catch (PropertyVetoException e)
{
}
}
}
}
}
// Exceptions
StringTable tbl = m_tblExcept;
for (Enumeration enmr = method.getExceptions(); enmr.hasMoreElements(); )
{
DataType dt = DataType.getClassType(((String) enmr.nextElement()).replace('/', '.'));
tbl.put(dt.getClassName(), new Throwee(this, dt));
}
}
/**
* Construct a blank Behavior Trait.
*
* @param base the base Behavior to derive from
* @param cd the containing Component
* @param nMode one of RESOLVED, DERIVATION, MODIFICATION
*
* @see #getBlankDerivedTrait(Trait, int)
*/
protected Behavior(Behavior base, Component cd, int nMode)
{
super(base, cd, nMode);
// only temporary; will be immediately resolved or extracted
// (don't bother creating blank params, return value, or exceptions)
this.m_sName = base.m_sName;
this.m_sSig = base.m_sSig;
this.m_nFlags = EXISTS_UPDATE;
}
/**
* Copy constructor.
*
* @param cd the Component containing the new Behavior
* @param that the Behavior to copy from
*/
protected Behavior(Component cd, Behavior that)
{
super(cd, that);
this.m_sName = that.m_sName;
this.m_sSig = that.m_sSig;
this.m_nFlags = that.m_nFlags;
this.m_nPrevFlags = that.m_nPrevFlags;
this.m_fOverrideBase = that.m_fOverrideBase;
this.m_fPrevOverrideBase = that.m_fPrevOverrideBase;
this.m_cBaseLevelImpl = that.m_cBaseLevelImpl;
this.m_retval = new ReturnValue(this, that.m_retval);
if (!that.m_vectParam.isEmpty())
{
Vector src = that.m_vectParam;
Vector dest = this.m_vectParam;
int c = src.size();
dest.setSize(c);
for (int i = 0; i < c; ++i)
{
dest.setElementAt(new Parameter(this, (Parameter) src.elementAt(i)), i);
}
}
if (!that.m_vectScript.isEmpty())
{
Vector src = that.m_vectScript;
Vector dest = this.m_vectScript;
int c = src.size();
dest.setSize(c);
for (int i = 0; i < c; ++i)
{
dest.setElementAt(new Implementation(this, (Implementation) src.elementAt(i)), i);
}
}
if (!that.m_tblExcept.isEmpty())
{
StringTable tblThat = that.m_tblExcept;
StringTable tblThis = this.m_tblExcept;
for (Enumeration enmr = tblThat.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
Throwee throwee = new Throwee(this, (Throwee) tblThat.get(sExcept));
if (cd.isSignature())
{
// TODO: explain why
throwee.addOriginTrait(cd);
}
tblThis.put(sExcept, throwee);
}
this.m_tblExcept = tblThis;
}
}
/**
* Construct the behavior from a stream.
*
* This is a custom serialization implementation that is unrelated to the
* Serializable interface and the Java implementation of persistence.
*
* @param cd the containing Component Definition
* @param stream the stream to read this Behavior from
* @param nVersion version of the data structure in the stream
*
* @exception IOException An IOException is thrown if an error occurs
* reading the Behavior information from the stream
*/
protected Behavior(Component cd, DataInput stream, int nVersion)
throws IOException
{
super(cd, stream, nVersion);
// name
m_sName = stream.readUTF();
// bit flags (various attributes)
m_nFlags = stream.readInt();
m_nPrevFlags = stream.readInt();
// return value trait
m_retval = new ReturnValue(this, stream, nVersion);
// parameter traits
int cParam = stream.readInt();
m_vectParam.setSize(cParam);
for (int i = 0; i < cParam; ++i)
{
Parameter param = new Parameter(this, stream, nVersion);
m_vectParam.setElementAt(param, i);
}
updateSignature();
// exception traits
int cExcept = stream.readInt();
for (int i = 0; i < cExcept; ++i)
{
Throwee except = new Throwee(this, stream, nVersion);
m_tblExcept.put(except.getUniqueName(), except);
}
// implementation traits
int cImpl = stream.readInt();
m_vectScript.setSize(cImpl);
for (int i = 0; i < cImpl; ++i)
{
Implementation impl = new Implementation(this, stream, nVersion);
m_vectScript.setElementAt(impl, i);
}
// override etc.
m_fOverrideBase = stream.readBoolean();
m_cBaseLevelImpl = stream.readInt();
}
/**
* 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 Behavior(Trait parent, XmlElement xml, int nVersion)
throws IOException
{
super(parent, xml, nVersion);
// name
String sName = readString(xml.getElement("name"));
if (sName == BLANK)
{
throw new IOException("name is missing");
}
m_sName = sName;
// bit flags (various attributes)
m_nFlags = readFlags(xml, "flags", 0);
m_nPrevFlags = readFlags(xml, "prev-flags", 0);
// return value trait
XmlElement xmlRetVal = xml.getElement("return-value");
if (xmlRetVal == null)
{
throw new IOException("return value is missing");
}
m_retval = new ReturnValue(this, xmlRetVal, nVersion);
// parameter traits
XmlElement xmlParams = xml.getElement("params");
if (xmlParams != null)
{
Vector vect = m_vectParam;
for (Iterator iter = xmlParams.getElements("param"); iter.hasNext(); )
{
XmlElement xmlParam = (XmlElement) iter.next();
Parameter param = new Parameter(this, xmlParam, nVersion);
vect.add(param);
}
}
updateSignature();
// exception traits
XmlElement xmlExcepts = xml.getElement("exceptions");
if (xmlExcepts != null)
{
StringTable tbl = m_tblExcept;
for (Iterator iter = xmlExcepts.getElements("exception"); iter.hasNext(); )
{
XmlElement xmlExcept = (XmlElement) iter.next();
Throwee except = new Throwee(this, xmlExcept, nVersion);
tbl.put(except.getUniqueName(), except);
}
}
// implementation traits
Vector vectScript = m_vectScript;
for (Iterator iter = xml.getElements("implementation"); iter.hasNext(); )
{
XmlElement xmlImpl = (XmlElement) iter.next();
Implementation impl = new Implementation(this, xmlImpl, nVersion);
vectScript.add(impl);
}
// override etc.
m_fOverrideBase = readBoolean(xml.getElement("override-base"));
m_cBaseLevelImpl = xml.ensureElement("base-implementations").getInt();
}
// ----- persistence ----------------------------------------------------
/**
* Save the Behavior to 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 write this behavior to
*
* @exception IOException An IOException is thrown if an error occurs
* writing the Behavior contents to the stream
*/
protected synchronized void save(DataOutput stream)
throws IOException
{
super.save(stream);
// name
stream.writeUTF(m_sName);
// bit flags (various attributes)
stream.writeInt(m_nFlags);
stream.writeInt(m_nPrevFlags);
// return value trait
m_retval.save(stream);
// parameter traits
int cParam = m_vectParam.size();
stream.writeInt(cParam);
for (int i = 0; i < cParam; ++i)
{
((Parameter) m_vectParam.elementAt(i)).save(stream);
}
// exception traits
int cExcept = m_tblExcept.getSize();
stream.writeInt(cExcept);
Enumeration enmrExcept = m_tblExcept.elements();
for (int i = 0; i < cExcept; ++i)
{
((Throwee) enmrExcept.nextElement()).save(stream);
}
// implementation traits
int cImpl = m_vectScript.size() - m_cBaseLevelImpl;
stream.writeInt(cImpl);
for (int i = 0; i < cImpl; ++i)
{
((Implementation) m_vectScript.elementAt(i)).save(stream);
}
// override etc.
stream.writeBoolean(m_fOverrideBase);
stream.writeInt(m_cBaseLevelImpl);
}
/**
* Save the Trait information to XML. If derived traits have any
* data of their own, then they must implement (i.e. supplement) this
* method.
*
* This is a custom serialization implementation that is unrelated to the
* Serializable interface and the Java implementation of persistence.
*
* @param xml an XmlElement to write the persistent information to
*
* @throws IOException if an exception occurs saving the trait data
*/
protected synchronized void save(XmlElement xml)
throws IOException
{
// name
xml.addElement("name").setString(m_sName);
super.save(xml);
// bit flags (various attributes)
saveFlags(xml, "flags", m_nFlags, 0);
saveFlags(xml, "prev-flags", m_nPrevFlags, 0);
// REVIEW: jhowes 2007.10.18:
// Added a human-readable description attribute to the flags elements
XmlElement xmlFlags = xml.getElement("flags");
if (xmlFlags != null)
{
xmlFlags.addAttribute("desc").setString(flagsDescription(m_nFlags,
ACCESS_SPECIFIED | SCOPE_SPECIFIED | SYNC_SPECIFIED, false));
}
xmlFlags = xml.getElement("prev-flags");
if (xmlFlags != null)
{
xmlFlags.addAttribute("desc").setString(flagsDescription(m_nPrevFlags,
ACCESS_SPECIFIED | SCOPE_SPECIFIED | SYNC_SPECIFIED, false));
}
// return value trait
m_retval.save(xml.addElement("return-value"));
// parameter traits
List list = m_vectParam;
if (list != null && !list.isEmpty())
{
XmlElement xmlParams = xml.addElement("params");
for (Iterator iter = list.iterator(); iter.hasNext(); )
{
((Parameter) iter.next()).save(xmlParams.addElement("param"));
}
}
// exception traits
saveTable(xml, m_tblExcept, "exceptions", "exception");
// implementation traits
int cImpl = m_vectScript.size() - m_cBaseLevelImpl;
if (cImpl > 0)
{
for (int i = 0; i < cImpl; ++i)
{
// expect only one, so don't nest them; however, any number
// is supported
((Implementation) m_vectScript.elementAt(i)).save(xml.addElement("implementation"));
}
}
// override etc.
if (m_fOverrideBase)
{
xml.addElement("override-base").setBoolean(true);
}
if (m_cBaseLevelImpl != 0)
{
xml.addElement("base-implementations").setInt(m_cBaseLevelImpl);
}
}
// ----- derivation/modification ----------------------------------------
/**
* Construct a blank Behavior from this base.
*
* @param parent the containing Component
* @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)
{
Behavior beh = new Behavior(this, (Component) parent, nMode);
// for signature, create blank derived traits for exceptions
// (see special processing in resolve() for exceptions on signature
// behaviors)
if (getComponent().isSignature() && !m_tblExcept.isEmpty())
{
StringTable tblExcept = (StringTable) m_tblExcept.clone();
for (Enumeration enmr = tblExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
Throwee throwee = (Throwee) tblExcept.get(sExcept);
tblExcept.put(sExcept, throwee.getBlankDerivedTrait(this, nMode));
}
beh.m_tblExcept = tblExcept;
}
return beh;
}
/**
* 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.
*
* Note: resolve must be invoked with a null derivation when the base
* behavior is final
*
* @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
{
Behavior base = this;
Behavior delta = (Behavior) resolveDelta(traitDelta, loader, errlist);
Behavior derived = (Behavior) super.resolve(delta, parent, loader, errlist);
// for general use below
boolean fSignature = base.getComponent().isSignature();
// verify that behavior attributes match
delta.verifyMatch(base, true, errlist);
// if the base is resolved, this will be resolved when resolve
// completes (otherwise it will be a derivation/modification)
int nBaseMode = base .getMode();
boolean fBaseResolved = (nBaseMode == RESOLVED);
int nDeltaMode = delta.getMode();
if (nDeltaMode == RESOLVED)
{
// this can happen when the Behavior is an INSERT with the
// same name as a Behavior later added to the base
nDeltaMode = delta.getExtractMode(base);
}
// 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
// if delta is a modification of an insert, then keep it as an insert
int nExists = EXISTS_UPDATE;
if (nDeltaMode == MODIFICATION && (nBaseFlags & EXISTS_MASK) == EXISTS_INSERT)
{
nExists = EXISTS_INSERT;
}
// gg: 2003.11.24 Behavior is EXISTS_NOT if the method is not present
// in the class represented by the JCS.
if (fSignature && (nDeltaFlags & EXISTS_MASK) == EXISTS_NOT)
{
nExists = EXISTS_NOT;
}
nDerivedFlags = nDerivedFlags & ~EXISTS_FULLMASK | nExists;
// behavior attributes
derived.m_sName = base.m_sName;
derived.m_nFlags = nDerivedFlags;
derived.m_nPrevFlags = nPrevFlags;
// return value
ReturnValue retBase = base.m_retval;
ReturnValue retDelta = delta.m_retval;
if (retDelta == null)
{
retDelta = (ReturnValue) retBase.getNullDerivedTrait(delta, nDeltaMode);
}
derived.m_retval = (ReturnValue) retBase.resolve(retDelta, derived, loader, errlist);
// parameters
Vector vectBaseParam = base.m_vectParam;
Vector vectDeltaParam = delta.matchParameters(base, true, errlist);
Vector vectDerivedParam = derived.m_vectParam;
int cParam = vectBaseParam.size();
vectDerivedParam.setSize(cParam);
for (int i = 0; i < cParam; ++i)
{
Parameter paramBase = (Parameter) vectBaseParam .get(i);
Parameter paramDelta = (Parameter) vectDeltaParam.get(i);
if (paramDelta == null)
{
paramDelta = (Parameter) paramBase.getNullDerivedTrait(delta, nDeltaMode);
}
vectDerivedParam.set(i, paramBase.resolve(paramDelta, derived, loader, errlist));
}
updateSignature();
// exceptions (note: delta exceptions may be a superset of base)
StringTable tblBaseExcept = base.m_tblExcept;
StringTable tblDeltaExcept = delta.matchExceptions(base, true, errlist);
StringTable tblDerivedExcept = derived.m_tblExcept; // empty
for (Enumeration enmr = tblDeltaExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
Throwee exceptBase = (Throwee) tblBaseExcept .get(sExcept);
Throwee exceptDelta = (Throwee) tblDeltaExcept.get(sExcept);
Throwee exceptDerived = null;
if (exceptBase == null)
{
// just copy exception information (nothing to apply it to)
exceptDerived = new Throwee(derived, exceptDelta);
// if the base is resolved, the derived exception must be
// marked as deleted (see matchExceptions)
if (fBaseResolved)
{
nExists = exceptDerived.getExists();
if (nExists == EXISTS_INSERT)
{
// originated at this level, so mark as removed at this
// level
exceptDerived.setExists(EXISTS_DELETE);
}
else if (nExists == EXISTS_UPDATE)
{
// not originated at this level
exceptDerived.setExists(EXISTS_NOT);
}
}
}
else
{
if (exceptDelta == null)
{
if (fSignature && nDeltaMode == DERIVATION)
{
// the sub-class declared the method without the
// exception, implying that the exception has been
// removed; this occurs only with signatures because
// Java classes do not store exception declarations
// as a delta from the super, rather they store the
// list in its fully resolved form
exceptDerived = new Throwee(derived, exceptBase);
exceptDerived.setExists(EXISTS_DELETE);
}
else
{
// create a null derivation if no delta exists
exceptDelta = (Throwee) exceptBase.getNullDerivedTrait(delta, nDeltaMode);
}
}
// apply the delta
if (exceptDelta != null)
{
exceptDerived = (Throwee) exceptBase.resolve(exceptDelta, derived, loader, errlist);
}
}
tblDerivedExcept.put(sExcept, exceptDerived);
}
// implementations
Vector vectBaseScript = base.m_vectScript;
Vector vectDeltaScript = delta.m_vectScript;
Vector vectDerivedScript = derived.m_vectScript; // empty
// copy the delta implementations to the derived behavior
int cScripts = vectDeltaScript.size();
vectDerivedScript.setSize(cScripts);
for (int i = 0; i < cScripts; ++i)
{
Implementation script = (Implementation) vectDeltaScript.get(i);
vectDerivedScript.set(i, new Implementation(derived, script));
}
// if the delta is a modification, that means that some of the
// implementations may have come from a base of the delta (i.e. the
// delta itself may be a result of resolve processing)
if (nDeltaMode == MODIFICATION && !delta.m_fPrevOverrideBase)
{
// determine the number of scripts on the base
int cBaseImpl = vectBaseScript.size();
// if the base overrode its base then only keep the reachable
// base scripts
if (base.m_fOverrideBase)
{
cBaseImpl -= base.m_cBaseLevelImpl;
}
// get the base scripts
for (int i = 0; i < cBaseImpl; ++i)
{
Implementation scriptBase = (Implementation) vectBaseScript.get(i);
Implementation scriptDelta = (Implementation) scriptBase.getNullDerivedTrait(delta, MODIFICATION);
Implementation scriptDerived = (Implementation) scriptBase.resolve(scriptDelta, derived, loader, errlist);
vectDerivedScript.addElement(scriptDerived);
}
derived.m_cBaseLevelImpl = delta.m_cBaseLevelImpl + cBaseImpl;
derived.m_fOverrideBase = delta.m_fOverrideBase;
derived.m_fPrevOverrideBase = base.m_fOverrideBase || base.m_fPrevOverrideBase;
}
else
{
derived.m_cBaseLevelImpl = delta.m_cBaseLevelImpl;
derived.m_fOverrideBase = delta.m_fOverrideBase;
derived.m_fPrevOverrideBase = delta.m_fPrevOverrideBase;
}
return derived;
}
/**
* Resolve delta in flags.
*
* implementation note: a flag value is always meaningful if the
* behavior 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 = getComponent().isSignature();
// derived flags always start as the base flags; then the delta flags
// are applied
int nDerivedFlags = nBaseFlags;
// optimization: check for nothing specified
if (!fSignature && 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;
}
// the access attribute is one-way: private to protected to public
if (fSignature || (nDeltaFlags & ACCESS_SPECIFIED) != 0)
{
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_PACKAGE:
// from package to protected is legal (for JCSs only)
if (nDeltaAccess == ACCESS_PROTECTED)
{
break;
}
// no 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 synchronized attribute is flexible
if (fSignature || (nDeltaFlags & SYNC_SPECIFIED) != 0)
{
nDerivedFlags = nDerivedFlags & ~SYNC_FULLMASK | nDeltaFlags & SYNC_FULLMASK;
}
// the scope attribute is never overridden (a Behavior cannot change
// from static to instance or vice versa due to a derivation)
// the abstract attribute is flexible
if ((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 distribution (remote) attribute is one-way, and is specifiable
// only for Behaviors on global remote Components
if ((nDeltaFlags & DIST_SPECIFIED) != 0
&& (nDeltaFlags & DIST_MASK) == DIST_REMOTE)
{
// only process if base is not already remote
if (!((fBaseResolved || (nBaseFlags & DIST_SPECIFIED) != 0)
&& (nBaseFlags & DIST_MASK) == DIST_REMOTE))
{
// remote behaviors only on global remote Components
Component cd = getComponent();
if (cd.isGlobal() && (cd.getMode() != RESOLVED || cd.isRemote()))
{
// determine accessibility of the method
boolean fPublic = (nDerivedFlags & ACCESS_MASK) == ACCESS_PUBLIC;
if (!fBaseResolved && (nDerivedFlags & ACCESS_SPECIFIED) == 0)
{
// if no access information is available, assume public
// until a resolve occurs in which information is available
fPublic = true;
}
// 2001.05.08 cp allow static behaviors to be remote in order to
// support ejb home design using static methods
/*
// determine scope of the behavior
boolean fInstance = (nDerivedFlags & SCOPE_MASK) == SCOPE_INSTANCE;
if (!fBaseResolved && (nDerivedFlags & SCOPE_SPECIFIED) == 0)
{
// if no scope information is available, assume instance
// until a resolve occurs in which information is available
fInstance = true;
}
// only allow remote to be set if behavior is non-static and public
if (fPublic && fInstance)
*/
if (fPublic)
{
nDerivedFlags = nDerivedFlags & ~DIST_FULLMASK | nDeltaFlags & DIST_FULLMASK;
}
}
}
}
return nDerivedFlags;
}
/**
* Complete the resolve processing for this Behavior and its sub-traits,
* discarding any Behavior Exceptions that have no origin.
*
* @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
*/
protected 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;
// discard transient (resolve only) data
m_fPrevOverrideBase = false;
// resolve sub-traits: return value
m_retval.finalizeResolve(loader, errlist);
// resolve sub-traits: parameters
int c = m_vectParam.size();
for (int i = 0; i < c; ++i)
{
((Parameter) m_vectParam.elementAt(i)).finalizeResolve(loader, errlist);
}
// resolve sub-traits: exceptions
if (!m_tblExcept.isEmpty())
{
for (Enumeration enmr = m_tblExcept.elements(); enmr.hasMoreElements(); )
{
Throwee except = (Throwee) enmr.nextElement();
except.finalizeResolve(loader, errlist);
// discard un-needed exceptions
if (except.isDiscardable())
{
m_tblExcept.remove(except.getUniqueName());
except.invalidate();
}
}
}
}
/**
* 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
{
Behavior derived = this;
Behavior base = (Behavior) traitBase;
Behavior delta = (Behavior) super.extract(base, parent, loader, errlist);
// for general use below
boolean fSignature = getComponent().isSignature();
// verify that behavior attributes match
derived.verifyMatch(base, false, 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();
// 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;
// exists (always update for Behavior)
nDeltaFlags = nDeltaFlags & ~EXISTS_FULLMASK | EXISTS_UPDATE;
// visible
if ((nDifFlags & VIS_MASK) != 0 &&
(fBaseResolved || (nBaseFlags & VIS_SPECIFIED) != 0))
{
nDeltaFlags |= VIS_SPECIFIED;
}
// access
if ((nDifFlags & ACCESS_MASK) != 0 &&
(fBaseResolved || (nBaseFlags & ACCESS_SPECIFIED) != 0))
{
nDeltaFlags |= ACCESS_SPECIFIED;
}
// synchronized
if ((nDifFlags & SYNC_MASK) != 0 &&
(fBaseResolved || (nBaseFlags & SYNC_SPECIFIED) != 0))
{
nDeltaFlags |= SYNC_SPECIFIED;
}
// scope is not specifiable
// 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;
}
// distribution
if ((nDifFlags & DIST_MASK) != 0 &&
(fBaseResolved || (nBaseFlags & DIST_SPECIFIED) != 0))
{
nDeltaFlags |= DIST_SPECIFIED;
}
// behavior attributes
delta.m_sName = base.m_sName;
delta.m_nFlags = nDeltaFlags;
delta.m_nPrevFlags = 0;
// extract sub-trait: return value
delta.m_retval = (ReturnValue) derived.m_retval.extract(
base.m_retval, delta, loader, errlist);
// extract sub-traits: parameters
Vector vectBaseParam = base.m_vectParam;
Vector vectDerivedParam = derived.matchParameters(base, false, errlist);
Vector vectDeltaParam = delta.m_vectParam;
int cParam = vectBaseParam.size();
vectDeltaParam.setSize(cParam);
for (int i = 0; i < cParam; ++i)
{
Parameter paramBase = (Parameter) vectBaseParam .get(i);
Parameter paramDerived = (Parameter) vectDerivedParam.get(i);
Parameter paramDelta;
// derived parameter is null to imply a resulting null derivation
if (paramDerived == null)
{
paramDelta = (Parameter) paramBase.getNullDerivedTrait(delta, nDeltaMode);
}
else
{
paramDelta = (Parameter) paramDerived.extract(
paramBase, delta, loader, errlist);
}
vectDeltaParam.set(i, paramDelta);
}
delta.updateSignature();
// extract sub-traits: exceptions
// (note: derived exceptions may be a superset of base)
StringTable tblBaseExcept = base.m_tblExcept;
StringTable tblDerivedExcept = derived.matchExceptions(base, false, errlist);
StringTable tblDeltaExcept = delta.m_tblExcept; // empty
for (Enumeration enmr = tblDerivedExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
Throwee exceptBase = (Throwee) tblBaseExcept .get(sExcept);
Throwee exceptDerived = (Throwee) tblDerivedExcept.get(sExcept);
Throwee exceptDelta = null;
if (exceptBase == null)
{
// just copy derived exception information (nothing to extract)
exceptDelta = new Throwee(delta, exceptDerived);
}
else
{
if (fSignature && exceptDerived == null)
{
// the super method has an exception type that is not on
// the derived method, meaning it has been deleted, so at
// this point reconstruct the "deleted derived" exception
exceptDerived = (Throwee) exceptBase.resolve(
exceptBase.getNullDerivedTrait(delta, nDeltaMode), derived, loader, errlist);
exceptDerived.setExists(EXISTS_DELETE);
}
if (exceptDerived != null)
{
// extract the delta
exceptDelta = (Throwee) exceptDerived.extract(exceptBase, delta, loader, errlist);
}
}
if (exceptDelta != null)
{
tblDeltaExcept.put(sExcept, exceptDelta);
}
}
// extract sub-traits: implementations
Vector vectBaseScripts = base .m_vectScript;
Vector vectDerivedScripts = derived.m_vectScript;
Vector vectDeltaScripts = delta .m_vectScript; // empty
// delta keeps only reachable implementations from derived
int cScripts = vectDerivedScripts.size();
if (cScripts > 0)
{
// the JCS implementations are not actually there; they are used only
// for display in the tools
if (isJcsImplementation(cScripts - 1))
{
cScripts--;
}
if (derived.m_fOverrideBase)
{
cScripts -= derived.m_cBaseLevelImpl;
}
}
delta.m_fOverrideBase = derived.m_fOverrideBase;
delta.m_cBaseLevelImpl = nDeltaMode == DERIVATION ? derived.m_cBaseLevelImpl : 0;
// deltas are never extracted for implementations; they are either
// stored resolved (whole) or are discarded
Script: for (int i = 0; i < cScripts; ++i)
{
Implementation script = (Implementation) vectDerivedScripts.get(i);
if (nDeltaMode == MODIFICATION)
{
int cBaseScripts = vectBaseScripts.size();
for (int iBase = 0; iBase < cBaseScripts; ++iBase)
{
if (script.equalsUID((Implementation)vectBaseScripts.get(iBase)))
{
// this script belongs to the base; don't copy any
// more scripts to the delta
break Script;
}
}
}
vectDeltaScripts.add(new Implementation(delta, script));
}
return delta;
}
/**
* Complete the extract processing for this Behavior 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
*/
protected synchronized void finalizeExtract(Loader loader, ErrorList errlist)
throws ComponentException
{
super.finalizeExtract(loader, errlist);
// for general use below
boolean fSignature = getComponent().isSignature();
// finalize sub-trait: return value
m_retval.finalizeExtract(loader, errlist);
// finalize sub-traits: parameters
int c = m_vectParam.size();
for (int i = 0; i < c; ++i)
{
((Parameter) m_vectParam.get(i)).finalizeExtract(loader, errlist);
}
// finalize sub-traits: exceptions
if (!m_tblExcept.isEmpty())
{
for (Enumeration enmr = m_tblExcept.elements(); enmr.hasMoreElements(); )
{
Throwee except = (Throwee) enmr.nextElement();
except.finalizeExtract(loader, errlist);
// check if the exception is discardable
// (don't discard exceptions for signature methods: see the
// special resolve processing for signatures)
if (!fSignature && except.isDiscardable())
{
m_tblExcept.remove(except.getUniqueName());
except.invalidate();
}
}
}
// 2001.05.23 cp this will break roll-up but will fix JCSs
Vector vectScript = m_vectScript;
int cScripts = vectScript.size();
while (cScripts > 0 &&
!((Implementation) vectScript.get(cScripts - 1)).isDeclaredAtThisLevel())
{
vectScript.remove(--cScripts);
}
m_cBaseLevelImpl = 0;
}
/**
* Check for illegal mismatches between the base and this behavior.
*
* (Neither the base nor this behavior are modified by this method.)
*
* @param base the super or base level's Behavior object
* @param fResolve true if being RESOLVED
* @param errlist the error list to log any mismatches to
*
* @exception DerivationException
*/
protected void verifyMatch(Behavior base, boolean fResolve, ErrorList errlist)
throws DerivationException
{
// check for name mismatch
if (!this.m_sName.equals(base.m_sName))
{
String sCode = (fResolve ? RESOLVE_BEHAVIORNAMECHANGE
: EXTRACT_BEHAVIORNAMECHANGE);
Object[] aoParam = new Object[]
{
this.m_sName,
base.m_sName,
toPathString()
};
logError(sCode, WARNING, aoParam, errlist);
}
}
/**
* Match up the parameters from the base and this behavior. Return a
* Vector of parameters to resolve or extract from the base. The returned
* vector must not be modified.
*
* The returned vector may have null values which imply null derivations.
*
* (Neither the base nor this behavior are modified by this method.)
*
* @param base the super or base level's Behavior object
* @param fResolve true if being RESOLVED
* @param errlist the error list to log any mismatches to
*
* @exception DerivationException
*/
protected Vector matchParameters(Behavior base, boolean fResolve, ErrorList errlist)
throws DerivationException
{
// get behavior parameters
Vector vectThisParam = this.m_vectParam;
Vector vectBaseParam = base.m_vectParam;
int cThisParam = vectThisParam.size();
int cBaseParam = vectBaseParam.size();
if (cThisParam == cBaseParam)
{
boolean fMatch = true;
if (!this.getComponent().isSignature())
{
for (int i = 0; i < cBaseParam; ++i)
{
Parameter pBase = (Parameter) vectBaseParam.get(i);
Parameter pThis = (Parameter) vectThisParam.get(i);
if (pThis.getUID() == null || !pThis.equalsUID(pBase))
{
fMatch = false;
break;
}
}
}
// most common: parameters match
if (fMatch)
{
return vectThisParam;
}
}
// if parameters didn't match, create a new vector which does match
// by adding, removing, and re-arranging parameters; this is assumed
// to happen rarely
Vector vectResultParam = new Vector(cBaseParam);
vectResultParam.setSize(cBaseParam);
// null derivations have no parameters in the delta to match
if (cThisParam == 0)
{
return vectResultParam;
}
// build look up tables by UID and name
Hashtable tblParamByUID = new Hashtable(cBaseParam);
StringTable tblParamByName = new StringTable(INSENS);
for (int i = 0; i < cThisParam; ++i)
{
Parameter paramThis = (Parameter) vectThisParam.get(i);
UID uid = paramThis.getUID();
if (uid != null)
{
tblParamByUID .put(paramThis.getUID (), paramThis);
}
tblParamByName.put(paramThis.getUniqueName(), paramThis);
}
// look up parameters by UID; remove each one found from the name
// look up table
if (!tblParamByUID.isEmpty())
{
for (int i = 0; i < cBaseParam; ++i)
{
Parameter paramBase = (Parameter) vectBaseParam.get(i);
UID uid = paramBase.getUID();
if (uid != null)
{
Parameter paramThis = (Parameter) tblParamByUID.get(uid);
if (paramThis != null)
{
vectResultParam.set(i, paramThis);
tblParamByName.remove(paramThis.getUniqueName());
}
}
}
}
// fill in missing parameters by looking up by name; failing that
// assume "null" derived traits
for (int i = 0; i < cBaseParam; ++i)
{
if (vectResultParam.get(i) == null)
{
Parameter paramBase = (Parameter) vectBaseParam.get(i);
Parameter paramThis = (Parameter) tblParamByName.get(paramBase.getUniqueName());
if (paramThis != null)
{
vectResultParam.set(i, paramThis);
// only leave unmatched parameters in tblParamByName
// (so they can be discarded)
tblParamByName.remove(paramThis.getUniqueName());
}
}
}
// discard remaining parameters
for (Enumeration enmr = tblParamByName.elements(); enmr.hasMoreElements(); )
{
Parameter param = (Parameter) enmr.nextElement();
String sCode = (fResolve ? RESOLVE_PARAMETERDISCARDED
: EXTRACT_PARAMETERDISCARDED);
Object[] aoParam = new Object[]
{
param.getName(),
base.m_sSig,
toPathString()
};
logError(sCode, WARNING, aoParam, errlist);
}
return vectResultParam;
}
/**
* Match up the exceptions from the base and this behavior. Return a
* StringTable of exceptions 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 exceptions. Although the Java
* Language Specification (8.4.4) states that there cannot be any
* additional exceptions, it is possible that exception information was
* added by an interface (for example) although such an exception will be
* automatically marked as "deleted".
*
* (Neither the base nor this behavior are modified by this method.)
*
* @param base the super or base level's Behavior object
* @param fResolve true if being RESOLVED
* @param errlist the error list to log any mismatches to
*
* @exception DerivationException
*/
protected StringTable matchExceptions(Behavior base, boolean fResolve, ErrorList errlist)
throws DerivationException
{
StringTable tblThis = this.m_tblExcept;
StringTable tblBase = base.m_tblExcept;
StringTable tblResult = tblThis;
// most common case overall: behavior has no declared exceptions
// most common case for extract: exact match
if (tblThis.keysEquals(tblBase))
{
return tblResult;
}
// most common for resolve: no exception information in the delta
if (tblThis.isEmpty())
{
// copy keys from base (but leave exception traits 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 exceptions (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(); )
{
Throwee except = (Throwee) enmr.nextElement();
UID uid = except.getUID();
if (uid != null)
{
tblByUID.put(uid, except);
}
tblByName.put(except.getUniqueName(), except);
}
// look up by UID; remove each one found from the name look up table
if (!tblByUID.isEmpty())
{
for (Enumeration enmr = tblBase.elements(); enmr.hasMoreElements(); )
{
Throwee exceptBase = (Throwee) enmr.nextElement();
UID uid = exceptBase.getUID();
if (uid != null)
{
Throwee exceptThis = (Throwee) tblByUID.get(uid);
if (exceptThis != null)
{
tblResult.put(exceptBase.getUniqueName(), exceptThis);
tblByName.remove(exceptThis.getUniqueName());
}
}
}
}
// look up by name
for (Enumeration enmr = tblBase.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (!tblResult.contains(sExcept))
{
// find the exception on this behavior with the same name;
// whether or not one exists, reserve the name in the result
Throwee except = (Throwee) tblByName.get(sExcept);
tblResult.put(sExcept, except);
// only leave unmatched exceptions in tblByName
// (so they can be added to the results or discarded)
if (except != null)
{
tblByName.remove(sExcept);
}
}
}
// keep additional exceptions (but discard any conflicting ones)
for (Enumeration enmr = tblByName.elements(); enmr.hasMoreElements(); )
{
Throwee except = (Throwee) enmr.nextElement();
String sExcept = except.getUniqueName();
// check for conflict (this happens when a base exception is
// renamed which conflicts if another exception was added at
// this level and coincidentally has the same name)
if (tblResult.contains(sExcept))
{
String sCode = (fResolve ? RESOLVE_EXCEPTIONDISCARDED
: EXTRACT_EXCEPTIONDISCARDED);
Object[] aoParam = new Object[]
{
except.getUniqueName(),
base.m_sSig,
toPathString()
};
logError(sCode, WARNING, aoParam, errlist);
}
else
{
tblResult.put(sExcept, except);
}
}
return tblResult;
}
/**
* 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)
{
Behavior that = (Behavior) base;
if (that == null || !isFromSuper())
{
return false;
}
// attributes
if (((this.m_nFlags ^ that.m_nFlags) & CLASSGEN_FLAGS) != 0)
{
return false;
}
// return value
if (!this.m_retval.isClassDiscardable(that.m_retval))
{
return false;
}
// parameters
Vector vectParamThis = this.m_vectParam;
Vector vectParamThat = that.m_vectParam;
for (int i = 0, c = vectParamThis.size(); i < c; ++i)
{
Parameter paramThis = (Parameter) vectParamThis.get(i);
Parameter paramThat = (Parameter) vectParamThat.get(i);
if (!paramThis.isClassDiscardable(paramThat))
{
return false;
}
}
// exceptions
if (!isClassDiscardableFromSubtraitTable(this.m_tblExcept, that.m_tblExcept))
{
return false;
}
// there must be no implementations
if (this.m_vectScript.size() != (this.m_fOverrideBase ? this.m_cBaseLevelImpl : 0))
{
return false;
}
return super.isClassDiscardable(base);
}
// ----- miscellaneous Trait methods ------------------------------------
/**
* Determine if the Behavior is modifiable. Behaviors that modify or
* derive from final behaviors are not modifiable.
*
* @return true if the Trait is modifiable, false otherwise
*/
public boolean isModifiable()
{
if ((m_nPrevFlags & DERIVE_MASK) == DERIVE_FINAL)
{
return false;
}
// gg: 2001.7.18 JCS constructors are not designable for now
if (getComponent().isSignature() && getName().indexOf('<') != -1)
{
return false;
}
return super.isModifiable();
}
/**
* Determines if this Behavior exists for any reason at all. If a
* Behavior exists, for example, as part of an interface, and the
* interface changes, removing the Behavior, then the Behavior will be
* discarded as part of the Component's resolve finalization processing.
*
* @return true if the Behavior is discardable
*/
protected boolean isDiscardable()
{
switch (getMode())
{
case RESOLVED:
{
// Don't discard Java Class Signature Behaviors
if (((Component) getParentTrait()).isSignature())
{
return false;
}
break;
}
case DERIVATION:
case MODIFICATION:
{
// check for delta information
if ((m_nFlags & ALL_SPECIFIED) != 0 || m_fOverrideBase)
{
return false;
}
break;
}
}
return super.isDiscardable();
}
/**
* Determine all traits contained by this behavior.
*
* @return the an enumeration of traits contained by this trait
*/
protected Enumeration getSubTraits()
{
ChainedEnumerator enmr = new ChainedEnumerator();
enmr.addEnumeration(new SimpleEnumerator(new Object[] {m_retval}));
enmr.addEnumeration(m_vectParam.elements());
enmr.addEnumeration(m_tblExcept.elements());
enmr.addEnumeration(m_vectScript.elements());
return enmr;
}
/**
* Reset state, discarding all information.
*/
protected synchronized void invalidate()
{
super.invalidate();
m_sName = null;
m_sSig = null;
m_retval = null;
m_vectParam = null;
m_tblExcept = null;
m_vectScript = null;
}
/**
* Determine the unique name for this trait.
*
* A sub-trait that exists within a collection of sub-traits must have
* two ways of being identified:
*
* 1) A unique name, which is a string identifier
* 2) A UID as a secondary identifier (dog tag)
*
* @return the primary string identifier of the trait
*/
protected String getUniqueName()
{
// note: unique name _can_ change but not behavior is not used as a
// trait origin for other traits
return m_sSig;
}
/**
* 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 DESCRIPTOR + ' ' + getUniqueName();
}
// ----- accessors ------------------------------------------------------
/**
* Determine the component which contains this behavior.
*
* @return the Component Definition that contains this behavior or null
* if this behavior is not part of a component
*/
public Component getComponent()
{
return (Component) getParentTrait();
}
// ----- Signature
/**
* Build a behavior signature from a behavior name and parameter types.
*
* @param sName the name of the behavior
* @param adtParam the behavior's parameter data types
*
* @return the behavior signature built from the passed information
*/
public static String getSignature(String sName, DataType[] adtParam)
{
return getSignature(sName, adtParam, 0);
}
/**
* Build a behavior signature from a behavior name and parameter types.
*
* @param sName the name of the behavior
* @param adtParam the behavior's parameter data types
* @param iFirst the index of the first parameter in the array
*
* @return the behavior signature built from the passed information
*/
public static String getSignature(String sName, DataType[] adtParam, int iFirst)
{
StringBuffer sb = new StringBuffer();
sb.append(sName)
.append('(');
int cParam = (adtParam != null ? adtParam.length : 0);
for (int i = iFirst; i < cParam; ++i)
{
sb.append(adtParam[i].getTypeString());
}
sb.append(')');
return sb.toString();
}
/**
* Get the signature for the behavior. The signature uniquely identifies
* the behavior.
*
* @return the signature for the behavior
*/
public String getSignature()
{
return m_sSig;
}
/**
* Update the signature for the behavior. This method is called
* internally when the behavior or a sub-trait of the behavior is
* changed in such a way that the behavior signature is changed.
*/
protected void updateSignature()
{
// get old signature (could be null if this has been called to ensure
// that the signature is cached)
String sOldSig = m_sSig;
// get new signature
StringBuffer sb = new StringBuffer();
sb.append(m_sName)
.append('(');
int c = getParameterCount();
for (int i = 0; i < c; ++i)
{
sb.append(getParameter(i).getSignature());
}
sb.append(')');
String sNewSig = sb.toString();
if (!sNewSig.equals(sOldSig))
{
// store new signature
m_sSig = sNewSig;
// update component's list of behaviors
if (sOldSig != null)
{
getComponent().renameBehavior(sOldSig, sNewSig);
}
}
}
/**
* Get the JVM signature for the behavior. The JVM signature for a method
* is composed of the JVM signatures for each of the parameters (within
* parenthesis) plus the JVM signature for the method return type.
*
* @return the JVM signature for the behavior
*/
public String getJVMSignature()
{
StringBuffer sb = new StringBuffer();
sb.append('(');
int c = getParameterCount();
for (int i = 0; i < c; ++i)
{
sb.append(getParameter(i).getDataType().getJVMSignature());
}
sb.append(')')
.append(m_retval.getDataType().getJVMSignature());
return sb.toString();
}
// ----- origin: helper for interface origins
/**
* Resolve any conflicts such that this Behavior matches the passed
* method declaration for integration.
*
* @param map declaring integration
* @param method the Java method information
*/
protected void setDeclaredByIntegration(Integration map, Behavior method)
{
setDeclaredByTrait(map, true, method);
}
/**
* Resolve any conflicts such that this Behavior matches the passed
* method declaration for an interface.
*
* @param iface declaring interface
* @param method the Java method information, or null if the method is
* implied (e.g. add/remove listener)
*/
protected void setDeclaredByInterface(Interface iface, Behavior method)
{
setDeclaredByTrait(iface, false, method);
}
/**
* Resolve any conflicts such that this Behavior matches the passed
* method declaration for an interface or integration.
*
* @param trait declaring interface or integration
* @param fIntegration true if the integration trait
* @param method the Java method information, or null if the method is
* implied (e.g. add/remove listener)
*/
private void setDeclaredByTrait(Trait trait, boolean fIntegration, Behavior method)
{
// add/remove listener methods are implied; assume defaults
DataType dtRet = DataType.VOID;
String sParamDirs = "I";
StringTable tblExcept = null;
if (method != null)
{
dtRet = method.m_retval.getDataType();
sParamDirs = method.getParameterDirections();
tblExcept = method.m_tblExcept;
}
try
{
// update access
if (fIntegration)
{
// integrates requires at least protected access
if (getAccess() == ACCESS_PRIVATE)
{
// TODO - uncomment the following when the tools mature
// (Gene creates prop first then integrates second to save time)
// setAccess(ACCESS_PROTECTED, false);
setAccess(ACCESS_PUBLIC, false);
}
}
else
{
// implements/dispatches require public methods
if (getAccess() != ACCESS_PUBLIC)
{
setAccess(ACCESS_PUBLIC, false);
}
}
// cannot be static for Component,
// but as of Java 8 static extension methods are allowed
setStatic(method != null && method.isStatic() && getComponent().isSignature(), false);
// match up return value data type and parameter directions
m_retval.setDataType(dtRet, false);
setParameterDirections(sParamDirs, false);
// the exceptions that currently exist must be merged with the
// exceptions from the interface/integrates method, and if the
// Behavior has a non-manual origin, then only the intersection
// of the exceptions are permitted to remain throwable
StringTable tblThrowee = m_tblExcept;
if (getComponent().isSignature())
{
// assuming the signature is correct, we can safely
// ignore any exceptions declared by the interface
// TODO: the logic below doesn't really do what the comment above
// claims, but to validate covariant types we need to have a loader
// (e.g. to figure out that SocketException is an IOException)
}
else
{
if (tblExcept != null && !tblExcept.isEmpty())
{
if (getComponent().isSignature())
{
return;
}
// copy method exceptions to the Behavior
for (Enumeration enmr = tblExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
Throwee except = (Throwee) tblExcept.get(sExcept);
Throwee throwee = (Throwee) tblThrowee.get(sExcept);
// create the exception if is not declared by the Behavior
if (throwee == null)
{
throwee = new Throwee(this, except.getDataType());
// if the behavior is declared elsewhere (base or
// super level or from an interface), the exception
// cannot be thrown
if (isFromSuper() || isFromImplements()
|| isFromDispatches() || isFromIntegration())
{
throwee.setExists(EXISTS_DELETE);
}
tblThrowee.put(sExcept, throwee);
throwee.validate();
}
// update exception origin
throwee.addOriginTrait(trait);
}
}
// remove previously existing declared exceptions that are not
// declared by the interface/integrates method
for (Enumeration enmr = tblThrowee.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (!tblExcept.contains(sExcept))
{
removeException(sExcept, false);
}
}
}
// update Behavior origin
addOriginTrait(trait);
}
catch (PropertyVetoException e)
{
throw new IllegalStateException(e.toString());
}
}
/**
* Merge the exceptions lists from two behaviors, modifying this behavior.
* This is used by JCS from ClassFile creation.
*
* @param that the other behavior
*/
protected void mergeJCSExceptions(Behavior that)
{
if (!this.m_tblExcept.equals(that.m_tblExcept))
{
this.m_tblExcept.retainAll(that.m_tblExcept);
}
}
// ----- origin: behavior implements interface(s)
/**
* Determine if this behavior is from an interface.
*
* @return true if this behavior results from an interface at this level
*/
public boolean isFromImplements()
{
return isFromTraitDescriptor(Interface.DESCRIPTOR_IMPLEMENTS);
}
/**
* Enumerate the interface names that exist at this level which declare
* this behavior.
*
* @return an enumeration of interface names
*/
public Enumeration enumImplements()
{
return getOriginTraits(Interface.DESCRIPTOR_IMPLEMENTS);
}
// ----- origin: behavior dispatches interface(s)
/**
* Determine if this behavior is from a dispatched interface.
*
* @return true if this behavior results from a dispatched interface at
* this level
*/
public boolean isFromDispatches()
{
return isFromTraitDescriptor(Interface.DESCRIPTOR_DISPATCHES);
}
/**
* Enumerate the dispatch interface names that exist at this level which
* declare this behavior.
*
* @return an enumeration of dispatch interface names
*/
public Enumeration enumDispatches()
{
return getOriginTraits(Interface.DESCRIPTOR_DISPATCHES);
}
// ----- origin: behavior integrates
/**
* Determine if this behavior exists as a result of integration at this
* level.
*
* @return true if this behavior results from integration at this level
*/
public boolean isFromIntegration()
{
return isFromTraitDescriptor(Integration.DESCRIPTOR);
}
// ----- origin: behavior from a property
/**
* Determine if this behavior exists due to a property.
*
* @return true if this behavior results from a property
*/
public boolean isFromProperty()
{
return isFromTraitDescriptor(Property.DESCRIPTOR);
}
/**
* Determine the name of the property that this behavior implements.
*
* @return the property name
*/
public String getPropertyName()
{
String sProp;
if (m_sName.startsWith("is"))
{
sProp = m_sName.substring("is".length());
}
else if (m_sName.startsWith("get"))
{
sProp = m_sName.substring("get".length());
}
else if (m_sName.startsWith("set"))
{
sProp = m_sName.substring("set".length());
}
else
{
return null;
}
Property prop = getComponent().getProperty(sProp);
return (prop == null ? null : sProp);
}
// ----- origin: behavior declared "manually"
/**
* Determine if the manual origin flag can be set. It cannot be set if
* the behavior's only origin is manual.
*
* @return true if the manual origin flag can be set
*/
public boolean isFromManualSettable()
{
return isDeclaredAtThisLevel() && isFromNonManual() && isModifiable();
}
/**
* Set whether or not this behavior exists at this level regardless of
* whether it exists from derivation, implements, dispatches, or
* integrates.
*
* @param fManual
*/
public void setFromManual(boolean fManual)
throws PropertyVetoException
{
setFromManual(fManual, true);
}
/**
* Set whether or not this behavior exists at this level regardless of
* whether it exists from derivation, implements, dispatches, or
* integrates.
*
* @param fManual
* @param fVetoable true if the setter can veto the value
*/
protected synchronized void setFromManual(boolean fManual, boolean fVetoable)
throws PropertyVetoException
{
boolean fPrev = isFromManual();
if (fManual == fPrev)
{
return;
}
Boolean prev = toBoolean(fPrev);
Boolean value = toBoolean(fManual);
if (fVetoable)
{
if (!isFromManualSettable())
{
readOnlyAttribute(ATTR_FROMMANUAL, prev, value);
}
fireVetoableChange(ATTR_FROMMANUAL, prev, value);
}
if (fManual)
{
setFromManual();
}
else
{
clearFromManual();
}
firePropertyChange(ATTR_FROMMANUAL, prev, value);
}
// ----- Exists
/**
* Get the exists flag for this Behavior.
*
* For a JCS, a Behavior is EXISTS_NOT if a super or interface declares
* the method but the method is not present in the class represented by
* the JCS.
*
* @return either EXISTS_INSERT or EXISTS_UPDATE (or EXISTS_NOT if a JCS)
*/
public int getExists()
{
return m_nFlags & EXISTS_MASK;
}
/**
* Set the exists flag for this Behavior.
*
* @param nExists the exists flag for this Behavior
*/
protected void setExists(int nExists)
{
m_nFlags = m_nFlags & ~EXISTS_MASK | nExists;
}
// ----- Access
/**
* Determine the current accessibility of the Behavior.
*
* @return either ACCESS_PUBLIC, ACCESS_PROTECTED, or ACCESS_PRIVATE
*
* @see com.tangosol.dev.component.Constants#ACCESS_PUBLIC
* @see com.tangosol.dev.component.Constants#ACCESS_PROTECTED
* @see com.tangosol.dev.component.Constants#ACCESS_PRIVATE
*/
public int getAccess()
{
return m_nFlags & ACCESS_MASK;
}
/**
* Determine if the accessibility of the Behavior can be modified.
*
* The accessibility cannot be set if the Behavior is declared final at
* a super level or if the Behavior originates from an interface.
*
* @return true if the access attribute of the Behavior can be set
*/
public boolean isAccessSettable()
{
// if Behavior is part of an "interface", it can only be public
return isModifiable()
&& !isFromImplements()
&& !isFromDispatches();
}
/**
* Determine if the specified value is acceptable for the access
* attribute.
*
* The accessibility can only be increased from the super level; access
* is a one-way attribute (private -> protected -> public).
*
* @return true if the specified value is acceptable for the access
* attribute
*
* @see com.tangosol.dev.component.Constants#ACCESS_PUBLIC
* @see com.tangosol.dev.component.Constants#ACCESS_PROTECTED
* @see com.tangosol.dev.component.Constants#ACCESS_PRIVATE
*/
public boolean isAccessLegal(int nAccess)
{
switch (nAccess)
{
case ACCESS_PUBLIC:
case ACCESS_PROTECTED:
case ACCESS_PRIVATE:
break;
default:
return false;
}
// remote methods must be public
if (isRemote() && nAccess != ACCESS_PUBLIC)
{
return false;
}
// flexible at declaration level
if (isDeclaredAtThisLevel())
{
if (isFromImplements() || isFromDispatches())
{
// interface Behaviors must be public
return false;
}
if (isFromIntegration())
{
// integrated Behaviors must be protected or public in order
// to be called from the integratee
return (nAccess != ACCESS_PRIVATE);
}
return true;
}
// one-way access validation
switch (m_nPrevFlags & ACCESS_MASK)
{
case ACCESS_PUBLIC:
if (nAccess == ACCESS_PROTECTED)
{
return false;
}
// no break;
case ACCESS_PROTECTED:
if (nAccess == ACCESS_PRIVATE)
{
return false;
}
// no break;
case ACCESS_PRIVATE:
default:
return true;
}
}
/**
* Set the accessibility of the Behavior.
*
* @param nAccess ACCESS_PUBLIC, ACCESS_PROTECTED, or ACCESS_PRIVATE
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*
* @see com.tangosol.dev.component.Constants#ACCESS_PUBLIC
* @see com.tangosol.dev.component.Constants#ACCESS_PROTECTED
* @see com.tangosol.dev.component.Constants#ACCESS_PRIVATE
*/
public void setAccess(int nAccess)
throws PropertyVetoException
{
setAccess(nAccess, true);
}
/**
* Set the accessibility of the Behavior.
*
* @param nAccess ACCESS_PUBLIC, ACCESS_PROTECTED, or ACCESS_PRIVATE
* @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 setAccess(int nAccess, boolean fVetoable)
throws PropertyVetoException
{
int nPrev = getAccess();
if (nAccess == nPrev)
{
return;
}
Integer prev = Integer.valueOf(nPrev);
Integer value = Integer.valueOf(nAccess);
if (fVetoable)
{
if (!isAccessSettable())
{
readOnlyAttribute(ATTR_ACCESS, prev, value);
}
if (!isAccessLegal(nAccess))
{
illegalAttributeValue(ATTR_ACCESS, prev, value);
}
fireVetoableChange(ATTR_ACCESS, prev, value);
}
m_nFlags = m_nFlags & ~ACCESS_MASK | nAccess;
firePropertyChange(ATTR_ACCESS, prev, value);
}
// ----- Visible
/**
* Get the visibility attribute of the Behavior.
*
* @return the value of the Behavior's visibility attribute
*
* @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 Behavior can be set.
*
* @return true if the Behavior attribute can set with a valid value
*/
public boolean isVisibleSettable()
{
return isModifiable();
}
/**
* Determine whether the Visible attribute of the Behavior can be set to
* the specified value. The Visible attribute 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 Behavior.
*
* @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 Behavior.
*
* @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);
}
// ----- Synchronized
/**
* Get the synchronized attribute of the Behavior.
*
* @return true if the Behavior is synchronized
*/
public boolean isSynchronized()
{
return (m_nFlags & SYNC_MASK) == SYNC_MONITOR;
}
/**
* Determine whether the synchronized attribute of the Behavior can be
* set. Since the synchronized attribute is expressed as a boolean, this
* method doubles for both the "is settable" and "is legal" questions. The
* synchronized attribute of the Behavior is flexible.
*
* @return true if the synchronized attribute can set
*/
public boolean isSynchronizedSettable()
{
return isModifiable();
}
/**
* Set the synchronized attribute of the Behavior.
*
* @param fSync the new synchronized attribute value
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void setSynchronized(boolean fSync)
throws PropertyVetoException
{
setSynchronized(fSync, true);
}
/**
* Set the synchronized attribute of the Behavior.
*
* @param fSync the new synchronized 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 setSynchronized(boolean fSync, boolean fVetoable)
throws PropertyVetoException
{
boolean fPrevSync = isSynchronized();
if (fSync == fPrevSync)
{
return;
}
Boolean prev = toBoolean(fPrevSync);
Boolean value = toBoolean(fSync);
if (fVetoable)
{
if (!isSynchronizedSettable())
{
readOnlyAttribute(ATTR_SYNCHRONIZED, prev, value);
}
fireVetoableChange(ATTR_SYNCHRONIZED, prev, value);
}
m_nFlags = m_nFlags & ~SYNC_MASK | (fSync ? SYNC_MONITOR : SYNC_NOMONITOR);
firePropertyChange(ATTR_SYNCHRONIZED, prev, value);
}
// ----- Abstract
/**
* Get the Behavior implementation attribute.
*
* @return true if the Behavior is abstract
*/
public boolean isAbstract()
{
return (m_nFlags & IMPL_MASK) == IMPL_ABSTRACT;
}
/**
* Determine whether the implementation attribute of the Behavior 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 Behavior is flexible
* for instance-scope Behaviors but cannot be set for static-scope.
*
* @return true if the implementation attribute can set
*/
public boolean isAbstractSettable()
{
return isModifiable() && !(isStatic() || isFinal());
}
/**
* Set the Behavior'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 Behavior'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);
}
// ----- Static
/**
* Determine the current scope of the Behavior.
*
* @return true if the Behavior is static (not instance)
*/
public boolean isStatic()
{
return (m_nFlags & SCOPE_MASK) == SCOPE_STATIC;
}
/**
* Determine if the scope of the Behavior can be modified.
*
* Static cannot co-exist with abstract or remote.
* Static cannot be set if the Behavior is from an "interface",
* a Property, or from a super level.
*
* @return true if the scope attribute of the Behavior can be set
*/
public boolean isStaticSettable()
{
// 2001.05.08 cp allow static behaviors to be remote in order to
// support ejb home design using static methods
return isModifiable() && !isFromNonManual() && !isAbstract(); // && !isRemote();
}
/**
* Set the scope attribute of the Behavior.
*
* @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 Behavior.
*
* @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);
}
// ----- Final
/**
* Determine the current finality of the Behavior.
*
* @return true if the Behavior is final
*/
public boolean isFinal()
{
return (m_nFlags & DERIVE_MASK) == DERIVE_FINAL;
}
/**
* Determine if the finality of the Behavior can be modified.
*
* @return true if the final attribute of the Behavior can be set
*/
public boolean isFinalSettable()
{
return isModifiable() && !isAbstract();
}
/**
* Set the finality attribute of the Behavior.
*
* @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 Behavior.
*
* @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);
}
// ----- Deprecated
/**
* Get the antiquity attribute of the Behavior.
*
* @return true if the Behavior is deprecated
*/
public boolean isDeprecated()
{
return (m_nFlags & ANTIQ_MASK) == ANTIQ_DEPRECATED;
}
/**
* Determine whether the antiquity attribute of the Behavior 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 Behavior is flexible.
*
* @return true if the antiquity attribute can set
*/
public boolean isDeprecatedSettable()
{
return isModifiable();
}
/**
* Set the antiquity attribute of the Behavior.
*
* @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 Behavior.
*
* @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);
}
// ----- Remote
/**
* Get the Behavior distribution attribute.
*
* @return true if the Behavior is remotable
*/
public boolean isRemote()
{
return (m_nFlags & DIST_MASK) == DIST_REMOTE;
}
/**
* Determine whether the distribution attribute of the Behavior 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 is one-way attribute (local -> remote).
* Note that a behavior cannot be marked as remote if it is static or
* non-public.
*
* @return true if the distribution attribute can set
*/
public boolean isRemoteSettable()
{
Component cd = getComponent();
// 2001.05.08 cp allow static behaviors to be remote in order to
// support ejb home design using static methods
// return isModifiable() && !isStatic() && getAccess() == ACCESS_PUBLIC
// && cd.isRemote() && cd.isGlobal()
// && (m_nPrevFlags & DIST_MASK) == DIST_LOCAL;
return isModifiable() && getAccess() == ACCESS_PUBLIC
&& cd.isRemote() && cd.isGlobal()
&& (m_nPrevFlags & DIST_MASK) == DIST_LOCAL;
}
/**
* Set the Behavior'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 Behavior'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)
{
// local Behaviors cannot have inout or out Parameters
int c = getParameterCount();
for (int i = 0; i < c; ++i)
{
Parameter param = getParameter(i);
if (param.getDirection() != DIR_IN)
{
param.setDirection(DIR_IN, false);
}
}
}
firePropertyChange(ATTR_REMOTE, prev, value);
}
// ----- return value
/**
* Access the return value sub-trait. All modifications are done to the
* sub-trait itself so there is no add/remove/set etc. for the return
* value here.
*
* @return the return value sub-trait
*/
public ReturnValue getReturnValue()
{
return m_retval;
}
// ----- name
/**
* Determine the name of this behavior.
*
* @return the name of this behavior
*/
public String getName()
{
return m_sName;
}
/**
* Determine if this behavior is a constructor,
* only valid for Java Class Signatures.
*
* @return true if it is a constructor
*/
public boolean isConstructor()
{
return isConstructor(m_sName);
}
/**
* Determine if this behavior name or signature is a
* constructor, only valid for Java Class Signatures.
*
* @param sName the name or signature to check
* @return true if is is a constructor
*/
public static boolean isConstructor(String sName)
{
return sName.charAt(0) == '<';
}
/**
* Determine if the behavior name can be set. It cannot be set if
* the behavior originates from anything except manual addition.
*
* @return true if the behavior name can be set
*/
public boolean isNameSettable()
{
return isModifiable() && !isFromNonManual();
}
/**
* Determine if the specified name is a legal behavior name and that
* it won't conflict with other behavior signatures.
*
* @return true if the specified name is legal for this behavior
*/
public boolean isNameLegal(String sName)
{
// must be a legal Java identifier
if (sName == null || sName.length() == 0 ||
!ClassHelper.isSimpleNameLegal(sName))
{
return false;
}
// check if name is unchanged
if (sName.equals(m_sName))
{
return true;
}
// build the proposed signature
String sSig = getSignature(sName, getParameterTypes());
return !isSignatureReserved(sSig);
}
/**
* Set the behavior name.
*
* @param sName the new name for the behavior
*
* @exception PropertyVetoException if the new attribute value is not
* accepted
*/
public void setName(String sName)
throws PropertyVetoException
{
setName(sName, true);
}
/**
* Set the behavior name.
*
* @param sName the new name for the behavior
* @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;
updateSignature();
firePropertyChange(ATTR_NAME, sPrev, sName);
}
// ----- parameters
/**
* Get all behavior parameters.
*
* @return an array of behavior parameters
*/
public Parameter[] getParameter()
{
int c = getParameterCount();
Parameter[] aparam = new Parameter[c];
for (int i = 0; i < c; ++i)
{
aparam[i] = getParameter(i);
}
return aparam;
}
/**
* Determine if the parameter array can be set. The parameter array
* can only be changed if the behavior is declared at this level
* and isn't part of an interface or the result of integration.
*
* @return true if the array of parameters can be set
*/
public boolean isParameterSettable()
{
return isModifiable() && !isFromNonManual();
}
/**
* Determine if the specified array of parameters is a legal array of
* parameters for this behavior.
*
* @param aparam an array of behavior parameters; this must be the same
* set of parameters as returned from the corresponding
* accessor, but can be in a different order
*
* @return true if the specified array of parameters is legal
*/
public boolean isParameterLegal(Parameter[] aparam)
{
int c = getParameterCount();
if (aparam == null || aparam.length != c)
{
return false;
}
// verify that all parameters are accounted for and then build the
// proposed signature
StringBuffer sb = new StringBuffer(m_sName);
sb.append('(');
boolean[] afFound = new boolean [c];
for (int i = 0; i < c; ++i)
{
Parameter param = aparam[i];
int iCurrent = getParameterPosition(param);
if (iCurrent < 0 || afFound[iCurrent])
{
return false;
}
afFound[iCurrent] = true;
sb.append(param.getSignature());
}
sb.append(')');
String sSig = sb.toString();
return !isSignatureReserved(sSig);
}
/**
* Set all behavior parameters, allowing parameter re-ordering.
*
* @param aparam an array of behavior parameters; this must be the same
* set of parameters as returned from the corresponding
* accessor, but can be in a different order
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void setParameter(Parameter[] aparam)
throws PropertyVetoException
{
setParameter(aparam, true);
}
/**
* Set all behavior parameters, allowing parameter re-ordering.
*
* @param aParam an array of behavior parameters; this must be the
* same set of parameters as returned from the
* corresponding accessor, but can be in a different
* order
* @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 setParameter(Parameter[] aParam, boolean fVetoable)
throws PropertyVetoException
{
Parameter[] aPrev = getParameter();
int cParam = (fVetoable ? aPrev : aParam).length;
// check if the passed set of parameters is in a different order
try
{
boolean fSame = true;
for (int i = 0; i < cParam; ++i)
{
if (aParam[i] != aPrev[i])
{
fSame = false;
break;
}
}
if (fSame)
{
return;
}
}
catch (NullPointerException e)
{
// handled by legal check below
}
catch (ArrayIndexOutOfBoundsException e)
{
// handled by legal check below
}
if (fVetoable)
{
if (!isParameterSettable())
{
readOnlyAttribute(ATTR_PARAMETER, aPrev, aParam);
}
if (!isParameterLegal(aParam))
{
illegalAttributeValue(ATTR_PARAMETER, aPrev, aParam);
}
fireVetoableChange(ATTR_PARAMETER, aPrev, aParam);
}
m_vectParam.removeAllElements();
for (int i = 0; i < cParam; ++i)
{
m_vectParam.addElement(aParam[i]);
}
updateSignature();
firePropertyChange(ATTR_PARAMETER, aPrev, aParam);
}
/**
* Helper to modify/add/remove parameters using only names and data types.
*
* @param adt parameter data types
* @param asName parameter names
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void setParameter(DataType[] adt, String[] asName)
throws PropertyVetoException
{
// validate passed information is legal
if (adt == null || asName == null)
{
adt = new DataType[0];
asName = new String [0];
}
Parameter[] aPrev = getParameter();
int cPrev = aPrev.length;
if (adt.length != asName.length)
{
illegalAttributeValue(ATTR_PARAMETER, aPrev, new Object[] {adt, asName});
}
// make sure information has been changed
if (cPrev == adt.length)
{
boolean fSame = true;
for (int i = 0; i < cPrev; ++i)
{
Parameter param = aPrev[i];
if (param.getDataType() != adt[i] || !param.getName().equals(asName[i]))
{
fSame = false;
break;
}
}
if (fSame)
{
return;
}
}
// make sure information can be changed
if (!(isModifiable() && isDeclaredAtThisLevel()))
{
illegalAttributeValue(ATTR_PARAMETER, aPrev, new Object[] {adt, asName});
}
// verify that signature is legal
StringBuffer sb = new StringBuffer(m_sName);
sb.append('(');
StringTable tblNames = new StringTable(INSENS);
int cParam = adt.length;
for (int i = 0; i < cParam; ++i)
{
// validate type and name
DataType dt = adt[i];
String sName = asName[i];
if (dt == null || dt == DataType.VOID || sName == null
|| !ClassHelper.isSimpleNameLegal(sName) || tblNames.contains(sName))
{
illegalAttributeValue(ATTR_PARAMETER, aPrev, new Object[] {adt, asName});
}
// build signature
sb.append(dt.getTypeString());
// keep track of names
tblNames.put(sName, Integer.valueOf(i));
}
sb.append(')');
String sSig = sb.toString();
// verify that signature is available
if (isSignatureReserved(sSig))
{
illegalAttributeValue(ATTR_PARAMETER, aPrev, new Object[] {adt, asName});
}
// new parameter list (not all the info is available at this time)
Parameter[] aParam = new Parameter[cParam];
// check if signature is changed
boolean fOrderUnchanged = sSig.equals(getSignature());
if (!fOrderUnchanged)
{
// verify that order can be changed
if (!isParameterSettable())
{
readOnlyAttribute(ATTR_PARAMETER, aPrev, aParam);
}
}
// notify veto listeners
fireVetoableChange(ATTR_PARAMETER, aPrev, aParam);
if (fOrderUnchanged)
{
// only name (if any) changes
for (int i = 0; i < cParam; ++i)
{
aPrev[i].setName(asName[i], false);
}
}
else
{
// match up old parameters to new ones
Vector vectNoMatch = new Vector();
for (int i = 0; i < cPrev; ++i)
{
Parameter prev = aPrev[i];
String sPrev = prev.getName();
Integer index = (Integer) tblNames.get(sPrev);
if (index == null)
{
vectNoMatch.add(prev);
}
else
{
// name matched
int iParam = index.intValue();
aParam[iParam] = prev;
// update type and name (in case of a case sensitive change)
prev.setDataType(adt [iParam], false);
prev.setName (asName[iParam], false);
}
}
// check for unmatched parameters
boolean fMatch = true;
for (int i = 0, c = 0; i < cParam; ++i)
{
Parameter param = aParam[i];
if (param == null)
{
// try to match by data type
DataType dt = adt [i];
String sName = asName[i];
if (fMatch)
{
if (vectNoMatch.isEmpty())
{
fMatch = false;
}
else
{
Parameter prev = (Parameter) vectNoMatch.get(0);
if (dt == prev.getDataType())
{
prev.setName(sName, false);
param = prev;
vectNoMatch.remove(0);
}
else
{
fMatch = false;
}
}
}
// otherwise create a new one
if (param == null)
{
param = new Parameter(this, dt, sName, DIR_IN);
param.validate();
}
aParam[i] = param;
}
}
// destroy left-overs
if (!vectNoMatch.isEmpty())
{
for (Enumeration enmr = vectNoMatch.elements(); enmr.hasMoreElements(); )
{
((Parameter) enmr.nextElement()).invalidate();
}
}
// store new set of Parameters
Vector vectParam = new Vector(cParam);
for (int i = 0; i < cParam; ++i)
{
vectParam.add(aParam[i]);
}
m_vectParam = vectParam;
updateSignature();
}
// notify
firePropertyChange(ATTR_PARAMETER, aPrev, aParam);
}
/**
* Determine if a parameter can be added to the behavior.
*
* @param iParam position for the new parameter (-1 to add to end)
* @param dt proposed parameter data type
* @param sName proposed parameter name
*
* @return true if it is possible to add the parameter as specified
*/
public boolean isParameterAddable(int iParam, DataType dt, String sName)
{
// check if the signature is alterable; verify proposed index;
// parameter name must be a unique legal Java identifier
int c = getParameterCount();
if (iParam < 0)
{
iParam = c;
}
if (!isParameterSettable()
|| iParam > c
|| sName == null
|| sName.length() == 0
|| !ClassHelper.isSimpleNameLegal(sName)
|| getParameter(sName) != null
|| dt == null
|| dt == DataType.VOID)
{
return false;
}
// build the proposed signature
StringBuffer sb = new StringBuffer(m_sName);
sb.append('(');
for (int i = 0; i < c; ++i)
{
if (i == iParam)
{
sb.append(dt.getTypeString());
}
sb.append(getParameter(i).getSignature());
}
if (iParam == c)
{
sb.append(dt.getTypeString());
}
sb.append(')');
String sSig = sb.toString();
return !isSignatureReserved(sSig);
}
/**
* Add the specified parameter to the behavior.
*
* @param iParam position for the new parameter (-1 to add to end)
* @param dt proposed parameter data type
* @param sName proposed parameter name
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public Parameter addParameter(int iParam, DataType dt, String sName)
throws PropertyVetoException
{
return addParameter(iParam, dt, sName, true);
}
/**
* Add the specified parameter to the behavior.
*
* @param iParam position for the new parameter (-1 to add to end)
* @param dt proposed parameter data type
* @param sName proposed parameter name
* @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 Parameter addParameter(int iParam, DataType dt, String sName, boolean fVetoable)
throws PropertyVetoException
{
if (fVetoable && !isParameterAddable(iParam, dt, sName))
{
subNotAddable(ATTR_PARAMETER, sName);
}
// create parameter
Parameter param = new Parameter(this, dt, sName, DIR_IN);
param.setUID(new UID(), fVetoable);
// notify veto listeners
if (fVetoable)
{
try
{
fireVetoableSubChange(param, SUB_ADD);
}
catch (PropertyVetoException e)
{
param.invalidate();
throw e;
}
}
// add parameter
if (iParam < 0)
{
m_vectParam.addElement(param);
}
else
{
m_vectParam.insertElementAt(param, iParam);
}
updateSignature();
// notify listeners
param.validate();
fireSubChange(param, SUB_ADD);
return param;
}
/**
* Determine if a parameter can be removed to the behavior.
*
* @param iParam position of the parameter to remove
*
* @return true if it is possible to remove the specified parameter
*/
public boolean isParameterRemovable(int iParam)
{
// check if the signature is alterable; verify index;
int c = getParameterCount();
if (!isParameterSettable()
|| iParam < 0
|| iParam >= c)
{
return false;
}
// build the proposed signature
StringBuffer sb = new StringBuffer(m_sName);
sb.append('(');
for (int i = 0; i < c; ++i)
{
if (i != iParam)
{
sb.append(getParameter(i).getSignature());
}
}
sb.append(')');
String sSig = sb.toString();
return !isSignatureReserved(sSig);
}
/**
* Remove the specified parameter from the behavior.
*
* @param iParam the parameter index to remove
*
* @exception PropertyVetoException if removal is illegal or if removal
* is vetoed
*/
public void removeParameter(int iParam)
throws PropertyVetoException
{
removeParameter(iParam, true);
}
/**
* Remove the specified parameter from the behavior.
*
* @param iParam the parameter index 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 removeParameter(int iParam, boolean fVetoable)
throws PropertyVetoException
{
Parameter param;
try
{
// get the parameter information
param = getParameter(iParam);
}
catch (IndexOutOfBoundsException e)
{
if (fVetoable)
{
// the caller handed us garbage (so report garbage)
subNotRemovable(ATTR_PARAMETER, e);
}
return;
}
if (fVetoable)
{
// verify that the parameter can be removed
if (!isParameterRemovable(iParam))
{
subNotRemovable(ATTR_PARAMETER, param);
}
// notify veto listeners
fireVetoableSubChange(param, SUB_REMOVE);
}
// remove the parameter
m_vectParam.removeElementAt(iParam);
updateSignature();
// notify listeners
fireSubChange(param, SUB_REMOVE);
// discard the parameter
param.invalidate();
}
/**
* Get the number of behavior parameters.
*
* @return the number of behavior parameters
*/
public int getParameterCount()
{
return m_vectParam.size();
}
/**
* Get parameter by position.
*
* @param i the parameter number, zero based
*
* @return the specified parameter
*/
public Parameter getParameter(int i)
{
return (Parameter) m_vectParam.elementAt(i);
}
/**
* Get position by parameter.
*
* @param param the parameter to search for
*
* @return the parameter position, zero based, or -1 if not found
*/
public int getParameterPosition(Parameter param)
{
return m_vectParam.indexOf(param);
}
/**
* Get parameter by name, case insensitive.
*
* @param sName the parameter name
*
* @return the specified parameter or null if no parameter exists by that
* name
*/
public Parameter getParameter(String sName)
{
CollationKey ckName = INSENS.getCollationKey(sName);
int c = getParameterCount();
for (int i = 0; i < c; ++i)
{
Parameter param = getParameter(i);
CollationKey ckParam = INSENS.getCollationKey(param.getName());
if (ckName.compareTo(ckParam) == 0)
{
return param;
}
}
return null;
}
/**
* Build an array of the Parameter data types.
*
* @return an array of the Parameter data types
*/
public DataType[] getParameterTypes()
{
int cdt = m_vectParam.size();
DataType[] adt = new DataType[cdt];
for (int i = 0; i < cdt; ++i)
{
adt[i] = ((Parameter) m_vectParam.elementAt(i)).getDataType();
}
return adt;
}
/**
* Extract the parameter names from an existing behavior.
*
* @return an array of the Parameter names
*/
public String[] getParameterNames()
{
int cNames = m_vectParam.size();
String[] asName = new String[cNames];
for (int i = 0; i < cNames; ++i)
{
asName[i] = ((Parameter) m_vectParam.elementAt(i)).getName();
}
return asName;
}
/**
* Build a list of default parameter names for the given parameter data
* types.
*
* @param adtParam an array of parameter Data Types
*
* @return an array of parameter names
*/
public static String[] getDefaultParameterNames(DataType[] adtParam)
{
int cParams = (adtParam != null ? adtParam.length : 0);
String[] asParam = new String[cParams];
for (int i = 0; i < cParams; ++i)
{
asParam[i] = "Param_" + (i + 1);
}
return asParam;
}
/**
* Build a string representing the Parameter directions. The string is
* composed the characters 'I' (in), 'O' (out), and 'B' (both in and out).
*
* @return a string of characters representing the Parameter directions
*/
protected String getParameterDirections()
{
int c = m_vectParam.size();
char[] ach = new char[c];
for (int i = 0; i < c; ++i)
{
switch (((Parameter) m_vectParam.elementAt(i)).getDirection())
{
default:
case DIR_IN:
ach[i] = 'I';
break;
case DIR_OUT:
ach[i] = 'O';
break;
case DIR_INOUT:
ach[i] = 'B';
break;
}
}
return new String(ach);
}
/**
* Set the Parameter directions based on a string composed of the
* characters 'I' (in), 'O' (out), and 'B' (both in and out).
*
* @param sDir a string of characters representing the Parameter
* directions
* @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 void setParameterDirections(String sDir, boolean fVetoable)
throws PropertyVetoException
{
int c = m_vectParam.size();
if (c != sDir.length())
{
throw new IllegalArgumentException(CLASS + ".setParameterDirections:"
+ " Invalid direction string (" + sDir + ")!");
}
for (int i = 0; i < c; ++i)
{
int nDir;
switch (sDir.charAt(i))
{
case 'I':
nDir = DIR_IN;
break;
case 'O':
nDir = DIR_OUT;
break;
case 'B':
nDir = DIR_INOUT;
break;
default:
throw new IllegalArgumentException(CLASS + ".setParameterDirections:"
+ " Invalid direction string (" + sDir + ")!");
}
((Parameter) m_vectParam.elementAt(i)).setDirection(nDir, fVetoable);
}
}
// ----- exceptions
/**
* Get a list of the names of all declared exceptions.
*
* @return an array of the qualified names of the exceptions declared for
* this behavior.
*/
public String[] getExceptionNames()
{
return m_tblExcept.strings();
}
/**
* Get an exceptions by its name. For a list of names, see
* getExceptionNames.
*
* @param sExcept the qualified name of the exception to get
*
* @return the behavior exception corresponding to the passed name or null
* if the specified exception is not declared by this behavior
*/
public Throwee getException(String sExcept)
{
Throwee except = (Throwee) m_tblExcept.get(sExcept);
if (except != null)
{
int nExists = except.getExists();
if (nExists == EXISTS_DELETE || nExists == EXISTS_NOT)
{
return null;
}
}
return except;
}
/**
* Determine if the exception array can be set. The exception array
* can be set iff at least one of the following is true:
*
* 1) There are exceptions that can be added
* 2) There are exceptions that can be removed
* 3) There are exceptions that can be unremoved
*
* @return true if the array of exceptions can be set
*/
public boolean isExceptionSettable()
{
if (!isModifiable())
{
return false;
}
// exceptions can be added iff the behavior is not inherited and
// does not originate from an interface or from integration
if (!(isFromSuper() || isFromImplements() || isFromDispatches() || isFromIntegration()))
{
return true;
}
// exceptions can be removed or unremoved iff the behavior says so
for (Enumeration enmr = m_tblExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (isExceptionRemovable(sExcept) || isExceptionUnremovable(sExcept))
{
return true;
}
}
// nothing can be set
return false;
}
/**
* Determine if the exception array can be set to the specified value.
*
* @param asExcept an array of behavior exceptions names
*
* @return true if the array of exceptions can be set as specified
*/
public boolean isExceptionLegal(String[] asExcept)
{
// get the old list of exceptions
StringTable tblOld = new StringTable();
for (Enumeration enmr = m_tblExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (getException(sExcept) != null)
{
tblOld.add(sExcept);
}
}
// get the new list of exceptions
StringTable tblNew = new StringTable();
for (int i = asExcept.length - 1; i >= 0; --i)
{
tblNew.add(asExcept[i]);
}
// check if the set of exceptions is unchanged
if (tblNew.keysEquals(tblOld))
{
return true;
}
// determine what exceptions were added (or "unremoved")
StringTable tblAdded = (StringTable) tblNew.clone();
tblAdded.removeAll(tblOld);
for (Enumeration enmr = tblAdded.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (!isExceptionAddable(sExcept) && !isExceptionUnremovable(sExcept))
{
return false;
}
}
// determine what exceptions were removed
StringTable tblRemoved = tblOld;
tblRemoved.removeAll(tblNew);
for (Enumeration enmr = tblRemoved.keys(); enmr.hasMoreElements(); )
{
if (!isExceptionRemovable((String) enmr.nextElement()))
{
return false;
}
}
return true;
}
/**
* Set all behavior exceptions.
*
* @param asExcept an array of behavior exceptions names
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void setException(String[] asExcept)
throws PropertyVetoException
{
setException(asExcept, true);
}
/**
* Set all behavior exceptions, allowing exception re-ordering.
*
* @param asExcept an array of behavior exceptions names
* @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 setException(String[] asExcept, boolean fVetoable)
throws PropertyVetoException
{
// get the old list of exceptions
StringTable tblOld = new StringTable();
for (Enumeration enmr = m_tblExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (getException(sExcept) != null)
{
tblOld.add(sExcept);
}
}
// get the new list of exceptions
StringTable tblNew = new StringTable();
for (int i = asExcept.length - 1; i >= 0; --i)
{
tblNew.add(asExcept[i]);
}
// check if the set of exceptions is unchanged
if (tblNew.keysEquals(tblOld))
{
return;
}
// for "previous vs. new" notifications
String[] asOld = tblOld.strings();
String[] asNew = tblNew.strings();
// verify exceptions can be changed
if (fVetoable)
{
if (!isExceptionSettable())
{
readOnlyAttribute(ATTR_EXCEPTION, asOld, asNew);
}
if (!isExceptionLegal(asExcept))
{
illegalAttributeValue(ATTR_EXCEPTION, asOld, asNew);
}
fireVetoableChange(ATTR_EXCEPTION, asOld, asNew);
}
// determine what exceptions were added (or "unremoved")
StringTable tblAdded = (StringTable) tblNew.clone();
tblAdded.removeAll(tblOld);
for (Enumeration enmr = tblAdded.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
if (isExceptionUnremovable(sExcept))
{
unremoveException(sExcept, false);
}
else
{
addException(sExcept, false);
}
}
// determine what exceptions were removed
StringTable tblRemoved = tblOld;
tblRemoved.removeAll(tblNew);
for (Enumeration enmr = tblRemoved.keys(); enmr.hasMoreElements(); )
{
removeException((String) enmr.nextElement(), false);
}
firePropertyChange(ATTR_EXCEPTION, asOld, asNew);
}
/**
* Determine if the specified exception can be added to this behavior.
*
* Unfortunately, there is no way to tell if a name actually references an
* existing class or if that class is truly an exception (or actually, if
* that class derives in some way from java.lang.Throwable).
*
* From the Java Language Specification (8.4.4):
* A method that overrides or hides another method (8.4.6), including
* methods that implement abstract methods defined in interfaces, may not
* be declared to throw more checked exceptions than the overridden or
* hidden method. More precisely, suppose that B is a class or interface,
* and A is a superclass or super interface of B, and a method declaration
* n in B overrides or hides a method declaration m in A. If n has a
* throws clause that mentions any checked exception types, then m must
* have a throws clause, and for every checked exception type listed in
* the throws clause of n, that same exception class or one of its super-
* classes must occur in the throws clause of m; otherwise, a compile-time
* error occurs.
*
* Behaviors resulting from property declarations can have additional
* exceptions; from the JavaBeans 1.0 API Specification:
* Both simple and indexed property accessor methods may throw checked
* exceptions. This allows property setter/getter methods to report
* exceptional conditions.
*
* @param sExcept the qualified name of the exception to add
*
* @return true if it is possible to add the exception as specified
*/
public boolean isExceptionAddable(String sExcept)
{
if (!isModifiable() || isFromSuper() || isFromImplements() || isFromDispatches() || isFromIntegration())
{
return false;
}
// check if an identically named exception already exists
if (m_tblExcept.contains(sExcept))
{
return false;
}
// validate that sExcept is an acceptable class name
try
{
return DataType.getClassType(sExcept) != null;
}
catch (IllegalArgumentException e)
{
return false;
}
}
/**
* Add the specified exception to the behavior.
*
* @param sExcept the qualified name of the exception to add
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public Throwee addException(String sExcept)
throws PropertyVetoException
{
return addException(sExcept, true);
}
/**
* Add the specified exception to the behavior.
*
* @param sExcept the qualified name of the exception to add
* @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 Throwee addException(String sExcept, boolean fVetoable)
throws PropertyVetoException
{
if (fVetoable && !isExceptionAddable(sExcept))
{
subNotAddable(ATTR_EXCEPTION, sExcept);
}
// create exception
Throwee except = new Throwee(this, DataType.getClassType(sExcept));
except.setFromManual(true, false);
except.setUID(new UID(), fVetoable);
// notify veto listeners
if (fVetoable)
{
try
{
fireVetoableSubChange(except, SUB_ADD);
}
catch (PropertyVetoException e)
{
except.invalidate();
throw e;
}
}
// add exception
m_tblExcept.put(except.getUniqueName(), except);
// notify listeners
except.validate();
fireSubChange(except, SUB_ADD);
return except;
}
/**
* Determine if the specified exception can be removed from the behavior.
* Exceptions are basically always removable, since you can throw less
* (but not more); see the Java Language Specification (8.4.4).
*
* @param sExcept the qualified name of the exception to remove
*
* @return true if it is possible to remove the exception as specified
*/
public boolean isExceptionRemovable(String sExcept)
{
if (!isModifiable())
{
return false;
}
Throwee except = getException(sExcept);
if (except == null)
{
return false;
}
int nExists = except.getExists();
return nExists == EXISTS_INSERT || nExists == EXISTS_UPDATE;
}
/**
* Remove the specified exception from the behavior.
*
* @param sExcept the qualified name of the exception to remove
*
* @exception PropertyVetoException if removal is illegal or if
* removal is vetoed
*/
public void removeException(String sExcept)
throws PropertyVetoException
{
removeException(sExcept, true);
}
/**
* Remove the specified exception from the behavior.
*
* @param sExcept the qualified name of the exception to remove
* @param fVetoable if the removal can be vetoed
*
* @exception PropertyVetoException if removal is illegal or if
* removal is vetoed
*/
protected synchronized void removeException(String sExcept, boolean fVetoable)
throws PropertyVetoException
{
// get the exception information
Throwee except = getException(sExcept);
if (except == null)
{
if (fVetoable)
{
subNotRemovable(ATTR_EXCEPTION, sExcept);
}
return;
}
// check if already removed
int nExists = except.getExists();
if (nExists != EXISTS_INSERT && nExists != EXISTS_UPDATE)
{
return;
}
if (fVetoable)
{
// verify the exception can be removed
if (!isExceptionRemovable(sExcept))
{
subNotRemovable(ATTR_EXCEPTION, sExcept);
}
// notify veto listeners
fireVetoableSubChange(except, SUB_REMOVE);
}
boolean fDestroy = isDeclaredAtThisLevel() && !except.isFromNonManual();
if (fDestroy)
{
// remove the exception altogether
m_tblExcept.remove(sExcept);
}
else
{
// just flag exception as removed
except.setExists(EXISTS_DELETE);
}
// notify listeners
fireSubChange(except, SUB_REMOVE);
// if removed altogether, then destroy the exception information
if (fDestroy)
{
except.invalidate();
}
}
/**
* Determine if the specified exception can be un-removed from the
* behavior. Exceptions that have been removed at this level can
* be un-removed assuming they don't cause a behavior declaration
* conflict (e.g. two interfaces define same method signature with
* two different exceptions).
*
* @param sExcept the qualified name of the exception to un-remove
*
* @return true if it is possible to un-remove the specified exception
*/
public boolean isExceptionUnremovable(String sExcept)
{
// verify that exception has been removed
Throwee except = (Throwee) m_tblExcept.get(sExcept);
if (except == null || except.getExists() != EXISTS_DELETE)
{
return false;
}
// the non-manual origin of the exception must match the non-manual
// origin of the behavior; in other words, if two interfaces declare
// the behavior, then they must both declare the exception
if (equalsOriginSansManual(except))
{
return true;
}
// could just be a difference in origins caused by a Property trait
return this.isFromSuper() == except.isFromSuper()
&& this.isFromIntegration() == except.isFromIntegration()
&& isEqual(this.enumImplements(), except.enumImplements())
&& isEqual(this.enumDispatches(), except.enumDispatches());
}
/**
* Check for equality of two enumerations in terms of order and
* contents. All elements of the first enumeration must be non-null.
*
* TODO move to com.tangosol.util.Base
*/
private static boolean isEqual(Enumeration enmr1, Enumeration enmr2)
{
while (enmr1.hasMoreElements() && enmr2.hasMoreElements())
{
if (!enmr1.nextElement().equals(enmr2.nextElement()))
{
return false;
}
}
return !enmr1.hasMoreElements() && !enmr2.hasMoreElements();
}
/**
* Compare the contents of a vector with the contents of an enumerator.
*
* @param vect an instance of java.util.Vector
* @param enmr an instance of java.util.Enumeration
*
* @return true if the contents are identical (irregardless of order)
*/
private static boolean VectMatchesEnum(Vector vect, Enumeration enmr)
{
int cEnum = 0;
while (enmr.hasMoreElements())
{
if (!vect.contains(enmr.nextElement()))
{
return false;
}
++cEnum;
}
return (cEnum == vect.size());
}
/**
* Un-remove the specified exception from the behavior.
*
* @param sExcept the qualified name of the exception to un-remove
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void unremoveException(String sExcept)
throws PropertyVetoException
{
unremoveException(sExcept, true);
}
/**
* Un-remove the specified exception from the behavior.
*
* @param sExcept the qualified name of the exception to un-remove
* @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 unremoveException(String sExcept, boolean fVetoable)
throws PropertyVetoException
{
// get the exception information
Throwee except = (Throwee) m_tblExcept.get(sExcept);
if (except == null)
{
if (fVetoable)
{
subNotUnremovable(ATTR_EXCEPTION, sExcept);
}
return;
}
// check for no change
int nExists = except.getExists();
if (nExists == EXISTS_INSERT || nExists == EXISTS_UPDATE)
{
return;
}
if (fVetoable)
{
// verify that the exception can be un-removed
if (!isExceptionUnremovable(sExcept))
{
subNotUnremovable(ATTR_EXCEPTION, sExcept);
}
// notify veto listeners
fireSubChange(except, SUB_UNREMOVE);
}
// flag exception as no longer removed
except.setExists(EXISTS_UPDATE);
// notify listeners
fireSubChange(except, SUB_UNREMOVE);
}
/**
* Update the reference to an exception when the exception data type
* changes. This method is used internally by the Component Definition.
*
* @param sOld the old exception class name
* @param sNew the new exception class name
*/
protected void renameException(String sOld, String sNew)
{
m_tblExcept.put(sNew, m_tblExcept.remove(sOld));
}
// ----- implementations
/**
* Get all implementations at this derivation level.
*
* @return an array of this behavior's implementations
*/
public Implementation[] getImplementation()
{
Vector vect = m_vectScript;
int cImpl = vect.size();
Implementation[] aImpl = new Implementation[cImpl];
while (cImpl-- > 0)
{
aImpl[cImpl] = (Implementation) vect.get(cImpl);
}
return aImpl;
}
/**
* Get implementation by position. The first implementation (index 0) is
* the first implementation that will be executed at this derivation
* level. Each implementation can "super" to the next implementation. If
* a modification level of the behavior sets the OverrideBase attribute,
* then the implementations from the base modification level(s) are not
* available to "super" to, and thus described as "hidden" or "replaced"
* or "overridden". The "super" call from the last implementation in a
* derivation level executes the first implementation of the behavior in
* the next derivation level that contains an implementation of the
* behavior.
*
* @param i the implementation number, zero based
*
* @return the specified implementation
*/
public Implementation getImplementation(int i)
{
return (Implementation) m_vectScript.elementAt(i);
}
/**
* Get the number of behavior implementations (at this derivation level).
*
* @return the number of behavior implementations
*/
public int getImplementationCount()
{
return m_vectScript.size();
}
/**
* Get the number of behavior implementations at this modification level.
*
* @return the number of implementations which are at this modification
* level
*/
public int getModifiableImplementationCount()
{
return m_vectScript.size() - m_cBaseLevelImpl;
}
/**
* Get the number of behavior implementations at this derivation level,
* not including this modification level's implementations.
*
* Using the indexed accessor method getImplementation(int), the caller
* can get any base level implementation by adding the return value from
* getModifiableImplementationCount() to the desired base implementation index.
*
* @return the number of base level behavior implementations
*/
public int getBaseImplementationCount()
{
return m_cBaseLevelImpl;
}
/**
* Determine the number of reachable implementations at this derivation
* level.
*
* @return the number of implementations at this modification level plus
* (if the base implementations are not overridden) the number
* of base implementations
*/
public int getCallableImplementationCount()
{
int cImpl = m_vectScript.size();
if (m_fOverrideBase)
{
cImpl -= m_cBaseLevelImpl;
}
return cImpl;
}
/**
* Determine if the implementation array can be set. The implementation array
* can be changed if the behavior is modifiable.
*
* @return true if the array of implementations can be set
*/
public boolean isImplementationSettable()
{
return isModifiable();
}
/**
* Determine if the specified array of implementations is a legal array of
* implementations for this behavior.
*
* @param aImpl an array of behavior implementations; this must be the same
* set of implementations as returned from the corresponding
* accessor, but can be in a different order
*
* @return true if the specified array of implementations is legal
*/
public boolean isImplementationLegal(Implementation[] aImpl)
{
Implementation[] aPrev = getImplementation();
int cImpl = aPrev.length;
if (aImpl == null || aImpl.length != cImpl)
{
return false;
}
// verify that non-moveable implementations did not move
int cMove = getModifiableImplementationCount();
for (int i = cMove; i < cImpl; ++i)
{
if (aImpl[i] != aPrev[i])
{
return false;
}
}
// verify that all moveable implementations are accounted for
boolean[] afFound = new boolean [cMove];
for (int i = 0; i < cMove; ++i)
{
Implementation impl = aImpl[i];
if (impl == null)
{
return false;
}
int iCurrent = getImplementationPosition(impl);
if (iCurrent < 0 || iCurrent >= cMove || afFound[iCurrent])
{
return false;
}
afFound[iCurrent] = true;
}
return true;
}
/**
* Set all behavior implementations, allowing implementation re-ordering.
*
* @param aImpl an array of behavior implementations; this must be the same
* set of implementations as returned from the corresponding
* accessor, but can be in a different order
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void setImplementation(Implementation[] aImpl)
throws PropertyVetoException
{
setImplementation(aImpl, true);
}
/**
* Set all behavior implementations, allowing implementation re-ordering.
*
* @param aImpl an array of behavior implementations; this must be
* the same set of implementations as returned from the
* corresponding accessor, but can be in a different
* order
* @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 setImplementation(Implementation[] aImpl, boolean fVetoable)
throws PropertyVetoException
{
Implementation[] aPrev = getImplementation();
int cImpl = (fVetoable ? aPrev : aImpl).length;
// check if the passed set of Implementations is in a different order
try
{
boolean fSame = true;
for (int i = 0; i < cImpl; ++i)
{
if (aImpl[i] != aPrev[i])
{
fSame = false;
break;
}
}
if (fSame)
{
return;
}
}
catch (NullPointerException e)
{
// handled by legal check below
}
catch (ArrayIndexOutOfBoundsException e)
{
// handled by legal check below
}
if (fVetoable)
{
if (!isImplementationSettable())
{
readOnlyAttribute(ATTR_IMPLEMENTATION, aPrev, aImpl);
}
if (!isImplementationLegal(aImpl))
{
illegalAttributeValue(ATTR_IMPLEMENTATION, aPrev, aImpl);
}
fireVetoableChange(ATTR_IMPLEMENTATION, aPrev, aImpl);
}
// store new set of implementations
Vector vectScript = new Vector();
for (int i = 0; i < cImpl; ++i)
{
vectScript.add(aImpl[i]);
}
m_vectScript = vectScript;
firePropertyChange(ATTR_IMPLEMENTATION, aPrev, aImpl);
}
/**
* Determine if a implementation can be added to the behavior.
*
* @param iImpl position for the new implementation (0 to insert at the
* beginning or -1 to add to end of the execution "chain")
* @param sLang proposed implementation language
* @param sScript proposed implementation script
*
* @return true if it is possible to add the implementation as specified
*/
public boolean isImplementationAddable(int iImpl, String sLang, String sScript)
{
return isImplementationSettable()
&& iImpl <= getModifiableImplementationCount()
&& Implementation.isLanguageLegal(sLang)
&& Implementation.isScriptLegal(sScript);
}
/**
* Add the specified implementation to the behavior.
*
* @param iImpl position for the new implementation (0 to insert at the
* beginning or -1 to add to end of the execution "chain")
* @param sLang implementation language
* @param sScript implementation script
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public Implementation addImplementation(int iImpl, String sLang, String sScript)
throws PropertyVetoException
{
return addImplementation(iImpl, sLang, sScript, true);
}
/**
* Add the specified implementation to the behavior.
*
* @param iImpl position for the new implementation (0 to insert at
* the beginning or -1 to add to end of the execution
* "chain")
* @param sLang implementation language
* @param sScript implementation script
* @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 Implementation addImplementation(int iImpl, String sLang, String sScript, boolean fVetoable)
throws PropertyVetoException
{
// verify implementation can be added
if (fVetoable && !isImplementationAddable(iImpl, sLang, sScript))
{
subNotAddable(ATTR_IMPLEMENTATION, sScript);
}
// create implementation
Implementation impl = new Implementation(this, sLang, sScript);
impl.assignUID();
// notify veto listeners
if (fVetoable)
{
try
{
fireVetoableSubChange(impl, SUB_ADD);
}
catch (PropertyVetoException e)
{
impl.invalidate();
throw e;
}
}
// add implementation
if (iImpl < 0)
{
iImpl = getModifiableImplementationCount();
}
if (iImpl >= m_vectScript.size())
{
m_vectScript.addElement(impl);
}
else
{
m_vectScript.insertElementAt(impl, iImpl);
}
// check if abstract should be toggled to concrete automatically
if ((m_nFlags & IMPL_MASK) == IMPL_ABSTRACT &&
(m_nPrevFlags & IMPL_MASK) == IMPL_ABSTRACT &&
isFromSuper())
{
setAbstract(false, false);
}
// notify listeners
fireSubChange(impl, SUB_ADD);
return impl;
}
/**
* Store the specified implementation on the JCS behavior.
*
* @param sLang implementation language
* @param sScript implementation script
*/
void setJcsImplementation(String sLang, String sScript)
{
azzert(sLang.indexOf('(') != -1);
// create implementation
Implementation impl = new Implementation(this, sLang, sScript);
impl.assignUID();
removeJcsImplementation(); // provides idempotency
m_vectScript.addElement(impl);
++m_cBaseLevelImpl; // assumed to be at base level
}
/**
* Remove the JCS implementation.
*/
void removeJcsImplementation()
{
Vector vectScript = m_vectScript;
if (vectScript.isEmpty())
{
return;
}
int iScript = vectScript.size() - 1;
if (isJcsImplementation(iScript))
{
vectScript.remove(iScript);
if (m_cBaseLevelImpl > 0)
{
--m_cBaseLevelImpl;
}
}
}
/**
* Check whether the implementation at the specified index
* is an added "synthetic" implementation
*
* @return true if the implementation at the specified index
* is an added implementation; false otherwise
*
* @see #setJcsImplementation(String, String)
*/
private boolean isJcsImplementation(int iImpl)
{
Implementation impl = (Implementation) m_vectScript.get(iImpl);
return impl.getLanguage().indexOf('(') != -1;
}
/**
* Determine if a implementation can be removed from the behavior.
*
* @param iImpl position of the implementation to remove
*
* @return true if it is possible to remove the specified implementation
*/
public boolean isImplementationRemovable(int iImpl)
{
return isImplementationSettable()
&& iImpl >= 0
&& iImpl < getModifiableImplementationCount();
}
/**
* Remove the specified implementation from the behavior.
*
* @param iImpl the implementation index to remove
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void removeImplementation(int iImpl)
throws PropertyVetoException
{
removeImplementation(iImpl, true);
}
/**
* Remove the specified implementation from the behavior.
*
* @param iImpl the implementation index to remove
* @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 removeImplementation(int iImpl, boolean fVetoable)
throws PropertyVetoException
{
// get the implementation
Implementation impl = null;
try
{
impl = getImplementation(iImpl);
}
catch (IndexOutOfBoundsException e)
{
if (fVetoable)
{
// the caller handed us garbage (so report garbage)
subNotRemovable(ATTR_PARAMETER, e);
}
return;
}
if (fVetoable)
{
// verify the implementation can be removed
if (!isImplementationRemovable(iImpl))
{
subNotRemovable(ATTR_IMPLEMENTATION, getImplementation(iImpl));
}
// notify veto listeners
fireVetoableSubChange(impl, SUB_REMOVE);
}
// remove the implementation
m_vectScript.removeElementAt(iImpl);
// check if abstract should be set automatically
if ((m_nFlags & IMPL_MASK) == IMPL_CONCRETE &&
(m_nPrevFlags & IMPL_MASK) == IMPL_ABSTRACT &&
isFromSuper())
{
setAbstract(true, false);
}
// notify listeners
fireSubChange(impl, SUB_REMOVE);
// discard the implementation
impl.invalidate();
}
/**
* Get position by implementation.
*
* @param impl the implementation to search for
*
* @return the implementation position, zero based, or -1 if not found
*/
public int getImplementationPosition(Implementation impl)
{
return m_vectScript.indexOf(impl);
}
// ----- override base
/**
* Determine if this modification level's implementations override (do not
* super to) the base level's implementations.
*
* @return true if the implementations at this modification level override
* (i.e. hide) the base implementations, false if this level's
* implementations supplement (super to) the base implementations
*/
public boolean isOverrideBase()
{
return m_fOverrideBase;
}
/**
* Specify implementation override to either override (do not super to)
* or supplement (allow super to) the base level's implementations.
*
* @param fOverride true if the implementations at this modification
* level should override (i.e. hide) the base
* implementations, false if this level's implement-
* ations supplement (super to) the base implementations
*
* @exception PropertyVetoException if the property cannot be set as
* specified or was vetoed by a property listener
*/
public void setOverrideBase(boolean fOverride)
throws PropertyVetoException
{
setOverrideBase(fOverride, true);
}
/**
* Specify implementation override to either override (do not super to)
* or supplement (allow super to) the base level's implementations.
*
* @param fOverride true if the implementations at this modification
* level should override (i.e. hide) the base
* implementations, false if this level's implement-
* ations supplement (super to) the base implementations
* @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 setOverrideBase(boolean fOverride, boolean fVetoable)
throws PropertyVetoException
{
boolean fPrev = isOverrideBase();
if (fOverride == fPrev)
{
return;
}
Boolean prev = toBoolean(fPrev);
Boolean value = toBoolean(fOverride);
if (fVetoable)
{
if (!isModifiable())
{
readOnlyAttribute(ATTR_OVERRIDEBASE, prev, value);
}
fireVetoableChange(ATTR_OVERRIDEBASE, prev, value);
}
m_fOverrideBase = fOverride;
firePropertyChange(ATTR_OVERRIDEBASE, prev, value);
}
// ----- synthetic
/**
* Determine whether this behavior was based on a compiler generated method
* (({@link Method#isBridge()} && {@link Method#isSynthetic()}).
*
* @return whether this behavior was based on a compiler generated method
*/
public boolean isSynthetic()
{
return (m_nFlags & MISC_ISINTERFACE) != 0;
}
// ----- helpers
/**
* Determine if the signature is reserved and cannot be used by this
* Behavior.
*
* @param sSig the proposed signature
*
* @return true if the signature cannot be used by this Behavior
*/
protected boolean isSignatureReserved(String sSig)
{
// check for conflict with other behavior names
Behavior behavior = getComponent().getBehavior(sSig);
if (behavior != null && behavior != this)
{
return true;
}
// verify that the signature is not reserved
return isSignatureReserved(getComponent(), sSig);
}
/**
* Determine if the specified signature is reserved within the
* specified Component.
*
* @param cd the Component
* @param sSig the proposed signature
*
* @return true if the signature cannot be used within the specified Component
*/
protected static boolean isSignatureReserved(Component cd, String sSig)
{
// gg 2001.5.3 -- no restrictions for a JCS
if (cd.isSignature())
{
return false;
}
// compiler reserves double-underscore names
if (sSig.startsWith("__"))
{
return true;
}
// check Property accessors
String sProp = Property.getPropertyName(sSig);
if (sProp != null)
{
Property prop = cd.getProperty(sProp);
if (prop != null)
{
if (prop.isReservedBehaviorSignature(sSig))
{
if (!sProp.equals(prop.getName()))
{
// case sensitivity conflict
return false;
}
// accessors from super levels could be private ... in
// which case the signature cannot be created at this
// level
if (prop.isFromSuper())
{
return false;
}
// the Behavior cannot be created if the accessor is not
// applicable
for (int i = Property.PA_FIRST; i <= Property.PA_LAST; ++i)
{
if (sSig.equals(prop.getAccessorSignature(i))
&& !prop.isAccessorApplicable(i))
{
return true;
}
}
}
}
}
return false;
}
/**
* Parse the behavior signature into discrete return and parameter data
* types.
*
* @param sSig the behavior signature
*
* @return an array of DataType instances, where [0] is the return
* type and [1]..[c] are the parameter types.
*/
public static DataType[] getParameterTypes(String sSig)
{
return DataType.parseSignature(sSig);
}
// ----- Object methods -------------------------------------------------
/**
* Compare this Behavior to another Object for equality.
*
* @param obj the other Object to compare to this
*
* @return true if this Behavior equals that Object
*/
public boolean equals(Object obj)
{
if (obj instanceof Behavior)
{
Behavior that = (Behavior) obj;
return this == that
|| this.m_nFlags == that.m_nFlags
&& this.m_nPrevFlags == that.m_nPrevFlags
&& this.m_fOverrideBase == that.m_fOverrideBase
&& this.m_cBaseLevelImpl == that.m_cBaseLevelImpl
&& this.m_sName .equals(that.m_sName )
&& this.m_sSig .equals(that.m_sSig )
&& this.m_retval .equals(that.m_retval )
&& this.m_tblExcept .equals(that.m_tblExcept )
&& this.m_vectParam .equals(that.m_vectParam )
&& this.m_vectScript.equals(that.m_vectScript)
&& super.equals(that);
// PJM Removed the following because they are not persistent fields
//&& this.m_fPrevOverrideBase == that.m_fPrevOverrideBase
}
return false;
}
/**
* Provide a human-readable description of the behavior.
*
* @return a string describing the behavior
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
if (m_retval != null && !isConstructor())
{
sb.append(m_retval.getDataType().toString())
.append(' ');
}
sb.append(m_sName)
.append('(');
int c = getParameterCount();
for (int i = 0; i < c; ++i)
{
if (i > 0)
{
sb.append(", ");
}
Parameter parameter = getParameter(i);
sb.append(parameter.getDataType().toString());
sb.append(" " + parameter.getName());
}
sb.append(')');
return sb.toString();
}
// ----- debugging ------------------------------------------------------
/**
* 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)
{
boolean fDerOrMod = (getMode() == MODIFICATION || getMode() == DERIVATION);
out.println(sIndent + "Behavior " + toString());
out.println(sIndent + "Signature=\"" + m_sSig + '\"');
super.dump(out, sIndent);
// Exists, Access, Visible, Synchronized, Abstract, Static, Final,
// Deprecated, Remotable
out.print (sIndent + "flags=0x" + Integer.toHexString(m_nFlags));
out.println(" (" + flagsDescription(m_nFlags, SPECABLE_FLAGS, fDerOrMod) + ')');
out.print (sIndent + "previous flags=0x" + Integer.toHexString(m_nPrevFlags));
out.println(" (" + flagsDescription(m_nPrevFlags, SPECABLE_FLAGS, fDerOrMod) + ')');
// return value
out.print(sIndent + "Return Value:");
if (m_retval == null)
{
out.println(" ");
}
else
{
out.println();
m_retval.dump(out, nextIndent(sIndent));
}
// parameters
out.println(sIndent + m_vectParam.size() + " parameter(s)");
int i = 0;
for (Enumeration enmr = m_vectParam.elements(); enmr.hasMoreElements(); )
{
Parameter param = (Parameter) enmr.nextElement();
out.print(sIndent + "Parameter " + (++i) + ":");
if (param == null)
{
out.println(" ");
}
else
{
out.println();
param.dump(out, nextIndent(sIndent));
}
}
// exceptions
out.println(sIndent + m_tblExcept.getSize() + " exception(s)");
for (Enumeration enmr = m_tblExcept.keys(); enmr.hasMoreElements(); )
{
String sExcept = (String) enmr.nextElement();
Throwee except = (Throwee) m_tblExcept.get(sExcept);
out.print(sIndent + "Exception \"" + sExcept + "\":");
if (except == null)
{
out.println(" ");
}
else
{
out.println();
except.dump(out, nextIndent(sIndent));
}
}
// implementations
out.print (sIndent + m_vectScript.size() + " implementation(s), ");
out.print (m_cBaseLevelImpl + " at the base level (");
out.println((m_fOverrideBase ? "overridden" : "supplemented") + ')');
i = 0;
for (Enumeration enmr = m_vectScript.elements(); enmr.hasMoreElements(); )
{
Implementation impl = (Implementation) enmr.nextElement();
out.print(sIndent + "Implementation " + (++i) + ":");
if (impl == null)
{
out.println(" ");
}
else
{
out.println();
impl.dump(out, nextIndent(sIndent));
}
}
}
// ----- public constants ----------------------------------------------
/**
* The FromManual attribute.
*/
public static final String ATTR_FROMMANUAL = "FromManual";
/**
* The Accessibility attribute.
*/
public static final String ATTR_ACCESS = "Access";
/**
* The Visible attribute.
*/
public static final String ATTR_VISIBLE = "Visible";
/**
* The Synchronized attribute.
*/
public static final String ATTR_SYNCHRONIZED = "Synchronized";
/**
* The Static attribute.
*/
public static final String ATTR_STATIC = "Static";
/**
* The Abstract attribute.
*/
public static final String ATTR_ABSTRACT = "Abstract";
/**
* The Final attribute.
*/
public static final String ATTR_FINAL = "Final";
/**
* The Deprecated attribute name.
*/
public static final String ATTR_DEPRECATED = "Deprecated";
/**
* The Remote attribute name.
*/
public static final String ATTR_REMOTE = "Remote";
/**
* The Name attribute.
*/
public static final String ATTR_NAME = "Name";
/**
* The Parameter attribute.
*/
public static final String ATTR_PARAMETER = "Parameter";
/**
* The Exception attribute.
*/
public static final String ATTR_EXCEPTION = "Exception";
/**
* The Implementation attribute.
*/
public static final String ATTR_IMPLEMENTATION = "Implementation";
/**
* The OverrideBase attribute.
*/
public static final String ATTR_OVERRIDEBASE = "OverrideBase";
// ----- data members ---------------------------------------------------
/**
* The name of this class.
*/
private static final String CLASS = "Behavior";
/**
* The Behavior's descriptor string.
*/
protected static final String DESCRIPTOR = CLASS;
/**
* The default flags for the Behavior Trait.
*/
private static final int DEFAULT_FLAGS = VIS_VISIBLE |
SYNC_NOMONITOR |
IMPL_CONCRETE |
DERIVE_DERIVABLE |
ANTIQ_CURRENT |
DIST_LOCAL;
/**
* The flags that the Behavior Trait can specify.
*/
private static final int SPECABLE_FLAGS = EXISTS_SPECIFIED |
ACCESS_SPECIFIED |
VIS_SPECIFIED |
SYNC_SPECIFIED |
IMPL_SPECIFIED |
SCOPE_SPECIFIED |
DERIVE_SPECIFIED |
ANTIQ_SPECIFIED |
DIST_SPECIFIED;
/**
* Flags that will cause a Behavior Trait to force compilation if modified.
*/
private static final int CLASSGEN_FLAGS = ACCESS_MASK |
VIS_MASK |
SYNC_MASK |
IMPL_MASK |
SCOPE_MASK |
DERIVE_MASK |
ANTIQ_MASK |
DIST_MASK;
/**
* Parameter name for event listeners.
*/
private static final String[] EVENT_REG_PARAM = new String[] {"l"};
// ----- attributes
/**
* The behavior's name.
*/
private String m_sName;
/**
* The behavior's signature (cached).
*/
private String m_sSig;
/**
* Behavior attributes which are represented by bit flags, specifically
* the Visible, Access, Synchronized, Static, Abstract, Final, Deprecated,
* and Remotable attributes.
*
* @see com.tangosol.dev.component.Constants
*/
private int m_nFlags = DEFAULT_FLAGS;
/**
* The legal ranges for this Behavior's attribute flags may be dependent
* on the super (in the case of derivation) or base (in the case of
* modification); those values are stored here for reference.
*/
private int m_nPrevFlags = DEFAULT_FLAGS;
/**
* The behavior's return value.
*/
private ReturnValue m_retval;
/**
* The behavior's parameters.
*/
private Vector m_vectParam = new Vector();
/**
* The behavior's declared exceptions.
*/
private StringTable m_tblExcept = new StringTable();
/**
* The behavior's implementation (scripts). The order of the vector
* reflects the order of "virtual method" execution in Java. In other
* words, the 0 element is executed, and if it super's, the 1 element
* is executed, and so on. The vector contains scripts only from this
* derivation level (i.e. from this behavior and any modified base, but
* not from a derived base aka "super"). This reflects .class generation
* where a .class corresponds to a component, so all implementations at
* a derivation level are incorporated into the .class.
*/
private Vector m_vectScript = new Vector();
/**
* The number of implementations that do not belong to this behavior's
* modification level. These are the implementations which have null
* modifications applied when the behavior is resolved. They are
* immutable at this level. They can be "hidden" by setting the
* override-base attribute of the behavior.
*/
private int m_cBaseLevelImpl;
/**
* Does this behavior's modification level override (i.e. replace instead
* of supplement) base implementations. If true, the implementations from
* modified base behaviors are not "reachable".
*/
private boolean m_fOverrideBase;
/**
* The previous override of the implementations; this value is used only
* during resolve processing.
*/
private transient boolean m_fPrevOverrideBase;
}