
com.tangosol.dev.component.Throwee Maven / Gradle / Ivy
/*
* 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 java.beans.PropertyVetoException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import com.tangosol.util.ErrorList;
import com.tangosol.run.xml.XmlElement;
/**
* A Throwee describes a Java exception which is declared (i.e. potentially
* thrown) by a Behavior.
*
* @version 0.50, 12/16/97
* @version 1.00, 08/13/98
* @author Cameron Purdy
*/
public class Throwee
extends Trait
{
// ----- construction ---------------------------------------------------
/**
* Construct a Throwee. This is the "default" constructor.
*
* @param behavior the behavior that declares this exception throwable
* @param dt the exception data type
*/
protected Throwee(Behavior behavior, DataType dt)
{
super(behavior, RESOLVED);
// assertion: behavior required
if (behavior == null)
{
throw new IllegalArgumentException(CLASS +
": Containing behavior required.");
}
// verify that the data type is a Java class; there is no way to
// verify that it ultimately derives from java.lang.Exception
if (dt == null || !dt.isClass())
{
throw new IllegalArgumentException(CLASS +
": Illegal Throwee DataType (" + dt + ")");
}
m_dt = dt;
m_nFlags = EXISTS_INSERT;
// all exceptions of non-Signature Behaviors require a UID
if (!behavior.getComponent().isSignature())
{
assignUID();
}
}
/**
* Construct a blank Throwee Trait.
*
* @param base the base Throwee to derive from
* @param behavior the containing behavior
* @param nMode one of RESOLVED, DERIVATION, MODIFICATION
*
* @see #getBlankDerivedTrait(Trait, int)
*/
protected Throwee(Throwee base, Behavior behavior, int nMode)
{
super(base, behavior, nMode);
this.m_dt = base.m_dt;
this.m_nFlags = EXISTS_UPDATE;
}
/**
* Copy constructor.
*
* @param behavior the Behavior containing the new Throwee
* @param that the Throwee to copy from
*/
protected Throwee(Behavior behavior, Throwee that)
{
super(behavior, that);
this.m_dt = that.m_dt;
this.m_nFlags = that.m_nFlags;
}
/**
* Construct a Throwee from a stream.
*
* This is a custom serialization implementation that is unrelated to the
* Serializable interface and the Java implementation of persistence.
*
* @param behavior the containing behavior
* @param stream the stream to read this Behavior Exception from
* @param nVersion version of the data structure in the stream
*
* @exception IOException An IOException is thrown if an error occurs
* reading the Behavior Exception from the stream or if the
* stream does not contain a valid Behavior Exception
*/
protected Throwee(Behavior behavior, DataInput stream, int nVersion)
throws IOException
{
super(behavior, stream, nVersion);
m_nFlags = stream.readInt();
m_dt = DataType.getType(stream.readUTF());
}
/**
* 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 Throwee(Trait parent, XmlElement xml, int nVersion)
throws IOException
{
super(parent, xml, nVersion);
String sType = readString(xml.getElement("type"));
if (sType == BLANK)
{
throw new IOException("type is missing");
}
int nFlags = readFlags(xml, "flags", EXISTS_UPDATE);
m_dt = DataType.getType(sType);
m_nFlags = nFlags;
}
// ----- persistence ----------------------------------------------------
/**
* Save the Behavior Exception 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 Exception to
*
* @exception IOException An IOException is thrown if an error occurs
* writing the Behavior Exception to the stream
*/
protected synchronized void save(DataOutput stream)
throws IOException
{
super.save(stream);
stream.writeInt(m_nFlags);
stream.writeUTF(m_dt.getTypeString());
}
/**
* 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
{
xml.addElement("type").setString(m_dt.getTypeString());
super.save(xml);
saveFlags(xml, "flags", m_nFlags, EXISTS_UPDATE);
}
// ----- derivation/modification ----------------------------------------
/**
* Construct a blank Throwee from this base.
*
* @param parent the containing behavior
* @param nMode RESOLVED, DERIVATION or MODIFICATION
*
* @return a new blank derived trait of this trait's class with the
* specified parent and mode
*/
protected Trait getBlankDerivedTrait(Trait parent, int nMode)
{
return new Throwee(this, (Behavior) parent, nMode);
}
/**
* 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.
*
* @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
{
Throwee base = this;
Throwee delta = (Throwee) resolveDelta(traitDelta, loader, errlist);
Throwee derived = (Throwee) super.resolve(delta, parent, loader, errlist);
// Exists
int nBaseFlags = base .m_nFlags;
int nDeltaFlags = delta.m_nFlags;
int nDerivedFlags = nDeltaFlags;
if (base.getMode() == RESOLVED)
{
// when an exception is declared, it has the exists state of INSERT
// and subsequent derivation/modification levels are UPDATE
// when an exception is removed, it has the exists state of DELETE
// and subsequent derivation/modification levels are NOT
int nBaseExists = nBaseFlags & EXISTS_MASK;
if (nBaseExists == EXISTS_DELETE || nBaseExists == EXISTS_NOT)
{
nDerivedFlags = EXISTS_NOT;
}
else if ((nDeltaFlags & EXISTS_SPECIFIED) == 0)
{
nDerivedFlags = EXISTS_UPDATE;
}
}
else
{
// modifying a derivation or modification: use the base level's
// exists information if no exists information is present at this
// level
if ((nDeltaFlags & EXISTS_SPECIFIED) == 0 &&
(nBaseFlags & EXISTS_SPECIFIED) != 0)
{
nDerivedFlags = nBaseFlags;
}
}
derived.m_nFlags = nDerivedFlags;
// check for data type mismatch
if (delta.m_dt != base.m_dt)
{
Object[] aoParam = new Object[]
{
base.getBehavior().toString(),
delta.m_dt.toString(),
base.m_dt.toString(),
derived.toPathString()
};
logError(RESOLVE_EXCEPTTYPECHANGE, WARNING, aoParam, errlist);
}
// the exception type must match the base
derived.m_dt = base.m_dt;
return derived;
}
/**
* Finalize the resolve process. This means that this trait will not
* be asked to resolve again. A trait is considered designable after
* it has finalized the resolve process.
*
* @param loader the Loader object for JCS, CIM, and CD dependencies
* @param errlist the error list object to log error information to
*
* @exception ComponentException thrown only if a fatal error occurs
*/
protected void finalizeResolve(Loader loader, ErrorList errlist)
throws ComponentException
{
super.finalizeResolve(loader, errlist);
// specified flags are only for deltas
m_nFlags &= ~EXISTS_SPECIFIED;
// if this is declared at this level, make sure it is an insert
if (isDeclaredAtThisLevel() && m_nFlags != EXISTS_DELETE)
{
m_nFlags = EXISTS_INSERT;
}
}
/**
* 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
{
Throwee derived = this;
Throwee base = (Throwee) traitBase;
Throwee delta = (Throwee) super.extract(base, parent, loader, errlist);
// Exists: if the throwee is removed at this level, then a DELETE is
// specified in the derivation/modification, otherwise exists is not
// specified
if ((derived.m_nFlags & EXISTS_MASK) == EXISTS_DELETE
&& (base.m_nFlags == EXISTS_INSERT || base.m_nFlags == EXISTS_UPDATE)
&& (base.getMode() == RESOLVED || (derived.m_nFlags & EXISTS_SPECIFIED) != 0))
{
delta.m_nFlags = EXISTS_SPECIFIED | EXISTS_DELETE;
}
else
{
delta.m_nFlags = EXISTS_UPDATE;
}
// check for data type mismatch
if (derived.m_dt != base.m_dt)
{
Object[] aoParam = new Object[]
{
base.getBehavior().toString(),
derived.m_dt.toString(),
base.m_dt.toString(),
derived.toPathString()
};
logError(EXTRACT_EXCEPTTYPECHANGE, WARNING, aoParam, errlist);
}
// redundantly keep the base level's data type information
// in order to check for mismatch on resolve
delta.m_dt = base.m_dt;
return delta;
}
/**
* Determines if this exception exists for any reason at all. If an
* exception exists, for example, as part of an interface, and the
* interface changes, removing the exception, then the exception will be
* discarded as part of the Behavior's resolve finalization processing.
*
* @return true if the Behavior Exception can be discarded
*/
protected boolean isDiscardable()
{
int nMode = getMode();
if (nMode == DERIVATION || nMode == MODIFICATION)
{
// delta is not discardable if EXISTS is specified
if ((m_nFlags & EXISTS_SPECIFIED) != 0)
{
return false;
}
}
return super.isDiscardable();
}
/**
* Determine whether this trait contains information that would cause
* generation of a class that would operate differently than the class
* generated from the information maintained by the super trait.
*
* @param base the base (i.e. the super) Trait to compare to
*
* @return true if a delta between this trait and its super trait means
* that class generation should generate the class corresponding
* to this trait, otherwise false
*/
protected boolean isClassDiscardable(Trait base)
{
Throwee that = (Throwee) base;
if (that == null || !isFromSuper())
{
return false;
}
int nExistsThis = (this.m_nFlags & EXISTS_MASK);
int nExistsThat = (that.m_nFlags & EXISTS_MASK);
if (nExistsThis != nExistsThat)
{
boolean fThisThrowable = (nExistsThis == EXISTS_INSERT || nExistsThis == EXISTS_UPDATE);
boolean fThatThrowable = (nExistsThat == EXISTS_INSERT || nExistsThat == EXISTS_UPDATE);
if (fThisThrowable != fThatThrowable)
{
return false;
}
}
return super.isClassDiscardable(base);
}
// ----- miscellaneous Trait methods ------------------------------------
/**
* Reset state, discarding all information.
*/
protected synchronized void invalidate()
{
super.invalidate();
m_dt = 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()
{
return m_dt.getClassName();
}
/**
* 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 behavior which contains this Behavior Exception.
*
* @return the behavior trait that contains this Behavior Exception
*/
public Behavior getBehavior()
{
return (Behavior) getParentTrait();
}
// ----- exists
/**
* Access the Behavior Exception exists flag. This is only used
* internally by the Component Definition.
*
* @return the enumerated exists flag
*/
protected int getExists()
{
return m_nFlags;
}
/**
* Set the Behavior Exception exists flag. This is only used internally
* by the Component Definition.
*
* @param nExists the new exists flag for the Behavior Exception
*/
protected synchronized void setExists(int nExists)
{
m_nFlags = (nExists & EXISTS_MASK);
}
// ----- origin: exception implements interface(s)
/**
* Determine if this exception is from an interface.
*
* @return true if this exception 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 exception.
*
* @return an enumeration of interface names
*/
public Enumeration enumImplements()
{
return getOriginTraits(Interface.DESCRIPTOR_IMPLEMENTS);
}
// ----- origin: exception dispatches interface(s)
/**
* Determine if this exception is from a dispatched interface.
*
* @return true if this exception 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 exception.
*
* @return an enumeration of dispatch interface names
*/
public Enumeration enumDispatches()
{
return getOriginTraits(Interface.DESCRIPTOR_DISPATCHES);
}
// ----- origin: exception integrates
/**
* Determine if this exception exists as a result of integration at this
* level.
*
* @return true if this exception results from integration at this level
*/
public boolean isFromIntegration()
{
return isFromTraitDescriptor(Integration.DESCRIPTOR);
}
// ----- origin: exception from a property
/**
* Determine if this exception exists due to a property.
*
* @return true if this exception results from a property
*/
public boolean isFromProperty()
{
return isFromTraitDescriptor(Property.DESCRIPTOR);
}
// ----- origin: exception declared "manually"
/**
* Determine if the manual origin flag can be set. It cannot be set if
* the exception'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 exception 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 exception 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);
}
// ----- throwable
/**
* A Behavior may not be able to throw all of its declared exceptions.
* Even if an exception cannot be thrown, the details of the exception
* and its origin are maintained.
*
* For example, if a Behavior is declared by two interfaces which each
* declare a different exception, the Behavior may throw neither.
*
* @return true if the exception is throwable
*/
public boolean isThrowable()
{
int nExists = getExists();
return (nExists == EXISTS_INSERT || nExists == EXISTS_UPDATE);
}
// ----- data type
/**
* Access the Behavior Exception data type.
*
* @return the data type of the Behavior Exception
*/
public DataType getDataType()
{
return m_dt;
}
/**
* Determine if the Behavior Exception data type can be set. The Behavior Exception
* data type 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 data type of the Behavior Exception can be set
*/
public boolean isDataTypeSettable()
{
return isModifiable() && !isFromNonManual();
}
/**
* Determine if the specified data type is a legal data type value for
* this Behavior Exception.
*
* @return true if the specified data type is legal for this Behavior Exception
*/
public boolean isDataTypeLegal(DataType dt)
{
// data type is required and must be a Java class; there is no way
// at this point to verify if the type is a Java exception class
if (dt == null || !dt.isClass())
{
return false;
}
// check for no change
if (dt == m_dt)
{
return true;
}
Throwee except = getBehavior().getException(dt.getClassName());
return except == null || except == this;
}
/**
* Set the Behavior Exception data type.
*
* @param dt the new data type for the Behavior Exception
*/
public void setDataType(DataType dt)
throws PropertyVetoException
{
setDataType(dt, true);
}
/**
* Set the Behavior Exception data type.
*
* @param dt the new data type for the Behavior Exception
* @param fVetoable true if the setter can veto the value
*/
protected synchronized void setDataType(DataType dt, boolean fVetoable)
throws PropertyVetoException
{
DataType dtPrev = m_dt;
if (dt == dtPrev)
{
return;
}
if (fVetoable)
{
if (!isDataTypeSettable())
{
readOnlyAttribute(ATTR_DATATYPE, dtPrev, dt);
}
if (!isDataTypeLegal(dt))
{
illegalAttributeValue(ATTR_DATATYPE, dtPrev, dt);
}
fireVetoableChange(ATTR_DATATYPE, dtPrev, dt);
}
m_dt = dt;
// update the behavior's exception table
getBehavior().renameException(dtPrev.getClassName(), dt.getClassName());
firePropertyChange(ATTR_DATATYPE, dtPrev, dt);
}
// ----- Object methods -------------------------------------------------
/**
* Compare this Throwee to another Object for equality.
*
* @param obj the other Object to compare to this
*
* @return true if this Throwee equals that Object
*/
public boolean equals(Object obj)
{
if (obj instanceof Throwee)
{
Throwee that = (Throwee) obj;
return this == that
|| this.m_nFlags == that.m_nFlags
&& this.m_dt == that.m_dt
&& super.equals(that);
}
return false;
}
// ----- 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 + "Exception " + (m_dt == null ? "" : m_dt.toString()));
out.print (sIndent + "flags=0x" + Integer.toHexString(m_nFlags));
out.println(" (" + flagsDescription(m_nFlags, SPECABLE_FLAGS, fDerOrMod) + ')');
super.dump(out, sIndent);
}
// ----- public constants ----------------------------------------------
/**
* The FromManual attribute.
*/
public static final String ATTR_FROMMANUAL = "FromManual";
/**
* The DataType attribute.
*/
public static final String ATTR_DATATYPE = "DataType";
// ----- other constants ------------------------------------------------
/**
* The name of this class.
*/
private static final String CLASS = "Throwee";
/**
* The Throwee's descriptor string.
*/
protected static final String DESCRIPTOR = "Exception";
/**
* The flags that the Throwee Trait can specify.
*/
private static final int SPECABLE_FLAGS = EXISTS_SPECIFIED;
// ----- data members ---------------------------------------------------
/**
* The Behavior Exception's data type.
*/
private DataType m_dt;
/**
* The Behavior Exception has various attributes stored as bit flags.
* The attributes are: Exists.
*/
private int m_nFlags;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy