axis-java-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n...@apache.org
Subject svn commit: r495106 [4/10] - in /webservices/axis2/trunk/java/modules: integration/ integration/test/org/apache/axis2/engine/ integration/test/org/apache/axis2/mtom/ kernel/src/org/apache/axis2/addressing/ kernel/src/org/apache/axis2/client/ kernel/src...
Date Thu, 11 Jan 2007 04:04:33 GMT
Modified: webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/OperationContext.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/OperationContext.java?view=diff&rev=495106&r1=495105&r2=495106
==============================================================================
--- webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/OperationContext.java (original)
+++ webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/OperationContext.java Wed Jan 10 20:04:31 2007
@@ -19,9 +19,25 @@
 
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.description.AxisOperation;
+import org.apache.axis2.description.AxisService;
+import org.apache.axis2.engine.AxisConfiguration;
+import org.apache.axis2.util.ObjectStateUtils;
+import org.apache.axis2.util.MetaDataEntry;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
+import javax.xml.namespace.QName;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * An OperationContext represents a running "instance" of an operation, which is
@@ -31,27 +47,143 @@
  * exchanged the OperationContext remembers the state of where in the message
  * exchange pattern it is in.
  * <p/>
- * OperationContextFactory factory. The base implementation of OperationContext
+ * The base implementation of OperationContext
  * supports MEPs which have one input message and/or one output message. That
  * is, it supports the all the MEPs that are in the WSDL 2.0 specification. In
  * order to support another MEP one must extend this class and register its
  * creation in the OperationContexFactory.
  */
-public class OperationContext extends AbstractContext {
+public class OperationContext extends AbstractContext implements Externalizable {
+
+    /*
+     * setup for logging
+     */
+    private static final Log log = LogFactory.getLog(OperationContext.class);
+
+    private static final String myClassName = "OperationContext";
+
+    /**
+     * @serial The serialization version ID tracks the version of the class.
+     * If a class definition changes, then the serialization/externalization
+     * of the class is affected. If a change to the class is made which is
+     * not compatible with the serialization/externalization of the class,
+     * then the serialization version ID should be updated.
+     * Refer to the "serialVer" utility to compute a serialization
+     * version ID.
+     */
+    private  static final long serialVersionUID = -7264782778333554350L;
+
+    /**
+     * @serial Tracks the revision level of a class to identify changes to the 
+     * class definition that are compatible to serialization/externalization.
+     * If a class definition changes, then the serialization/externalization
+     * of the class is affected. 
+     * Refer to the writeExternal() and readExternal() methods.
+     */
+    // supported revision levels, add a new level to manage compatible changes
+    private static final int REVISION_1 = 1;
+    // current revision level of this object
+    private static final int revisionID = REVISION_1;
+
+
+    /**
+     * @serial isComplete flag
+     */
     private boolean isComplete;
 
+    /**
+     * @serial key string
+     */
     //The key value of the operationContextMap;
     private String key;
 
     // the AxisOperation of which this is a running instance. The MEP of this
     // AxisOperation must be one of the 8 predefined ones in WSDL 2.0.
     private transient AxisOperation axisOperation;
-    private HashMap messageContexts;
+
+    /**
+     * the set of message contexts associated with this operation
+     */
+    private transient HashMap messageContexts;
 
     // this is the global MessageID -> OperationContext map which is stored in
     // the EngineContext. We're caching it here for faster access.
-    private Map operationContextMap;
+    private transient Map operationContextMap;
+
+
+    //----------------------------------------------------------------
+    // MetaData for data to be restored in activate after readExternal
+    //----------------------------------------------------------------
+    
+    /**
+     * Indicates whether the message context has been reconstituted
+     * and needs to have its object references reconciled
+     */
+    private transient boolean needsToBeReconciled = false;
+
+    /**
+     * Suppresses warning messages for activation
+     * when doing internal reconciliation
+     */
+    private transient boolean suppressWarnings = false;
+
+    /**
+     * The AxisOperation metadata will be used during
+     * activate to match up with an existing object
+     */
+    private transient MetaDataEntry metaAxisOperation = null;
+    
+    /**
+     * The AxisService metadata will be used during
+     * activate to match up with an existing object
+     */
+    private transient MetaDataEntry metaAxisService = null;
+    
+    /**
+     * The ServiceContext metadata will be used during
+     * activate to match up with an existing object
+     */
+    private transient ServiceContext metaParent = null;
+    
+
+    /**
+     * This is used to hold information about message context objects
+     * that are in the messageContexts map.  This allows message context
+     * objects to be isolated from the object graph so that duplicate
+     * copies of objects are not saved/restored.
+     */
+    private HashMap metaMessageContextMap = null;
+
+    /**
+     * This is used to hold temporarily any message context objects
+     * that were isolated from the messageContexts map. 
+     */
+    private transient HashMap isolatedMessageContexts = null;
+
+    /**
+     * This is used to hold temporarily any message context objects
+     * from the messageContexts map for save/restore activities.
+     */
+    private transient HashMap workingSet = null;
+
+    //----------------------------------------------------------------
+    // end MetaData section
+    //----------------------------------------------------------------
 
+    /**
+     *  Simple constructor
+     */
+    public OperationContext() {
+        super(null);
+        this.messageContexts = new HashMap();
+    }
+
+
+
+
+    /**
+     *  Constructs a new OperationContext associated with the specified AxisOperation
+     */
     public OperationContext(AxisOperation axisOperation) {
         super(null);
         this.messageContexts = new HashMap();
@@ -71,9 +203,15 @@
         super(serviceContext);
         this.messageContexts = new HashMap();
         this.axisOperation = axisOperation;
-        this.operationContextMap =
-                getServiceContext().getConfigurationContext()
-                        .getOperationContextMap();
+
+        ServiceContext serv = getServiceContext();
+
+        if (serv != null)
+        {
+            this.operationContextMap =
+                    serv.getConfigurationContext()
+                            .getOperationContextMap();
+        }
     }
 
     /**
@@ -104,6 +242,15 @@
      */
     public void cleanup() {
         if (key != null) {
+            if (operationContextMap == null) {
+                ServiceContext serv = getServiceContext();
+
+                if (serv != null) {
+                    this.operationContextMap =
+                            serv.getConfigurationContext()
+                                    .getOperationContextMap();
+                }
+            }
             operationContextMap.remove(key);
         }
     }
@@ -112,6 +259,13 @@
      * @return Returns the axisOperation.
      */
     public AxisOperation getAxisOperation() {
+        if (needsToBeReconciled && !suppressWarnings) {
+            if (log.isWarnEnabled()) {
+                log.warn(myClassName+":getAxisOperation(): ****WARNING**** OperationContext.activate(configurationContext) needs to be invoked.");
+            }
+            //System.out.println(myClassName+":getAxisOperation(): ****WARNING**** OperationContext.activate(configurationContext) needs to be invoked.");
+        }
+
         return axisOperation;
     }
 
@@ -121,9 +275,17 @@
      * @return Returns parent ServiceContext's parent EngineContext.
      */
     public ConfigurationContext getConfigurationContext() {
-        return ((ServiceContext) parent).getConfigurationContext();
+        if (parent != null)
+        {
+            return ((ServiceContext) parent).getConfigurationContext();
+        }
+        else
+        {
+            return null;
+        }
     }
 
+
     /**
      * @param messageLabel
      * @return Returns MessageContext.
@@ -131,7 +293,13 @@
      */
     public MessageContext getMessageContext(String messageLabel)
             throws AxisFault {
-        return (MessageContext) messageContexts.get(messageLabel);
+        if (messageContexts == null) {
+            return null;
+        }
+
+        MessageContext mc = (MessageContext) messageContexts.get(messageLabel); 
+
+        return mc;
     }
 
     public HashMap getMessageContexts() {
@@ -161,12 +329,919 @@
 
     public void setParent(AbstractContext context) {
         super.setParent(context);
-        this.operationContextMap =
-                getServiceContext().getConfigurationContext()
-                        .getOperationContextMap();
+
+        ServiceContext serv = getServiceContext();
+
+        if (serv != null) {
+            this.operationContextMap =
+                    serv.getConfigurationContext()
+                            .getOperationContextMap();
+        }
     }
 
     public void setKey(String key) {
         this.key = key;
     }
+
+
+    /* ===============================================================
+     * Externalizable support 
+     * ===============================================================
+     */
+    
+
+    /**
+     * Save the contents of this object.
+     * <p>
+     * NOTE: Transient fields and static fields are not saved.
+     *       Also, objects that represent "static" data are
+     *       not saved, except for enough information to be
+     *       able to find matching objects when the message
+     *       context is re-constituted.
+     *
+     * @param out    The stream to write the object contents to
+     * 
+     * @exception IOException
+     */
+    public void writeExternal(ObjectOutput out) throws IOException
+    {
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":writeExternal():  BEGIN  ");
+        }
+        //System.out.println(myClassName+":writeExternal():  BEGIN  ");
+
+        //---------------------------------------------------------
+        // in order to handle future changes to the message 
+        // context definition, be sure to maintain the 
+        // object level identifiers
+        //---------------------------------------------------------
+        // serialization version ID
+        out.writeLong(serialVersionUID);
+
+        // revision ID
+        out.writeInt(revisionID);
+
+        //---------------------------------------------------------
+        // various simple fields
+        //---------------------------------------------------------
+
+        out.writeLong(getLastTouchedTime());
+
+        out.writeBoolean(isComplete);
+
+        ObjectStateUtils.writeString(out, key, "OperationContext.key");
+
+        //---------------------------------------------------------
+        // properties
+        //---------------------------------------------------------
+        Map tmpMap = getProperties();
+
+        HashMap tmpHashMap = null;
+
+        if ((tmpMap != null) && (tmpMap.isEmpty()==false))
+        {
+            tmpHashMap = new HashMap(tmpMap);
+        }
+
+        ObjectStateUtils.writeHashMap(out, tmpHashMap, "OperationContext.properties");
+
+
+        //---------------------------------------------------------
+        // AxisOperation axisOperation
+        //---------------------------------------------------------
+        String axisOpMarker = "OperationContext.axisOperation";
+        ObjectStateUtils.writeString(out, axisOpMarker, axisOpMarker);
+
+        if (axisOperation == null)
+        {
+        	out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
+        }
+        else
+        {
+        	out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
+        	metaAxisOperation = new MetaDataEntry(axisOperation.getClass().getName(), axisOperation.getName().toString());
+        	ObjectStateUtils.writeObject(out, metaAxisOperation, "OperationContext.metaAxisOperation");
+        }
+
+        // save the meta data for the corresponding axis service to better
+        // match up the axis operation 
+
+        String axisServMarker = "OperationContext.metaAxisService";
+        ObjectStateUtils.writeString(out, axisServMarker, axisServMarker);
+
+        AxisService axisService = (AxisService) axisOperation.getParent();
+
+        if (axisService == null)
+        {
+        	out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
+        }
+        else
+        {
+        	out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
+        	metaAxisService = new MetaDataEntry(axisService.getClass().getName(), axisService.getName().toString());
+        	ObjectStateUtils.writeObject(out, metaAxisService, "OperationContext.metaAxisService");
+        }
+        
+
+        //---------------------------------------------------------
+        // parent 
+        //---------------------------------------------------------
+        ServiceContext myParent = (ServiceContext) this.getServiceContext();
+
+        ObjectStateUtils.writeObject(out, myParent, "OperationContext.parent ServiceContext"); 
+
+
+        //---------------------------------------------------------
+        // HashMap messageContexts table
+        //---------------------------------------------------------
+
+        // NOTES: The assumption is that the table contains message contexts
+        // that are in the OperationContext hierarchy.  To reduce overlap
+        // of object information that is being saved, extract the 
+        // message context objects from the hierachy before saving.
+        // When the OperationContext is restored, the "slimmed down"
+        // message context objects are plugged back into the hierachy
+        // using the restored OperationContext as a basis.
+
+
+        // first deal with the original messageContexts table
+        HashMap tmpMsgCtxMap = null;
+
+        if ((messageContexts != null) && (messageContexts.isEmpty()==false))
+        {
+            // create a table of the non-isolated message contexts
+            workingSet = new HashMap();
+            tmpMsgCtxMap = new HashMap();
+
+            Set keySet = messageContexts.keySet();
+            Iterator itKeys = keySet.iterator();
+
+            while (itKeys.hasNext())
+            {
+                // expect the key to be a string
+                String keyObj = (String) itKeys.next();
+
+                // get the message context associated with that label
+                MessageContext value = (MessageContext) messageContexts.get(keyObj);
+
+                boolean addToWorkingSet = true;
+
+                // check to see if this message context was isolated
+                if (isolatedMessageContexts != null)
+                {
+                    if (isolatedMessageContexts.isEmpty() == false)
+                    {
+                        // see if the message context was previously isolated
+                        MessageContext valueIsolated = (MessageContext) isolatedMessageContexts.get(keyObj);
+
+                        if (valueIsolated != null)
+                        {
+                            String idIsol = valueIsolated.getMessageID();
+
+                            if (idIsol != null)
+                            {
+                                if (idIsol.equals(value.getMessageID()))
+                                {
+                                    // don't add to working set
+                                    addToWorkingSet = false;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (addToWorkingSet)
+                {
+                    // put the meta data entry in the list
+                    workingSet.put(keyObj,value);
+                }
+
+            }
+
+            // now we have a working set
+
+            Set keySet2 = workingSet.keySet();
+            Iterator itKeys2 = keySet2.iterator();
+
+            while (itKeys2.hasNext())
+            {
+                // expect the key to be a string
+                String keyObj2 = (String) itKeys2.next();
+
+                // get the message context associated with that label
+                MessageContext value2 = (MessageContext) workingSet.get(keyObj2);
+
+                // construct a copy of the message context
+                // that has been extracted from the object hierarchy
+                MessageContext modifiedValue2 = value2.extractCopyMessageContext();
+
+                // put the modified entry in the list
+                tmpMsgCtxMap.put(keyObj2,modifiedValue2);
+            }
+
+        }
+
+        ObjectStateUtils.writeHashMap(out, tmpMsgCtxMap, "OperationContext.messageContexts modified table");
+
+        // next, deal with the metadata table of messageContexts
+        ObjectStateUtils.writeHashMap(out, metaMessageContextMap, "OperationContext.metaMessageContextMap metadata table");
+
+
+        //---------------------------------------------------------
+        // done
+        //---------------------------------------------------------
+
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":writeExternal():  END  ");
+        }
+        //System.out.println(myClassName+":writeExternal():  END  ");
+    }
+
+
+    /**
+     * Restore the contents of the object that was previously saved.
+     * <p> 
+     * NOTE: The field data must read back in the same order and type
+     * as it was written.  Some data will need to be validated when 
+     * resurrected.
+     *
+     * @param in    The stream to read the object contents from 
+     * 
+     * @exception IOException
+     * @exception ClassNotFoundException
+     */
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+    {
+        // set the flag to indicate that the message context is being
+        // reconstituted and will need to have certain object references 
+        // to be reconciled with the current engine setup
+        needsToBeReconciled = true;
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":readExternal():  BEGIN  bytes available in stream ["+in.available()+"]  ");
+        }
+        //System.out.println(myClassName+":readExternal():  BEGIN  bytes available in stream ["+in.available()+"]  ");
+
+
+        //---------------------------------------------------------
+        // object level identifiers
+        //---------------------------------------------------------
+
+        // serialization version ID
+        long suid = in.readLong();
+
+        // revision ID
+        int  revID = in.readInt();
+
+        // make sure the object data is in a version we can handle
+        if (suid != serialVersionUID)
+        {
+            throw new ClassNotFoundException(ObjectStateUtils.UNSUPPORTED_SUID);
+        }
+
+        // make sure the object data is in a revision level we can handle
+        if (revID != REVISION_1)
+        {
+            throw new ClassNotFoundException(ObjectStateUtils.UNSUPPORTED_REVID);
+        }
+
+
+        //---------------------------------------------------------
+        // various simple fields
+        //---------------------------------------------------------
+
+        long time = in.readLong();
+        setLastTouchedTime(time);
+
+        isComplete = in.readBoolean();
+
+        key = ObjectStateUtils.readString(in,"OperationContext.key"); 
+
+        //---------------------------------------------------------
+        // properties
+        //---------------------------------------------------------
+
+        HashMap tmpHashMap = ObjectStateUtils.readHashMap(in,"OperationContext.properties");
+
+        properties = new HashMap();
+        if (tmpHashMap != null)
+        {
+            setProperties(tmpHashMap);
+        }
+
+
+        //---------------------------------------------------------
+        // axis operation meta data
+        //---------------------------------------------------------
+
+        // axisOperation is not usable until the meta data has been reconciled
+        axisOperation = null;
+
+        String axisOpMarker = ObjectStateUtils.readString(in, "OperationContext.axisOperation");
+
+        boolean metaAxisOperationIsActive = in.readBoolean();
+
+        if (metaAxisOperationIsActive == ObjectStateUtils.ACTIVE_OBJECT)
+        {
+        	metaAxisOperation = (MetaDataEntry) ObjectStateUtils.readObject(in, "OperationContext.metaAxisOperation");
+        }
+        else
+        {
+        	metaAxisOperation = null;
+        }
+
+
+        // axisService is not usable until the meta data has been reconciled
+
+        String axisServMarker = ObjectStateUtils.readString(in, "OperationContext.axisService");
+        
+        boolean metaAxisServiceIsActive = in.readBoolean();
+
+        if (metaAxisServiceIsActive == ObjectStateUtils.ACTIVE_OBJECT)
+        {
+        	metaAxisService = (MetaDataEntry) ObjectStateUtils.readObject(in, "OperationContext.metaAxisService");
+        }
+        else
+        {
+        	metaAxisService = null;
+        }
+        
+
+
+        //---------------------------------------------------------
+        // parent 
+        //---------------------------------------------------------
+
+        // ServiceContext is not usable until it has been activated 
+
+        metaParent = (ServiceContext) ObjectStateUtils.readObject(in, "OperationContext.parent ServiceContext");
+        
+
+        //---------------------------------------------------------
+        // HashMap messageContexts table
+        //---------------------------------------------------------
+
+        // set to empty until this can be activiated
+        messageContexts = new HashMap();
+
+        workingSet = ObjectStateUtils.readHashMap(in, "OperationContext.messageContexts working set");
+
+        metaMessageContextMap = ObjectStateUtils.readHashMap(in, "OperationContext.metaMessageContextMap metadata table");
+
+
+        //---------------------------------------------------------
+        // other
+        //---------------------------------------------------------
+
+        operationContextMap = null;  //need to reseed from config context
+
+
+        //---------------------------------------------------------
+        // done
+        //---------------------------------------------------------
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":readExternal():  END");
+        }
+        //System.out.println(myClassName+":readExternal():  END");
+
+    }
+
+    
+    /**
+     * This method checks to see if additional work needs to be
+     * done in order to complete the object reconstitution.
+     * Some parts of the object restored from the readExternal()
+     * cannot be completed until we have a configurationContext
+     * from the active engine. The configurationContext is used
+     * to help this object to plug back into the engine's
+     * configuration and deployment objects.
+     * 
+     * @param cc     The configuration context object representing the active configuration
+     */
+    public void activate(ConfigurationContext cc)
+    {
+        // see if there's any work to do
+        if (needsToBeReconciled == false)
+        {
+            // return quick
+            return;
+        }
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":activate():  BEGIN");
+        }
+        //System.out.println(myClassName+":activate():  BEGIN");
+
+
+        // get the axis configuration 
+        AxisConfiguration axisConfig = cc.getAxisConfiguration();
+
+
+        // We previously saved metaAxisService; restore it
+        AxisService axisService = null;
+
+        if (metaAxisService != null) 
+        {
+        	axisService = ObjectStateUtils.findService(axisConfig, metaAxisService.getClassName(), metaAxisService.getQNameAsString());
+        }
+
+        // We previously saved metaAxisOperation; restore it
+        if (metaAxisOperation != null)
+        {
+            if (axisService != null)
+            {
+                this.axisOperation = ObjectStateUtils.findOperation(axisService, metaAxisOperation.getClassName(), metaAxisOperation.getQName());
+            }
+            else
+            {
+                this.axisOperation = ObjectStateUtils.findOperation(axisConfig, metaAxisOperation.getClassName(), metaAxisOperation.getQName());
+            }
+        }
+        
+        // the parent ServiceContext object was saved
+        // either use the restored object or sync up with 
+        // an existing ServiceContext object
+        if (metaParent != null)
+        {
+            // find out if a copy of the ServiceContext object exists on this
+            // engine where this OperationContext is being restored/activated
+            // if so, use that object instead of the restored object
+            // in order to make sure that future changes to service-level 
+            // properties are preserved for future operations
+            String groupName = metaParent.getGroupName();
+            String serviceName = metaParent.getName();
+
+            ServiceContext existingSC = null;
+
+            // first look for the ServiceContext via the ServiceContextGroup
+            ServiceGroupContext sgc = cc.getServiceGroupContext(groupName);
+
+            if (sgc != null)
+            {
+                existingSC = sgc.findServiceContext(serviceName);
+            }
+
+            if (existingSC == null)
+            {
+                // we couldn't find the ServiceContext via the ServiceContextGroup
+                // try via the set of existing operation contexts 
+                OperationContext existingOC = cc.findOperationContext(getOperationName(), serviceName, groupName);
+
+                if (existingOC != null)
+                {
+                    existingSC = (ServiceContext) existingOC.getParent();
+                }
+            }
+
+            if (existingSC == null)
+            {
+                // could not find an existing ServiceContext
+                // use the restored object
+                metaParent.activate(cc);
+
+                // set parent 
+                this.setParent(metaParent);
+            }
+            else
+            {
+                // switch over to the existing object
+                this.setParent(existingSC);
+
+                // do a copy of the properties from the restored object
+                // to the existing ServiceContext
+                // Should the copy be a non-destructive one?  That is,
+                // if the key already exists in the properties table of the
+                // existing object, should the value be overwritten from the 
+                // restored ojbect? For now, the decision is that the state
+                // that has been preserved for a saved context object is
+                // is important to be restored.
+                metaParent.putContextProperties(existingSC,true);
+            }
+        }
+        else
+        {
+            // set parent  to null
+            this.setParent(metaParent);
+        }
+
+
+        // reseed the operation context map
+
+        ServiceContext serv = getServiceContext();
+        ConfigurationContext activeCC = null;
+        if (serv != null)
+        {
+            activeCC = serv.getConfigurationContext();
+        }
+        else
+        {
+            activeCC = cc;
+        }
+
+        this.operationContextMap = activeCC.getOperationContextMap(); 
+
+        if ((this.operationContextMap != null) && (key != null))
+        {
+            // is the current key already in the list?
+            if (this.operationContextMap.containsKey(key) == false)
+            {
+                // make sure this OperationContext object is registered in the 
+                // list maintained by the ConfigurationContext object
+                activeCC.registerOperationContext(key, this);
+            }
+            else
+            {
+                // trace point
+                if (log.isTraceEnabled())
+                {
+                    log.trace(myClassName+":activate():  OperationContext key ["+key+"] already exists in ConfigurationContext map.  This OperationContext ["+this.toString()+"] was not added to the table.");
+                }
+                //System.out.println(myClassName+":activate():  OperationContext key ["+key+"] already exists in ConfigurationContext map.");
+            }
+
+        }
+
+
+        //-------------------------------------------------------
+        // update the modified entries in the messageContexts table
+        //-------------------------------------------------------
+        // NOTE: an entry in the metaMessageContextMap must wait 
+        // for its corresponding active message context object
+        // to call this operation context object so we don't
+        // need to handle the metaMessagecontextMap table here
+
+        if ((workingSet != null) && (workingSet.isEmpty()==false))
+        {
+            Set keySet = workingSet.keySet();
+            Iterator itKeys = keySet.iterator();
+
+            while (itKeys.hasNext())
+            {
+                // expect the key to be a string
+                String keyObj = (String) itKeys.next();
+
+                // get the message context associated with that label
+                MessageContext value = (MessageContext) workingSet.get((Object)keyObj);
+
+                // activate that object 
+                if (value != null)
+                {
+                    //System.out.println(myClassName+":activate():  key ["+keyObj+"]  message id ["+value.getMessageID()+"]");
+
+                    suppressWarnings = true;
+                    value.activateWithOperationContext(this);
+                    suppressWarnings = false;
+
+                    if (messageContexts == null)
+                    {
+                        messageContexts = new HashMap();
+                    }
+                }
+
+                // put the entry in the "real" table
+                // note that the key or the value could be null
+                messageContexts.put(keyObj, value);
+            }
+        }
+
+
+        //-------------------------------------------------------
+        // done, reset the flag
+        //-------------------------------------------------------
+        needsToBeReconciled = false;
+
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":activate():  END");
+        }
+        //System.out.println(myClassName+":activate():  END");
+    }
+
+    /**
+     * Isolate the specified message context object
+     * to prepare for serialization.  Instead of 
+     * saving the entire message context object,
+     * just setup some metadata about the message
+     * context.
+     * <P>
+     * Note: this will remove the specified 
+     * message context object from the message context
+     * table.
+     * 
+     * @param mc     The message context object
+     */
+    public void isolateMessageContext(MessageContext mc)
+    {
+        if (mc == null)
+        {
+            return;
+        }
+
+        if ((messageContexts == null) || (messageContexts.isEmpty()))
+        {
+            return;
+        }
+
+        // get the message ID from the message context
+        String messageID = mc.getMessageID();
+
+        if (messageID == null)
+        {
+            // can't locate it without identification
+            return;
+        }
+
+
+        Iterator it = messageContexts.keySet().iterator();
+
+        while (it.hasNext())
+        {
+            // get the key
+            Object keyObj = it.next();
+
+            // get the value associated with that key
+            MessageContext value = (MessageContext) messageContexts.get(keyObj);
+
+            if (value != null)
+            {
+                String valueID = value.getMessageID();
+
+                if ((valueID != null) && valueID.equals(messageID))
+                {
+                    // found the input message context in our table
+
+                    if (metaMessageContextMap == null)
+                    {
+                        metaMessageContextMap = new HashMap();
+                    }
+
+                    // build a meta data entry
+                    //           MessageContext class name
+                    //           MessageContext messageID
+                    //           key used in the original hashmap that is associated with this MessageContext
+                    //                    note: this is typically something like "In", "Out", "Fault"
+                    //
+                    MetaDataEntry metaData = new MetaDataEntry(value.getClass().getName(), value.getMessageID(), keyObj.toString());
+
+                    // put the meta data entry in the list
+                    metaMessageContextMap.put(keyObj,metaData);
+
+                    // don't change the original table - there's potentially lots of areas that 
+                    // grab the table
+                    //  // now remove the original entry from the messageContexts table
+                    //  messageContexts.remove(keyObj);
+
+                    // put the original entry in the temporary list
+                    if (isolatedMessageContexts == null)
+                    {
+                        isolatedMessageContexts = new HashMap();
+                    }
+
+                    isolatedMessageContexts.put(keyObj,value);
+
+
+                    // trace point
+                    if (log.isTraceEnabled())
+                    {
+                        log.trace(myClassName+":isolateMessageContext():  set up message context id["+valueID+"]  with key ["+keyObj.toString()+"] from messageContexts table to prepare for serialization.");
+                    }
+                    //System.out.println(myClassName+":isolateMessageContext():  set up message context id["+valueID+"]  with key ["+keyObj.toString()+"] from messageContexts table to prepare for serialization.");
+
+                    break;
+                }
+            }
+        }
+    }
+
+
+
+    /**
+     * Restore the specified MessageContext object in the 
+     * table used to hold the message contexts associated
+     * with this operation.
+     *
+     * @param msg   The message context object 
+     */
+    public void restoreMessageContext(MessageContext msg)
+    {
+        // see if the activation has been done
+        if (needsToBeReconciled == true)
+        {
+            // nope, need to do the activation first
+            if (log.isTraceEnabled())
+            {
+                log.trace(myClassName+":restoreMessageContext(): *** WARNING : need to invoke activate() prior to restoring the MessageContext to the list.");
+            }
+            //System.out.println(myClassName+":restoreMessageContext(): *** WARNING : need to invoke activate() prior to restoring the MessageContext to the list.");
+
+            return;
+        }
+
+        if (msg == null)
+        {
+            return;
+        }
+
+        String msgID = msg.getMessageID();
+
+        if (msgID == null)
+        {
+            // can't identify message context
+            if (log.isTraceEnabled())
+            {
+                log.trace(myClassName+":restoreMessageContext(): *** WARNING : MessageContext does not have a message ID.");
+            }
+            //System.out.println(myClassName+":restoreMessageContext(): *** WARNING : MessageContext does not have a message ID.");
+            return;
+        }
+
+        // first check the metaMessageContextMap to see if 
+        // the specified message context object matches any
+        // of the metadata entries.  
+
+        if ((metaMessageContextMap != null) && (metaMessageContextMap.isEmpty() == false))
+        {
+            Iterator itMeta = metaMessageContextMap.keySet().iterator();
+
+            while (itMeta.hasNext())
+            {
+                String keyM = (String) itMeta.next();
+
+                MetaDataEntry valueM = (MetaDataEntry) metaMessageContextMap.get(keyM);
+                String valueM_ID = null;
+
+                if (valueM != null)
+                {
+                    valueM_ID = valueM.getQNameAsString();
+
+                    if (msgID.equals(valueM_ID))
+                    {
+                        String label = valueM.getExtraName();
+
+                        if (messageContexts == null)
+                        {
+                            messageContexts = new HashMap();
+                        }
+
+                        // put the message context into the messageContexts table
+                        messageContexts.put(label, msg);
+
+                        // remove the metadata from the metadata table
+                        metaMessageContextMap.remove(keyM);
+
+                        //System.out.println(myClassName+":restoreMessageContext():  restored   label ["+label+"]    message ID ["+msg.getMessageID()+"]");
+
+                        break;
+                    }
+                }
+            }
+        }
+        else 
+        // see if we can put the msg directly in the messageContexts table
+        if ((messageContexts != null) && (messageContexts.isEmpty() == false))
+        {
+            Iterator itList = messageContexts.keySet().iterator();
+
+            while (itList.hasNext())
+            {
+                String key = (String) itList.next();
+
+                MessageContext value = (MessageContext) messageContexts.get(key);
+                String valueID = null;
+
+                if (value != null)
+                {
+                    valueID = value.getMessageID();
+
+                    if (msgID.equals(valueID))
+                    {
+                        // update the entry
+                        messageContexts.put(key, msg);
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Get the name associated with the operation.
+     * 
+     * @return The name String
+     */
+    public String getOperationName()
+    {
+        String opName = null;
+
+        if (axisOperation != null)
+        {
+            QName qname = axisOperation.getName();
+            if (qname != null)
+            {
+                opName = qname.toString();
+            }
+        }
+
+        return opName;
+    }
+
+    /**
+     * Get the name associated with the service.
+     * 
+     * @return The name String
+     */
+    public String getServiceName()
+    {
+        String srvName = null;
+
+        ServiceContext sc = (ServiceContext) getParent();
+
+        if (sc == null)
+        {
+            sc = metaParent;
+        }
+
+        if (sc != null)
+        {
+            srvName = sc.getName();
+        }
+
+        return srvName;
+    }
+
+    /**
+     * Get the name associated with the service group.
+     * 
+     * @return The name String
+     */
+    public String getServiceGroupName()
+    {
+        String srvGroupName = null;
+
+        ServiceContext sc = (ServiceContext) getParent();
+
+        if (sc == null)
+        {
+            sc = metaParent;
+        }
+
+        if (sc != null)
+        {
+            srvGroupName = sc.getGroupName();
+        }
+
+        return srvGroupName;
+    }
+
+
+    /**
+     * Compares key parts of the state from the current instance of 
+     * this class with the specified instance to see if they are 
+     * equivalent. 
+     * <P>
+     * This differs from the java.lang.Object.equals() method in
+     * that the equals() method generally looks at both the 
+     * object identity (location in memory) and the object state
+     * (data).
+     * <P>
+     * 
+     * @param ctx  The object to compare with
+     * @return TRUE if this object is equivalent with the specified object
+     *              that is, key fields match
+     *         FALSE, otherwise
+     */
+    public boolean isEquivalent(OperationContext ctx)
+    {
+        // NOTE: the input object is expected to exist (ie, be non-null)
+
+        if (this.isComplete != ctx.isComplete())
+        {
+            return false;
+        }
+
+        if (!this.axisOperation.equals(ctx.getAxisOperation()))
+        {
+            return false;
+        }
+
+        // TODO: consider checking the parent objects for equivalency
+
+        // TODO: consider checking fields from the super class for equivalency
+
+        return true;
+    }
+
+
 }

Added: webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/SelfManagedDataManager.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/SelfManagedDataManager.java?view=auto&rev=495106
==============================================================================
--- webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/SelfManagedDataManager.java (added)
+++ webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/SelfManagedDataManager.java Wed Jan 10 20:04:31 2007
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.axis2.context;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * An interface for use by a message handler to allow 
+ * it to save and restore any message-specific data.
+ * <P>
+ * A handler can have message-specific data that 
+ * needs to be associated the message being processed.
+ * The handler can keep this message-specific data 
+ * in the Messagecontext object by adding the 
+ * data to the user data table via the 
+ * MessageContext method.  When the MessageContext 
+ * object is saved (for example, to persistent storage),
+ * and restored, this interface <B>SelfManagedDataManager</B>
+ * provides a way for the handler to save and restore
+ * the handler's message-specific data.
+ * 
+ * @see org.apache.axis2.context.MessageContext
+ */
+public interface SelfManagedDataManager {
+
+    /**
+     * This method is invoked when the MessageContext object is being saved.
+     *
+     * Implementors are expected to iterate through the data objects they wish
+     * to save and return it in a ByteArrayOutputStream.  This data will
+     * later be passed to the implementor's deserializeSelfManagedData method when
+     * the data object is to be restored.
+     * 
+     * The data being saved may be the data stored by the implementor
+     * in the MessageContext object's SelfManagedData list and may include
+     * additional information such as the implementor's fields.
+     * Note that data stored by the implementor in the MessageContext object's SelfManagedData
+     * list is retrievable by calling the MessageContext.getSelfManagedData() method
+     * for EACH key/value pair.
+     * 
+     * @param mc     the MessageContext that is being saved
+     * @return The saved data in the output stream. Note that the
+     *         format of the data in the output stream is defined
+     *         by the implementor.
+     * @exception IOException
+     */
+	public ByteArrayOutputStream serializeSelfManagedData(MessageContext mc) throws IOException;
+
+    /**
+     * This method is invoked when the MessageContext object is being restored.
+     *
+     * Implementors will receive the data they had previously saved in the
+     * serializeSelfManagedData() method. Implementors are responsible for
+     * reconstituting their message-specific data.
+     * 
+     * @param data   ByteArrayInputStream consisting of the data that this handler had previously saved
+     * @param mc     the MessageContext object being restored
+     * @exception IOException
+     */
+	public void deserializeSelfManagedData(ByteArrayInputStream data, MessageContext mc) throws IOException;
+
+
+	/**
+     * This method is invoked when the MessageContext object is being restored and
+     * after the deserializeSelfManagedData() method.
+     *
+     * Implementors use this method to re-establish transient message-specific data,
+     * particularly if the implementor did not save any user data in the 
+     * serializeSelfManagedData() method.
+	 * 
+	 * @param mc the MessageContext object being restored
+	 */
+	public void restoreTransientData(MessageContext mc);
+
+}

Modified: webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceContext.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceContext.java?view=diff&rev=495106&r1=495105&r2=495106
==============================================================================
--- webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceContext.java (original)
+++ webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceContext.java Wed Jan 10 20:04:31 2007
@@ -22,29 +22,111 @@
 import org.apache.axis2.description.AxisOperation;
 import org.apache.axis2.description.AxisService;
 import org.apache.axis2.description.TransportInDescription;
+import org.apache.axis2.engine.AxisConfiguration;
 import org.apache.axis2.engine.ListenerManager;
 import org.apache.axis2.i18n.Messages;
+import org.apache.axis2.util.ObjectStateUtils;
+import org.apache.axis2.util.MetaDataEntry;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 import javax.xml.namespace.QName;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Well this is never clearly defined, what it does or the life-cycle.
  * So do NOT use this as it might not live up to your expectation.
  */
-public class ServiceContext extends AbstractContext {
+public class ServiceContext extends AbstractContext implements Externalizable {
+
+    /*
+     * setup for logging
+     */
+    private static final Log log = LogFactory.getLog(ServiceContext.class);
+
+    private static final String myClassName = "ServiceContext";
+
+    /**
+     * @serial The serialization version ID tracks the version of the class.
+     * If a class definition changes, then the serialization/externalization
+     * of the class is affected. If a change to the class is made which is
+     * not compatible with the serialization/externalization of the class,
+     * then the serialization version ID should be updated.
+     * Refer to the "serialVer" utility to compute a serialization
+     * version ID.
+     */
+    private static final long serialVersionUID = 8265625275015738957L;
+
+    /**
+     * @serial Tracks the revision level of a class to identify changes to the 
+     * class definition that are compatible to serialization/externalization.
+     * If a class definition changes, then the serialization/externalization
+     * of the class is affected. 
+     * Refer to the writeExternal() and readExternal() methods.
+     */
+    // supported revision levels, add a new level to manage compatible changes
+    private static final int REVISION_1 = 1;
+    // current revision level of this object
+    private static final int revisionID = REVISION_1;
+
 
     public static final String SERVICE_OBJECT = "serviceObject";
+
     private EndpointReference targetEPR;
     private EndpointReference myEPR;
 
     private transient AxisService axisService;
-    private ServiceGroupContext serviceGroupContext;
-    private ConfigurationContext configContext;
+
+    // the service group context is the same as the parent
+    private transient ServiceGroupContext serviceGroupContext;
+
+    private transient ConfigurationContext configContext;
 
     /** Should we cache the last OperationContext? */
     private boolean cachingOperationContext;
     /** A cache for the last OperationContext */
-    private OperationContext lastOperationContext;
+    private transient OperationContext lastOperationContext;
+
+
+    //----------------------------------------------------------------
+    // MetaData for data to be restored in activate after readExternal
+    //----------------------------------------------------------------
+    
+    /**
+     * Indicates whether the message context has been reconstituted
+     * and needs to have its object references reconciled
+     */
+    private transient boolean needsToBeReconciled = false;
+
+    /**
+     * The AxisService metadata will be used during
+     * activate to match up with an existing object
+     */
+    private transient MetaDataEntry metaAxisService = null;
+    
+    /**
+     * The ServiceGroupContext object will be used during
+     * activate to finish its restoration 
+     */
+    private transient ServiceGroupContext  metaParent = null;
+    
+    
+    //----------------------------------------------------------------
+    // end MetaData section
+    //----------------------------------------------------------------
+
+    // simple constructor
+    public ServiceContext() {
+        super(null);
+    }
+
 
     public ServiceContext(AxisService serviceConfig, ServiceGroupContext serviceGroupContext) {
         super(serviceGroupContext);
@@ -68,14 +150,35 @@
     }
 
     public AxisService getAxisService() {
+        if (needsToBeReconciled) {
+            if (log.isWarnEnabled()) {
+                log.warn(myClassName+":getAxisService(): ****WARNING**** ServiceContext.activate(configurationContext) needs to be invoked.");
+            }
+            //System.out.println(myClassName+":getAxisService(): ****WARNING**** ServiceContext.activate(configurationContext) needs to be invoked.");
+        }
+
         return axisService;
     }
 
     public ConfigurationContext getConfigurationContext() {
+        if (needsToBeReconciled) {
+            if (log.isWarnEnabled()) {
+                log.warn(myClassName+":getConfigurationContext(): ****WARNING**** ServiceContext.activate(configurationContext) needs to be invoked.");
+            }
+            //System.out.println(myClassName+":getConfigurationContext(): ****WARNING**** ServiceContext.activate(configurationContext) needs to be invoked.");
+        }
+
         return configContext;
     }
 
     public ServiceGroupContext getServiceGroupContext() {
+        if (needsToBeReconciled) {
+            if (log.isWarnEnabled()) {
+                log.warn(myClassName+":getServiceGroupContext(): ****WARNING**** ServiceContext.activate(configurationContext) needs to be invoked.");
+            }
+            //System.out.println(myClassName+":getServiceGroupContext(): ****WARNING**** ServiceContext.activate(configurationContext) needs to be invoked.");
+        }
+
         return serviceGroupContext;
     }
 
@@ -86,6 +189,7 @@
      * for a given service
      *
      * @param transport : Name of the transport
+     * @return
      * @throws AxisFault
      */
     public EndpointReference getMyEPR(String transport) throws AxisFault {
@@ -153,4 +257,508 @@
     public void setCachingOperationContext(boolean cacheLastOperationContext) {
         this.cachingOperationContext = cacheLastOperationContext;
     }
+
+
+    /**
+     * Returns a name associated with this ServiceContext.
+     * <P>
+     * Note: this name is from the corresponding
+     * AxisService object.
+     * 
+     * @return The name string, or null if no name can be found
+     */
+    public String getName()
+    {
+        if (axisService != null)
+        {
+            return axisService.getName();
+        }
+
+        if (metaAxisService != null)
+        {
+            return metaAxisService.getName();
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Returns a name associated with the ServiceGroupContext 
+     * associated with this ServiceContext.
+     * 
+     * @return The name string, or null if no name can be found
+     */
+    public String getGroupName()
+    {
+        if (serviceGroupContext != null)
+        {
+            return serviceGroupContext.getId();
+        }
+
+        if (metaParent != null)
+        {
+            return metaParent.getId();
+        }
+
+        return null;
+    }
+
+    /* ===============================================================
+     * Externalizable support 
+     * ===============================================================
+     */
+    
+
+    /**
+     * Save the contents of this object.
+     * <p>
+     * NOTE: Transient fields and static fields are not saved.
+     *       Also, objects that represent "static" data are
+     *       not saved, except for enough information to be
+     *       able to find matching objects when the message
+     *       context is re-constituted.
+     *
+     * @param out    The stream to write the object contents to
+     * 
+     * @exception IOException
+     */
+    public void writeExternal(ObjectOutput out) throws IOException
+    {
+        //---------------------------------------------------------
+        // in order to handle future changes to the message 
+        // context definition, be sure to maintain the 
+        // object level identifiers
+        //---------------------------------------------------------
+        // serialization version ID
+        out.writeLong(serialVersionUID);
+
+        // revision ID
+        out.writeInt(revisionID);
+
+        //---------------------------------------------------------
+        // various simple fields
+        //---------------------------------------------------------
+
+        out.writeLong(getLastTouchedTime());
+
+        out.writeBoolean(cachingOperationContext);
+
+
+        // EndpointReference targetEPR
+        ObjectStateUtils.writeObject(out, targetEPR, "ServiceContext.targetEPR");
+
+        // EndpointReference myEPR
+        ObjectStateUtils.writeObject(out, myEPR, "ServiceContext.myEPR");
+
+
+        //---------------------------------------------------------
+        // properties
+        //---------------------------------------------------------
+        Map tmpMap = getProperties();
+
+        HashMap tmpHashMap = null;
+
+        if ((tmpMap != null) && (tmpMap.isEmpty()==false))
+        {
+            tmpHashMap = new HashMap(tmpMap);
+        }
+
+        ObjectStateUtils.writeHashMap(out, tmpHashMap, "ServiceContext.properties");
+
+
+        //---------------------------------------------------------
+        // AxisService
+        //---------------------------------------------------------
+
+        String axisServMarker = "ServiceContext.metaAxisService";
+        ObjectStateUtils.writeString(out, axisServMarker, axisServMarker);
+
+        if (axisService == null)
+        {
+        	out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
+        }
+        else
+        {
+        	out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
+        	metaAxisService = new MetaDataEntry(axisService.getClass().getName(), axisService.getName().toString());
+        	ObjectStateUtils.writeObject(out, metaAxisService, "ServiceContext.metaAxisService");
+        }
+        
+
+        //---------------------------------------------------------
+        // parent 
+        //---------------------------------------------------------
+        // ServiceGroupContext serviceGroupContext;
+
+        ServiceGroupContext myParent = (ServiceGroupContext) getParent();
+
+        ObjectStateUtils.writeObject(out, myParent, "ServiceContext.parent ServiceGroupContext");
+
+    }
+
+
+    /**
+     * Restore the contents of the object that was previously saved.
+     * <p> 
+     * NOTE: The field data must read back in the same order and type
+     * as it was written.  Some data will need to be validated when 
+     * resurrected.
+     *
+     * @param in    The stream to read the object contents from 
+     * 
+     * @exception IOException
+     * @exception ClassNotFoundException
+     */
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+    {
+        // set the flag to indicate that the message context is being
+        // reconstituted and will need to have certain object references 
+        // to be reconciled with the current engine setup
+        needsToBeReconciled = true;
+
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":readExternal():  BEGIN  bytes available in stream ["+in.available()+"]  ");
+        }
+        //System.out.println(myClassName+":readExternal():  BEGIN  bytes available in stream ["+in.available()+"]  ");
+
+
+        //---------------------------------------------------------
+        // object level identifiers
+        //---------------------------------------------------------
+
+        // serialization version ID
+        long suid = in.readLong();
+
+        // revision ID
+        int  revID = in.readInt();
+
+        // make sure the object data is in a version we can handle
+        if (suid != serialVersionUID)
+        {
+            throw new ClassNotFoundException(ObjectStateUtils.UNSUPPORTED_SUID);
+        }
+
+        // make sure the object data is in a revision level we can handle
+        if (revID != REVISION_1)
+        {
+            throw new ClassNotFoundException(ObjectStateUtils.UNSUPPORTED_REVID);
+        }
+
+
+        //---------------------------------------------------------
+        // various simple fields
+        //---------------------------------------------------------
+
+        long time = in.readLong();
+        setLastTouchedTime(time);
+
+        cachingOperationContext = in.readBoolean();
+
+        // EndpointReference targetEPR
+        targetEPR = (EndpointReference) ObjectStateUtils.readObject(in, "ServiceContext.targetEPR");
+
+        // EndpointReference myEPR
+        myEPR = (EndpointReference) ObjectStateUtils.readObject(in, "ServiceContext.myEPR");
+
+
+        //---------------------------------------------------------
+        // properties
+        //---------------------------------------------------------
+
+        HashMap tmpHashMap = ObjectStateUtils.readHashMap(in,"ServiceContext.properties");
+
+        properties = new HashMap();
+        if (tmpHashMap != null)
+        {
+            setProperties(tmpHashMap);
+        }
+
+
+        //---------------------------------------------------------
+        // AxisService
+        //---------------------------------------------------------
+
+        // axisService is not usable until the meta data has been reconciled
+
+        String axisServMarker = ObjectStateUtils.readString(in, "ServiceContext.axisService");
+        
+        boolean metaAxisServiceIsActive = in.readBoolean();
+
+        if (metaAxisServiceIsActive == ObjectStateUtils.ACTIVE_OBJECT)
+        {
+        	metaAxisService = (MetaDataEntry) ObjectStateUtils.readObject(in, "ServiceContext.metaAxisService");
+        }
+        else
+        {
+        	metaAxisService = null;
+        }
+        
+
+
+        //---------------------------------------------------------
+        // parent 
+        //---------------------------------------------------------
+
+        // ServiceGroupContext is not usable until it has been activated 
+
+        metaParent = (ServiceGroupContext) ObjectStateUtils.readObject(in, "ServiceContext.parent ServiceGroupContext");
+        
+
+        //---------------------------------------------------------
+        // other
+        //---------------------------------------------------------
+
+        // currently not saving this object
+        lastOperationContext = null;
+
+        //---------------------------------------------------------
+        // done
+        //---------------------------------------------------------
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":readExternal():  END");
+        }
+        //System.out.println(myClassName+":readExternal():  END");
+
+    }
+
+    
+    /**
+     * This method checks to see if additional work needs to be
+     * done in order to complete the object reconstitution.
+     * Some parts of the object restored from the readExternal()
+     * cannot be completed until we have a configurationContext
+     * from the active engine. The configurationContext is used
+     * to help this object to plug back into the engine's
+     * configuration and deployment objects.
+     * 
+     * @param cc     The configuration context object representing the active configuration
+     */
+    public void activate(ConfigurationContext cc)
+    {
+        // see if there's any work to do
+        if (needsToBeReconciled == false)
+        {
+            // return quick
+            return;
+        }
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":activate():  BEGIN");
+        }
+        //System.out.println(myClassName+":activate():  BEGIN");
+
+
+        // use the supplied configuration context
+        configContext = cc;
+
+        // get the axis configuration 
+        AxisConfiguration axisConfig = cc.getAxisConfiguration();
+
+        // We previously saved metaAxisService; restore it
+        axisService = null;
+
+        if (metaAxisService != null) 
+        {
+        	axisService = ObjectStateUtils.findService(axisConfig, metaAxisService.getClassName(), metaAxisService.getQNameAsString());
+        }
+
+
+        // the parent ServiceGroupContext object was saved
+        // either use the restored object or sync up with 
+        // an existing ServiceGroupContext object
+        if (metaParent != null)
+        {
+            // find out if a copy of the ServiceGroupContext object exists on this
+            // engine where this ServiceContext is being restored/activated
+            // if so, use that object instead of the restored object
+            // in order to make sure that future changes to group-level 
+            // properties are preserved for future operations
+            String groupName = metaParent.getId();
+
+            ServiceGroupContext existingSGC = null;
+
+            ServiceGroupContext sgc = cc.getServiceGroupContext(groupName);
+
+            if (existingSGC == null)
+            {
+                // could not find an existing ServiceGroupContext
+                // use the restored object
+                metaParent.activate(cc);
+
+                // set parent 
+                this.setParent(metaParent);
+            }
+            else
+            {
+                // switch over to the existing object
+                this.setParent(existingSGC);
+
+                // do a copy of the properties from the restored object
+                // to the existing ServiceContext
+                // Should the copy be a non-destructive one?  That is,
+                // if the key already exists in the properties table of the
+                // existing object, should the value be overwritten from the 
+                // restored ojbect? For now, the decision is that the state
+                // that has been preserved for a saved context object is
+                // is important to be restored.
+                metaParent.putContextProperties(existingSGC);
+            }
+
+        }
+        else
+        {
+            // set parent to null
+            this.setParent(metaParent);
+        }
+
+        // this is another pointer to our parent object
+        serviceGroupContext = (ServiceGroupContext) this.getParent();
+
+        if (serviceGroupContext != null)
+        {
+            // add the service context to the table
+            serviceGroupContext.addServiceContext(this);
+        }
+
+
+        //-------------------------------------------------------
+        // done, reset the flag
+        //-------------------------------------------------------
+        needsToBeReconciled = false;
+
+        // make sure this restored object is in the parent's list
+        if (metaParent != null)
+        {
+            // make sure this restored object is in the parent's list
+            metaParent.addServiceContext(this);
+        }
+
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":activate():  END");
+        }
+        //System.out.println(myClassName+":activate():  END");
+    }
+
+    /**                         
+     * This will do a copy of the properties from this context object 
+     * to the properties of the specified context object.
+     *
+     * @param context The ServiceContext object to hold the merged properties
+     * @param doParentProperties  Indicates whether to go up the context hierachy 
+     *                            copy the properties at each level
+     */
+    public void putContextProperties(ServiceContext context, boolean doParentProperties)
+    {
+        if (context != null)
+        {
+            // get the current properties on this context object
+            Map props = getProperties();
+
+            // copy them to the specified context object
+            context.mergeProperties(props);
+
+            if (doParentProperties)
+            {
+                ServiceGroupContext mySGC = null;
+
+                if (serviceGroupContext != null)
+                {
+                    mySGC = serviceGroupContext;
+                }
+                else if (metaParent != null) 
+                {
+                        mySGC = metaParent;
+                }
+
+                if (mySGC != null)
+                {
+                    ServiceGroupContext sgc = context.getServiceGroupContext();
+                    mySGC.putContextProperties(sgc);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Compares key parts of the state from the current instance of 
+     * this class with the specified instance to see if they are 
+     * equivalent. 
+     * <P>
+     * This differs from the java.lang.Object.equals() method in
+     * that the equals() method generally looks at both the 
+     * object identity (location in memory) and the object state
+     * (data).
+     * <P>
+     * 
+     * @param srvctx  The object to compare with
+     * @return TRUE if this object is equivalent with the specified object
+     *              that is, key fields match
+     *         FALSE, otherwise
+     */
+    public boolean isEquivalent(ServiceContext ctx)
+    {
+        // NOTE: the input object is expected to exist (ie, be non-null)
+
+        if (!this.axisService.equals(ctx.getAxisService()))
+        {
+            return false;
+        }
+
+
+        EndpointReference targetEPR2 = ctx.getTargetEPR();
+
+        if ( (this.targetEPR != null) && (targetEPR2 != null) )
+        {
+            if (!this.targetEPR.isEquivalent(targetEPR2))
+            {
+                return false;
+            }
+        }
+        else if ((this.targetEPR == null) && (targetEPR2 == null))
+        {
+            // keep going
+        }
+        else
+        {
+            // one of the objects is null
+            return false;
+        }
+
+        EndpointReference myEPR2 = ctx.getMyEPR();
+
+        if ( (this.myEPR != null) && (myEPR2 != null) )
+        {
+            if (!this.myEPR.isEquivalent(myEPR2))
+            {
+                return false;
+            }
+        }
+        else if ((this.myEPR == null) && (myEPR2 == null))
+        {
+            // keep going
+        }
+        else
+        {
+            // one of the objects is null
+            return false;
+        }
+
+        // TODO: consider checking the parent objects for equivalency
+
+        // TODO: consider checking fields from the super class for equivalency
+
+        return true;
+    }
+
 }

Modified: webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceGroupContext.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceGroupContext.java?view=diff&rev=495106&r1=495105&r2=495106
==============================================================================
--- webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceGroupContext.java (original)
+++ webservices/axis2/trunk/java/modules/kernel/src/org/apache/axis2/context/ServiceGroupContext.java Wed Jan 10 20:04:31 2007
@@ -20,25 +20,109 @@
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.description.AxisService;
 import org.apache.axis2.description.AxisServiceGroup;
+import org.apache.axis2.engine.AxisConfiguration;
 import org.apache.axis2.i18n.Messages;
+import org.apache.axis2.util.ObjectStateUtils;
+import org.apache.axis2.util.MetaDataEntry;
+import org.apache.axis2.util.UUIDGenerator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.HashMap;
 import java.util.Map;
 
-public class ServiceGroupContext extends AbstractContext {
+public class ServiceGroupContext extends AbstractContext implements Externalizable {
+
+    /*
+     * setup for logging
+     */
+    private static final Log log = LogFactory.getLog(ServiceGroupContext.class);
+
+    private static final String myClassName = "ServiceGroupContext";
+
+    /**
+     * @serial The serialization version ID tracks the version of the class.
+     * If a class definition changes, then the serialization/externalization
+     * of the class is affected. If a change to the class is made which is
+     * not compatible with the serialization/externalization of the class,
+     * then the serialization version ID should be updated.
+     * Refer to the "serialVer" utility to compute a serialization
+     * version ID.
+     */
+    private static final long serialVersionUID = 9014471144479928885L;
+
+    /**
+     * @serial Tracks the revision level of a class to identify changes to the 
+     * class definition that are compatible to serialization/externalization.
+     * If a class definition changes, then the serialization/externalization
+     * of the class is affected. 
+     * Refer to the writeExternal() and readExternal() methods.
+     */
+    // supported revision levels, add a new level to manage compatible changes
+    private static final int REVISION_1 = 1;
+    // current revision level of this object
+    private static final int revisionID = REVISION_1;
+
 
     private transient AxisServiceGroup axisServiceGroup;
     private String id;
     private Map serviceContextMap;
 
+    //----------------------------------------------------------------
+    // MetaData for data to be restored in activate after readExternal
+    //----------------------------------------------------------------
+    
+    /**
+     * Indicates whether the message context has been reconstituted
+     * and needs to have its object references reconciled
+     */
+    private transient boolean needsToBeReconciled = false;
+
+
+    /**
+     * The AxisServiceContext metadata will be used during
+     * activate to match up with an existing object
+     */
+    private transient MetaDataEntry metaAxisServiceGroup = null;
+    
+
+    //----------------------------------------------------------------
+    // end MetaData section
+    //----------------------------------------------------------------
+
+    // simple constructor
+    public ServiceGroupContext() {
+        super(null);
+        serviceContextMap = new HashMap();
+    }
+
+
     public ServiceGroupContext(ConfigurationContext parent, AxisServiceGroup axisServiceGroup) {
         super(parent);
         this.axisServiceGroup = axisServiceGroup;
         serviceContextMap = new HashMap();
+        // initially set the id to the axisServiceGroup
+        if (axisServiceGroup != null) {
+            setId(axisServiceGroup.getServiceGroupName());
+        }
     }
 
     public AxisServiceGroup getDescription() {
+        if (needsToBeReconciled) {
+            if (log.isWarnEnabled()) {
+                log.warn(myClassName+":getDescription(): ****WARNING**** ServiceGroupContext.activate(configurationContext) needs to be invoked.");
+            }
+            //System.out.println(myClassName+":getDescription(): ****WARNING**** ServiceGroupContext.activate(configurationContext) needs to be invoked.");
+        }
+
         return axisServiceGroup;
     }
 
@@ -61,6 +145,9 @@
             throw new AxisFault(Messages.getMessage("invalidserviceinagroup",
                     service.getName(), axisServiceGroup.getServiceGroupName()));
         }
+        if (serviceContextMap == null) {
+            serviceContextMap = new HashMap();
+        }
         ServiceContext serviceContext = (ServiceContext) serviceContextMap.get(service.getName());
         if (serviceContext == null) {
             serviceContext = new ServiceContext(service, this);
@@ -70,10 +157,446 @@
     }
 
     public Iterator getServiceContexts() {
+        if (serviceContextMap == null) {
+            serviceContextMap = new HashMap();
+        }
+        if (serviceContextMap.isEmpty()) {
+            return null;
+        }
         return serviceContextMap.values().iterator();
     }
 
     public void setId(String id) {
         this.id = id;
+    }
+
+
+
+    /**
+     * Adds the specified service context object to the
+     * lists of service contexts for this service group
+     * context.
+     * 
+     * @param srvctx The ServiceContext object to add
+     */
+    public void addServiceContext(ServiceContext srvctx)
+    {
+        if (srvctx == null)
+        {
+            return;
+        }
+
+        AxisService axisService = srvctx.getAxisService();
+        
+        if (axisService == null)
+        {
+            return;
+        }
+
+        if (serviceContextMap == null)
+        {
+            serviceContextMap = new HashMap();
+        }
+
+        serviceContextMap.put(axisService.getName(), srvctx);
+
+    }
+
+
+    /**
+     * Finds the service context object that corresponds
+     * to the specified name from the list
+     * of service contexts for this service group
+     * context.
+     * 
+     * @param name The name associated with the ServiceContext
+     *
+     * @return The ServiceContext associated with the name,
+     *         or null, if none can be found
+     */
+    public ServiceContext findServiceContext(String name)
+    {
+        if (serviceContextMap == null)
+        {
+            return null;
+        }
+
+        // a map allows a null key
+        ServiceContext sc = (ServiceContext) serviceContextMap.get(name);
+
+        return sc;
+    }
+
+
+    /**
+     * Finds the service context object that corresponds
+     * to the specified AxisService from the list
+     * of service contexts for this service group
+     * context.
+     * 
+     * @param name The AxisService associated with the ServiceContext
+     *
+     * @return The ServiceContext associated with the AxisService
+     *         or null, if none can be found
+     */
+    public ServiceContext findServiceContext(AxisService axisSrv)
+    {
+        if (axisSrv == null)
+        {
+            return null;
+        }
+
+        if (serviceContextMap == null)
+        {
+            return null;
+        }
+
+        ServiceContext sc = (ServiceContext) serviceContextMap.get(axisSrv.getName());
+
+        return sc;
+    }
+
+    /**                         
+     * This will do a copy of the properties from this context object 
+     * to the properties of the specified context object.
+     *
+     * @param context The ServiceGroupContext object to hold the merged properties
+     */
+    public void putContextProperties(ServiceGroupContext context) {
+        if (context != null)
+        {
+            // get the current properties on this context object
+            Map props = getProperties();
+
+            // copy them to the specified context object
+            context.mergeProperties(props);
+        }
+    }
+
+
+    /* ===============================================================
+     * Externalizable support 
+     * ===============================================================
+     */
+    
+
+    /**
+     * Save the contents of this object.
+     * <p>
+     * NOTE: Transient fields and static fields are not saved.
+     *       Also, objects that represent "static" data are
+     *       not saved, except for enough information to be
+     *       able to find matching objects when the message
+     *       context is re-constituted.
+     *
+     * @param out    The stream to write the object contents to
+     * 
+     * @exception IOException
+     */
+    public void writeExternal(ObjectOutput out) throws IOException
+    {
+        // write out contents of this object
+
+        //---------------------------------------------------------
+        // in order to handle future changes to the message 
+        // context definition, be sure to maintain the 
+        // object level identifiers
+        //---------------------------------------------------------
+        // serialization version ID
+        out.writeLong(serialVersionUID);
+
+        // revision ID
+        out.writeInt(revisionID);
+
+        //---------------------------------------------------------
+        // various simple fields
+        //---------------------------------------------------------
+
+        out.writeLong(getLastTouchedTime());
+
+        if (id == null)
+        {
+            // generate an ID to use when this object is restored
+            id = UUIDGenerator.getUUID();
+        }
+
+        ObjectStateUtils.writeString(out, id, "ServiceGroupContext.id");
+
+        //---------------------------------------------------------
+        // properties
+        //---------------------------------------------------------
+        Map tmpMap = getProperties();
+
+        HashMap tmpHashMap = null;
+
+        if ((tmpMap != null) && (tmpMap.isEmpty()==false))
+        {
+            tmpHashMap = new HashMap(tmpMap);
+        }
+
+        ObjectStateUtils.writeHashMap(out, tmpHashMap, "ServiceGroupContext.properties");
+
+
+        //---------------------------------------------------------
+        // AxisServiceGroup
+        //---------------------------------------------------------
+
+        String axisServGrpMarker = "ServiceGroupContext.axisServiceGroup";
+        ObjectStateUtils.writeString(out, axisServGrpMarker, axisServGrpMarker);
+
+        if (axisServiceGroup == null)
+        {
+        	out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
+        }
+        else
+        {
+        	out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
+        	metaAxisServiceGroup = new MetaDataEntry(axisServiceGroup.getClass().getName(), axisServiceGroup.getServiceGroupName());
+        	ObjectStateUtils.writeObject(out, metaAxisServiceGroup, "ServiceGroupContext.metaAxisServiceGroup");
+        }
+        
+
+        //---------------------------------------------------------
+        // parent 
+        //---------------------------------------------------------
+
+        // the parent is the ConfigurationContext object, which
+        // at this time, is not being saved.
+        // instead, we will need to register this ServiceGroupObject
+        // with the existing ConfigurationContext object when
+        // this object is reconstituted
+
+    }
+
+
+    /**
+     * Restore the contents of the object that was previously saved.
+     * <p> 
+     * NOTE: The field data must read back in the same order and type
+     * as it was written.  Some data will need to be validated when 
+     * resurrected.
+     *
+     * @param in    The stream to read the object contents from 
+     * 
+     * @exception IOException
+     * @exception ClassNotFoundException
+     */
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+    {
+        // set the flag to indicate that the message context is being
+        // reconstituted and will need to have certain object references 
+        // to be reconciled with the current engine setup
+        needsToBeReconciled = true;
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":readExternal():  BEGIN  bytes available in stream ["+in.available()+"]  ");
+        }
+        //System.out.println(myClassName+":readExternal():  BEGIN  bytes available in stream ["+in.available()+"]  ");
+
+
+        // serialization version ID
+        long suid = in.readLong();
+
+        // revision ID
+        int  revID = in.readInt();
+
+        // make sure the object data is in a version we can handle
+        if (suid != serialVersionUID)
+        {
+            throw new ClassNotFoundException(ObjectStateUtils.UNSUPPORTED_SUID);
+        }
+
+        // make sure the object data is in a revision level we can handle
+        if (revID != REVISION_1)
+        {
+            throw new ClassNotFoundException(ObjectStateUtils.UNSUPPORTED_REVID);
+        }
+
+
+        //---------------------------------------------------------
+        // various simple fields
+        //---------------------------------------------------------
+
+        long time = in.readLong();
+        setLastTouchedTime(time);
+
+        id = ObjectStateUtils.readString(in, "ServiceGroupContext.id");
+
+
+        //---------------------------------------------------------
+        // properties
+        //---------------------------------------------------------
+
+        HashMap tmpHashMap = ObjectStateUtils.readHashMap(in,"ServiceGroupContext.properties");
+
+        properties = new HashMap();
+        if (tmpHashMap != null)
+        {
+            setProperties(tmpHashMap);
+        }
+
+        //---------------------------------------------------------
+        // AxisServiceGroup
+        //---------------------------------------------------------
+
+        // axisServiceGroup is not usable until the meta data has been reconciled
+        axisServiceGroup = null;
+
+        String axisServGrpMarker = ObjectStateUtils.readString(in, "ServiceGroupContext.axisServiceGroup");
+        
+        boolean metaAxisServiceGrpIsActive = in.readBoolean();
+
+        if (metaAxisServiceGrpIsActive == ObjectStateUtils.ACTIVE_OBJECT)
+        {
+        	metaAxisServiceGroup = (MetaDataEntry) ObjectStateUtils.readObject(in, "ServiceGroupContext.metaAxisServiceGroup");
+        }
+        else
+        {
+        	metaAxisServiceGroup = null;
+        }
+        
+
+
+        //---------------------------------------------------------
+        // parent 
+        //---------------------------------------------------------
+
+        // the parent is the ConfigurationContext object, whic
+        // at this time, is not being saved.
+        // instead, we will need to register this ServiceGroupObject
+        // with the existing ConfigurationContext object when
+        // this object is reconstituted
+
+
+        //---------------------------------------------------------
+        // other
+        //---------------------------------------------------------
+        serviceContextMap = new HashMap();
+
+
+        //---------------------------------------------------------
+        // done
+        //---------------------------------------------------------
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":readExternal():  END");
+        }
+        //System.out.println(myClassName+":readExternal():  END");
+
+    }
+
+    
+    /**                     
+     * Some parts of the object restored from the 
+     * readExternal deserialization work cannot be completed until
+     * we have a configurationContext.  This method checks to see
+     * if additional work needs to be done in order to complete
+     * the object reconstitution.
+     */
+    public void activate(ConfigurationContext cc)
+    {
+        // see if there's any work to do
+        if (needsToBeReconciled == false)
+        {
+            // return quick
+            return;
+        }
+
+        // trace point
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":activate():  BEGIN");
+        }
+        //System.out.println(myClassName+":activate():  BEGIN");
+
+
+
+        // get the axis configuration 
+        AxisConfiguration axisConfig = cc.getAxisConfiguration();
+
+        // We previously saved metaAxisServiceGroup; restore it
+        if (metaAxisServiceGroup != null) {
+        	axisServiceGroup = ObjectStateUtils.findServiceGroup(axisConfig, metaAxisServiceGroup.getClassName(), metaAxisServiceGroup.getQNameAsString());
+        }
+        else
+        {
+            axisServiceGroup = null;
+        }
+
+        // set parent 
+        this.setParent(cc);
+
+        // register with the parent
+        cc.registerServiceGroupContext(this);
+
+
+        //-------------------------------------------------------
+        // done, reset the flag
+        //-------------------------------------------------------
+        needsToBeReconciled = false;
+
+        if (log.isTraceEnabled())
+        {
+            log.trace(myClassName+":activate():  END");
+        }
+        //System.out.println(myClassName+":activate():  END");
+    }
+
+    /**
+     * Compares key parts of the state from the current instance of 
+     * this class with the specified instance to see if they are 
+     * equivalent. 
+     * <P>
+     * This differs from the java.lang.Object.equals() method in
+     * that the equals() method generally looks at both the 
+     * object identity (location in memory) and the object state
+     * (data).
+     * <P>
+     * 
+     * @param ctx  The object to compare with
+     * @return TRUE if this object is equivalent with the specified object
+     *              that is, key fields match
+     *         FALSE, otherwise
+     */
+    public boolean isEquivalent(ServiceGroupContext ctx)
+    {
+        // NOTE: the input object is expected to exist (ie, be non-null)
+
+        if (!this.axisServiceGroup.equals(ctx.getDescription()))
+        {
+            return false;
+        }
+
+        String ctxid = ctx.getId();
+
+        if ((this.id != null) && (ctxid != null))
+        {
+            if (!this.id.equals(ctxid))
+            {
+                return false;
+            }
+
+        }
+        else if ((this.id == null) && (ctxid == null)) 
+        {
+            // keep going
+        }
+        else
+        {
+            // mismatch
+            return false;
+        }
+
+
+
+        // TODO: consider checking the parent objects for equivalency
+
+        // TODO: consider checking fields from the super class for equivalency
+
+        return true;
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: axis-cvs-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-cvs-help@ws.apache.org


Mime
View raw message