0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019:
0020: package org.apache.axis2.context;
0021:
0022: import org.apache.axiom.om.util.UUIDGenerator;
0023: import org.apache.axis2.AxisFault;
0024: import org.apache.axis2.description.AxisOperation;
0025: import org.apache.axis2.description.AxisService;
0026: import org.apache.axis2.engine.AxisConfiguration;
0027: import org.apache.axis2.util.MetaDataEntry;
0028: import org.apache.axis2.util.ObjectStateUtils;
0029: import org.apache.commons.logging.Log;
0030: import org.apache.commons.logging.LogFactory;
0031:
0032: import javax.xml.namespace.QName;
0033: import java.io.Externalizable;
0034: import java.io.IOException;
0035: import java.io.ObjectInput;
0036: import java.io.ObjectOutput;
0037: import java.util.HashMap;
0038: import java.util.Iterator;
0039: import java.util.Map;
0040: import java.util.Set;
0041:
0042: /**
0043: * An OperationContext represents a running "instance" of an operation, which is
0044: * represented by an AxisOperation object. This concept is needed to allow
0045: * messages to be grouped into operations as in WSDL 2.0-speak operations are
0046: * essentially arbitrary message exchange patterns. So as messages are being
0047: * exchanged the OperationContext remembers the state of where in the message
0048: * exchange pattern it is in.
0049: * <p/>
0050: * The base implementation of OperationContext
0051: * supports MEPs which have one input message and/or one output message. That
0052: * is, it supports the all the MEPs that are in the WSDL 2.0 specification. In
0053: * order to support another MEP one must extend this class and register its
0054: * creation in the OperationContexFactory.
0055: */
0056: public class OperationContext extends AbstractContext implements
0057: Externalizable {
0058:
0059: /*
0060: * setup for logging
0061: */
0062: private static final Log log = LogFactory
0063: .getLog(OperationContext.class);
0064:
0065: private static final String myClassName = "OperationContext";
0066:
0067: /**
0068: * An ID which can be used to correlate operations on an instance of
0069: * this object in the log files
0070: */
0071: private String logCorrelationIDString = myClassName + "@"
0072: + UUIDGenerator.getUUID();
0073:
0074: /**
0075: * @serial The serialization version ID tracks the version of the class.
0076: * If a class definition changes, then the serialization/externalization
0077: * of the class is affected. If a change to the class is made which is
0078: * not compatible with the serialization/externalization of the class,
0079: * then the serialization version ID should be updated.
0080: * Refer to the "serialVer" utility to compute a serialization
0081: * version ID.
0082: */
0083: private static final long serialVersionUID = -7264782778333554350L;
0084:
0085: /**
0086: * @serial Tracks the revision level of a class to identify changes to the
0087: * class definition that are compatible to serialization/externalization.
0088: * If a class definition changes, then the serialization/externalization
0089: * of the class is affected.
0090: * Refer to the writeExternal() and readExternal() methods.
0091: */
0092: // supported revision levels, add a new level to manage compatible changes
0093: private static final int REVISION_1 = 1;
0094: // current revision level of this object
0095: private static final int revisionID = REVISION_1;
0096:
0097: /**
0098: * @serial isComplete flag
0099: */
0100: private boolean isComplete;
0101:
0102: /**
0103: * @serial key string
0104: */
0105: //The key value of the operationContextMap;
0106: private String key;
0107:
0108: // the AxisOperation of which this is a running instance. The MEP of this
0109: // AxisOperation must be one of the 8 predefined ones in WSDL 2.0.
0110: private transient AxisOperation axisOperation;
0111:
0112: /**
0113: * the set of message contexts associated with this operation
0114: */
0115: private transient HashMap messageContexts;
0116:
0117: //----------------------------------------------------------------
0118: // MetaData for data to be restored in activate after readExternal
0119: //----------------------------------------------------------------
0120:
0121: /**
0122: * Indicates whether the message context has been reconstituted
0123: * and needs to have its object references reconciled
0124: */
0125: private transient boolean needsToBeReconciled = false;
0126:
0127: /**
0128: * Suppresses warning messages for activation
0129: * when doing internal reconciliation
0130: */
0131: private transient boolean suppressWarnings = false;
0132:
0133: /**
0134: * The AxisOperation metadata will be used during
0135: * activate to match up with an existing object
0136: */
0137: private transient MetaDataEntry metaAxisOperation = null;
0138:
0139: /**
0140: * The AxisService metadata will be used during
0141: * activate to match up with an existing object
0142: */
0143: private transient MetaDataEntry metaAxisService = null;
0144:
0145: /**
0146: * The ServiceContext metadata will be used during
0147: * activate to match up with an existing object
0148: */
0149: private transient ServiceContext metaParent = null;
0150:
0151: /**
0152: * This is used to hold information about message context objects
0153: * that are in the messageContexts map. This allows message context
0154: * objects to be isolated from the object graph so that duplicate
0155: * copies of objects are not saved/restored.
0156: */
0157: private HashMap metaMessageContextMap = null;
0158:
0159: /**
0160: * This is used to hold temporarily any message context objects
0161: * that were isolated from the messageContexts map.
0162: */
0163: private transient HashMap isolatedMessageContexts = null;
0164:
0165: /**
0166: * This is used to hold temporarily any message context objects
0167: * from the messageContexts map for save/restore activities.
0168: */
0169: private transient HashMap workingSet = null;
0170:
0171: //----------------------------------------------------------------
0172: // end MetaData section
0173: //----------------------------------------------------------------
0174:
0175: /**
0176: * Simple constructor (needed for deserialization, shouldn't be used otherwise!)
0177: */
0178: public OperationContext() {
0179: super (null);
0180: this .messageContexts = new HashMap();
0181: }
0182:
0183: /**
0184: * Constructs a new OperationContext.
0185: *
0186: * @param axisOperation the AxisOperation whose running instances' state this
0187: * OperationContext represents.
0188: * @param serviceContext the parent ServiceContext representing any state related to
0189: * the set of all operations of the service.
0190: */
0191: public OperationContext(AxisOperation axisOperation,
0192: ServiceContext serviceContext) {
0193: super (serviceContext);
0194: this .messageContexts = new HashMap();
0195: this .axisOperation = axisOperation;
0196: this .setParent(serviceContext);
0197: }
0198:
0199: /**
0200: * When a new message is added to the <code>MEPContext</code> the logic
0201: * should be included remove the MEPContext from the table in the
0202: * <code>EngineContext</code>. Example: IN_IN_OUT At the second IN
0203: * message the MEPContext should be removed from the AxisOperation.
0204: *
0205: * @param msgContext
0206: */
0207: public void addMessageContext(MessageContext msgContext)
0208: throws AxisFault {
0209: if (axisOperation != null) {
0210: axisOperation.addMessageContext(msgContext, this );
0211: touch();
0212: }
0213: }
0214:
0215: /**
0216: * Removes the pointers to this <code>OperationContext</code> in the
0217: * <code>ConfigurationContext</code>'s OperationContextMap so that this
0218: * <code>OperationContext</code> will eventually get garbage collected
0219: * along with the <code>MessageContext</code>'s it contains. Note that if
0220: * the caller wants to make sure its safe to clean up this OperationContext
0221: * he should call isComplete() first. However, in cases like IN_OPTIONAL_OUT
0222: * and OUT_OPTIONAL_IN, it is possibe this will get called without the MEP
0223: * being complete due to the optional nature of the MEP.
0224: */
0225: public void cleanup() {
0226: ServiceContext serv = getServiceContext();
0227:
0228: if (serv != null) {
0229: serv.getConfigurationContext().unregisterOperationContext(
0230: key);
0231: }
0232: }
0233:
0234: /**
0235: * @return Returns the axisOperation.
0236: */
0237: public AxisOperation getAxisOperation() {
0238: if (needsToBeReconciled && !suppressWarnings) {
0239: log
0240: .warn(logCorrelationIDString
0241: + ":getAxisOperation(): ****WARNING**** OperationContext.activate(configurationContext) needs to be invoked.");
0242: }
0243:
0244: return axisOperation;
0245: }
0246:
0247: /**
0248: * Returns the EngineContext in which the parent ServiceContext lives.
0249: *
0250: * @return Returns parent ServiceContext's parent EngineContext.
0251: */
0252: public ConfigurationContext getConfigurationContext() {
0253: if (parent != null) {
0254: return ((ServiceContext) parent).getConfigurationContext();
0255: } else {
0256: return null;
0257: }
0258: }
0259:
0260: /**
0261: * @param messageLabel
0262: * @return Returns MessageContext.
0263: * @throws AxisFault
0264: */
0265: public MessageContext getMessageContext(String messageLabel)
0266: throws AxisFault {
0267: if (messageContexts == null) {
0268: return null;
0269: }
0270:
0271: return (MessageContext) messageContexts.get(messageLabel);
0272:
0273: }
0274:
0275: public HashMap getMessageContexts() {
0276: return messageContexts;
0277: }
0278:
0279: /**
0280: * Returns the ServiceContext in which this OperationContext lives.
0281: *
0282: * @return Returns parent ServiceContext.
0283: */
0284: public ServiceContext getServiceContext() {
0285: return (ServiceContext) parent;
0286: }
0287:
0288: /**
0289: * Checks to see if the MEP is complete. i.e. whether all the messages that
0290: * are associated with the MEP has arrived and MEP is complete.
0291: */
0292: public boolean isComplete() {
0293: return isComplete;
0294: }
0295:
0296: public void setComplete(boolean complete) {
0297: isComplete = complete;
0298: }
0299:
0300: public void setKey(String key) {
0301: this .key = key;
0302: }
0303:
0304: /* ===============================================================
0305: * Externalizable support
0306: * ===============================================================
0307: */
0308:
0309: /**
0310: * Save the contents of this object.
0311: * <p/>
0312: * NOTE: Transient fields and static fields are not saved.
0313: * Also, objects that represent "static" data are
0314: * not saved, except for enough information to be
0315: * able to find matching objects when the message
0316: * context is re-constituted.
0317: *
0318: * @param out The stream to write the object contents to
0319: * @throws IOException
0320: */
0321: public void writeExternal(ObjectOutput out) throws IOException {
0322: //---------------------------------------------------------
0323: // in order to handle future changes to the message
0324: // context definition, be sure to maintain the
0325: // object level identifiers
0326: //---------------------------------------------------------
0327: // serialization version ID
0328: out.writeLong(serialVersionUID);
0329:
0330: // revision ID
0331: out.writeInt(revisionID);
0332:
0333: //---------------------------------------------------------
0334: // various simple fields
0335: //---------------------------------------------------------
0336:
0337: out.writeLong(getLastTouchedTime());
0338:
0339: out.writeBoolean(isComplete);
0340:
0341: ObjectStateUtils.writeString(out, key, logCorrelationIDString
0342: + ".key");
0343:
0344: ObjectStateUtils.writeString(out, logCorrelationIDString,
0345: logCorrelationIDString + ".logCorrelationIDString");
0346:
0347: //---------------------------------------------------------
0348: // properties
0349: //---------------------------------------------------------
0350: Map tmpMap = getProperties();
0351:
0352: HashMap tmpHashMap = null;
0353:
0354: if ((tmpMap != null) && (!tmpMap.isEmpty())) {
0355: tmpHashMap = new HashMap(tmpMap);
0356: }
0357:
0358: ObjectStateUtils.writeHashMap(out, tmpHashMap,
0359: logCorrelationIDString + ".properties");
0360:
0361: //---------------------------------------------------------
0362: // AxisOperation axisOperation
0363: //---------------------------------------------------------
0364: String axisOpMarker = logCorrelationIDString + ".axisOperation";
0365: ObjectStateUtils.writeString(out, axisOpMarker, axisOpMarker);
0366:
0367: if (axisOperation == null) {
0368: out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
0369: } else {
0370: out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
0371: metaAxisOperation = new MetaDataEntry(axisOperation
0372: .getClass().getName(), axisOperation.getName()
0373: .toString());
0374: ObjectStateUtils.writeObject(out, metaAxisOperation,
0375: logCorrelationIDString + ".metaAxisOperation");
0376: }
0377:
0378: // save the meta data for the corresponding axis service to better
0379: // match up the axis operation
0380:
0381: String axisServMarker = logCorrelationIDString
0382: + ".metaAxisService";
0383: ObjectStateUtils.writeString(out, axisServMarker,
0384: axisServMarker);
0385:
0386: AxisService axisService = axisOperation.getAxisService();
0387:
0388: if (axisService == null) {
0389: out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
0390: } else {
0391: out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
0392: metaAxisService = new MetaDataEntry(axisService.getClass()
0393: .getName(), axisService.getName());
0394: ObjectStateUtils.writeObject(out, metaAxisService,
0395: logCorrelationIDString + ".metaAxisService");
0396: }
0397:
0398: //---------------------------------------------------------
0399: // parent
0400: //---------------------------------------------------------
0401: ServiceContext myParent = this .getServiceContext();
0402:
0403: ObjectStateUtils.writeObject(out, myParent,
0404: logCorrelationIDString + ".parent ServiceContext");
0405:
0406: //---------------------------------------------------------
0407: // HashMap messageContexts table
0408: //---------------------------------------------------------
0409:
0410: // NOTES: The assumption is that the table contains message contexts
0411: // that are in the OperationContext hierarchy. To reduce overlap
0412: // of object information that is being saved, extract the
0413: // message context objects from the hierachy before saving.
0414: // When the OperationContext is restored, the "slimmed down"
0415: // message context objects are plugged back into the hierachy
0416: // using the restored OperationContext as a basis.
0417:
0418: // first deal with the original messageContexts table
0419: HashMap tmpMsgCtxMap = null;
0420:
0421: if ((messageContexts != null) && (!messageContexts.isEmpty())) {
0422: // create a table of the non-isolated message contexts
0423: workingSet = new HashMap();
0424: tmpMsgCtxMap = new HashMap();
0425:
0426: Set keySet = messageContexts.keySet();
0427: Iterator itKeys = keySet.iterator();
0428:
0429: while (itKeys.hasNext()) {
0430: // expect the key to be a string
0431: String keyObj = (String) itKeys.next();
0432:
0433: // get the message context associated with that label
0434: MessageContext value = (MessageContext) messageContexts
0435: .get(keyObj);
0436:
0437: boolean addToWorkingSet = true;
0438:
0439: // check to see if this message context was isolated
0440: if (isolatedMessageContexts != null) {
0441: if (!isolatedMessageContexts.isEmpty()) {
0442: // see if the message context was previously isolated
0443: MessageContext valueIsolated = (MessageContext) isolatedMessageContexts
0444: .get(keyObj);
0445:
0446: if (valueIsolated != null) {
0447: String idIsol = valueIsolated
0448: .getMessageID();
0449:
0450: if (idIsol != null) {
0451: if (idIsol.equals(value.getMessageID())) {
0452: // don't add to working set
0453: addToWorkingSet = false;
0454: }
0455: }
0456: }
0457: }
0458: }
0459:
0460: if (addToWorkingSet) {
0461: // put the meta data entry in the list
0462: workingSet.put(keyObj, value);
0463: }
0464:
0465: }
0466:
0467: // now we have a working set
0468:
0469: Set keySet2 = workingSet.keySet();
0470: Iterator itKeys2 = keySet2.iterator();
0471:
0472: while (itKeys2.hasNext()) {
0473: // expect the key to be a string
0474: String keyObj2 = (String) itKeys2.next();
0475:
0476: // get the message context associated with that label
0477: MessageContext value2 = (MessageContext) workingSet
0478: .get(keyObj2);
0479:
0480: // construct a copy of the message context
0481: // that has been extracted from the object hierarchy
0482: MessageContext modifiedValue2 = value2
0483: .extractCopyMessageContext();
0484:
0485: // put the modified entry in the list
0486: tmpMsgCtxMap.put(keyObj2, modifiedValue2);
0487:
0488: // trace point
0489: log
0490: .trace(logCorrelationIDString
0491: + ":writeExternal(): getting working set entry key ["
0492: + keyObj2 + "] message context ID["
0493: + modifiedValue2.getMessageID() + "]");
0494: }
0495:
0496: }
0497:
0498: ObjectStateUtils
0499: .writeHashMap(out, tmpMsgCtxMap, logCorrelationIDString
0500: + ".messageContexts working set");
0501:
0502: // next, deal with the metadata table of messageContexts
0503: ObjectStateUtils.writeHashMap(out, metaMessageContextMap,
0504: logCorrelationIDString
0505: + ".metaMessageContextMap metadata table");
0506:
0507: //---------------------------------------------------------
0508: // done
0509: //---------------------------------------------------------
0510:
0511: }
0512:
0513: /**
0514: * Restore the contents of the object that was previously saved.
0515: * <p/>
0516: * NOTE: The field data must read back in the same order and type
0517: * as it was written. Some data will need to be validated when
0518: * resurrected.
0519: *
0520: * @param in The stream to read the object contents from
0521: * @throws IOException
0522: * @throws ClassNotFoundException
0523: */
0524: public void readExternal(ObjectInput in) throws IOException,
0525: ClassNotFoundException {
0526: // set the flag to indicate that the message context is being
0527: // reconstituted and will need to have certain object references
0528: // to be reconciled with the current engine setup
0529: needsToBeReconciled = true;
0530:
0531: // trace point
0532: log
0533: .trace(myClassName
0534: + ":readExternal(): BEGIN bytes available in stream ["
0535: + in.available() + "] ");
0536:
0537: //---------------------------------------------------------
0538: // object level identifiers
0539: //---------------------------------------------------------
0540:
0541: // serialization version ID
0542: long suid = in.readLong();
0543:
0544: // revision ID
0545: int revID = in.readInt();
0546:
0547: // make sure the object data is in a version we can handle
0548: if (suid != serialVersionUID) {
0549: throw new ClassNotFoundException(
0550: ObjectStateUtils.UNSUPPORTED_SUID);
0551: }
0552:
0553: // make sure the object data is in a revision level we can handle
0554: if (revID != REVISION_1) {
0555: throw new ClassNotFoundException(
0556: ObjectStateUtils.UNSUPPORTED_REVID);
0557: }
0558:
0559: //---------------------------------------------------------
0560: // various simple fields
0561: //---------------------------------------------------------
0562:
0563: long time = in.readLong();
0564: setLastTouchedTime(time);
0565:
0566: isComplete = in.readBoolean();
0567:
0568: key = ObjectStateUtils.readString(in, "OperationContext.key");
0569:
0570: logCorrelationIDString = ObjectStateUtils.readString(in,
0571: "OperationContext.logCorrelationIDString");
0572:
0573: // trace point
0574: log.trace(myClassName
0575: + ":readExternal(): reading input stream for ["
0576: + logCorrelationIDString + "] ");
0577:
0578: //---------------------------------------------------------
0579: // properties
0580: //---------------------------------------------------------
0581:
0582: HashMap tmpHashMap = ObjectStateUtils.readHashMap(in,
0583: "OperationContext.properties");
0584:
0585: properties = new HashMap();
0586: if (tmpHashMap != null) {
0587: setProperties(tmpHashMap);
0588: }
0589:
0590: //---------------------------------------------------------
0591: // axis operation meta data
0592: //---------------------------------------------------------
0593:
0594: // axisOperation is not usable until the meta data has been reconciled
0595: axisOperation = null;
0596:
0597: ObjectStateUtils.readString(in,
0598: "OperationContext.axisOperation");
0599:
0600: boolean metaAxisOperationIsActive = in.readBoolean();
0601:
0602: if (metaAxisOperationIsActive == ObjectStateUtils.ACTIVE_OBJECT) {
0603: metaAxisOperation = (MetaDataEntry) ObjectStateUtils
0604: .readObject(in,
0605: "OperationContext.metaAxisOperation");
0606: } else {
0607: metaAxisOperation = null;
0608: }
0609:
0610: // axisService is not usable until the meta data has been reconciled
0611:
0612: ObjectStateUtils.readString(in, "OperationContext.axisService");
0613:
0614: boolean metaAxisServiceIsActive = in.readBoolean();
0615:
0616: if (metaAxisServiceIsActive == ObjectStateUtils.ACTIVE_OBJECT) {
0617: metaAxisService = (MetaDataEntry) ObjectStateUtils
0618: .readObject(in, "OperationContext.metaAxisService");
0619: } else {
0620: metaAxisService = null;
0621: }
0622:
0623: //---------------------------------------------------------
0624: // parent
0625: //---------------------------------------------------------
0626:
0627: // ServiceContext is not usable until it has been activated
0628:
0629: metaParent = (ServiceContext) ObjectStateUtils.readObject(in,
0630: "OperationContext.parent ServiceContext");
0631:
0632: //---------------------------------------------------------
0633: // HashMap messageContexts table
0634: //---------------------------------------------------------
0635:
0636: // set to empty until this can be activiated
0637: messageContexts = new HashMap();
0638:
0639: workingSet = ObjectStateUtils
0640: .readHashMap(in, logCorrelationIDString
0641: + ".messageContexts working set");
0642:
0643: metaMessageContextMap = ObjectStateUtils.readHashMap(in,
0644: logCorrelationIDString
0645: + ".metaMessageContextMap metadata table");
0646:
0647: //---------------------------------------------------------
0648: // done
0649: //---------------------------------------------------------
0650:
0651: }
0652:
0653: /**
0654: * This method checks to see if additional work needs to be
0655: * done in order to complete the object reconstitution.
0656: * Some parts of the object restored from the readExternal()
0657: * cannot be completed until we have a configurationContext
0658: * from the active engine. The configurationContext is used
0659: * to help this object to plug back into the engine's
0660: * configuration and deployment objects.
0661: *
0662: * @param cc The configuration context object representing the active configuration
0663: */
0664: public void activate(ConfigurationContext cc) {
0665: // see if there's any work to do
0666: if (!needsToBeReconciled) {
0667: // return quick
0668: return;
0669: }
0670:
0671: // get the axis configuration
0672: AxisConfiguration axisConfig = cc.getAxisConfiguration();
0673:
0674: // We previously saved metaAxisService; restore it
0675: AxisService axisService = null;
0676:
0677: if (metaAxisService != null) {
0678: axisService = ObjectStateUtils.findService(axisConfig,
0679: metaAxisService.getClassName(), metaAxisService
0680: .getQNameAsString());
0681: }
0682:
0683: // We previously saved metaAxisOperation; restore it
0684: if (metaAxisOperation != null) {
0685: if (axisService != null) {
0686: this .axisOperation = ObjectStateUtils.findOperation(
0687: axisService, metaAxisOperation.getClassName(),
0688: metaAxisOperation.getQName());
0689: } else {
0690: this .axisOperation = ObjectStateUtils.findOperation(
0691: axisConfig, metaAxisOperation.getClassName(),
0692: metaAxisOperation.getQName());
0693: }
0694: }
0695:
0696: // the parent ServiceContext object was saved
0697: // either use the restored object or sync up with
0698: // an existing ServiceContext object
0699: if (metaParent != null) {
0700: // find out if a copy of the ServiceContext object exists on this
0701: // engine where this OperationContext is being restored/activated
0702: // if so, use that object instead of the restored object
0703: // in order to make sure that future changes to service-level
0704: // properties are preserved for future operations
0705: String groupName = metaParent.getGroupName();
0706: String serviceName = metaParent.getName();
0707:
0708: ServiceContext existingSC = null;
0709:
0710: // first look for the ServiceContext via the ServiceContextGroup
0711: ServiceGroupContext sgc = cc
0712: .getServiceGroupContext(groupName);
0713:
0714: if (sgc != null) {
0715: existingSC = sgc.findServiceContext(serviceName);
0716: }
0717:
0718: if (existingSC == null) {
0719: // we couldn't find the ServiceContext via the ServiceContextGroup
0720: // try via the set of existing operation contexts
0721: OperationContext existingOC = cc.findOperationContext(
0722: getOperationName(), serviceName, groupName);
0723:
0724: if (existingOC != null) {
0725: existingSC = (ServiceContext) existingOC
0726: .getParent();
0727: }
0728: }
0729:
0730: if (existingSC == null) {
0731: // could not find an existing ServiceContext
0732: // use the restored object
0733: metaParent.activate(cc);
0734:
0735: // set parent
0736: this .setParent(metaParent);
0737: } else {
0738: // switch over to the existing object
0739: this .setParent(existingSC);
0740:
0741: // do a copy of the properties from the restored object
0742: // to the existing ServiceContext
0743: // Should the copy be a non-destructive one? That is,
0744: // if the key already exists in the properties table of the
0745: // existing object, should the value be overwritten from the
0746: // restored ojbect? For now, the decision is that the state
0747: // that has been preserved for a saved context object is
0748: // is important to be restored.
0749: metaParent.putContextProperties(existingSC, true);
0750: }
0751: } else {
0752: // set parent to null
0753: this .setParent(metaParent);
0754: }
0755:
0756: // reseed the operation context map
0757:
0758: ServiceContext serv = getServiceContext();
0759: ConfigurationContext activeCC;
0760: if (serv != null) {
0761: activeCC = serv.getConfigurationContext();
0762: } else {
0763: activeCC = cc;
0764: }
0765:
0766: if (key != null) {
0767: // make sure this OperationContext object is registered in the
0768: // list maintained by the ConfigurationContext object
0769: boolean registrationSuceeded = activeCC
0770: .registerOperationContext(key, this );
0771: if (!registrationSuceeded) {
0772: // trace point
0773: log
0774: .trace(logCorrelationIDString
0775: + ":activate(): OperationContext key ["
0776: + key
0777: + "] already exists in ConfigurationContext map. This OperationContext ["
0778: + this .toString()
0779: + "] was not added to the table.");
0780: }
0781: }
0782:
0783: //-------------------------------------------------------
0784: // update the modified entries in the messageContexts table
0785: //-------------------------------------------------------
0786: // NOTE: an entry in the metaMessageContextMap must wait
0787: // for its corresponding active message context object
0788: // to call this operation context object so we don't
0789: // need to handle the metaMessagecontextMap table here
0790:
0791: if ((workingSet != null) && (!workingSet.isEmpty())) {
0792: Set keySet = workingSet.keySet();
0793: Iterator itKeys = keySet.iterator();
0794:
0795: while (itKeys.hasNext()) {
0796: // expect the key to be a string
0797: String keyObj = (String) itKeys.next();
0798:
0799: // get the message context associated with that label
0800: MessageContext value = (MessageContext) workingSet
0801: .get((Object) keyObj);
0802:
0803: // activate that object
0804: if (value != null) {
0805: // trace point
0806: log.trace(logCorrelationIDString
0807: + ":activate(): key [" + keyObj
0808: + "] message id [" + value.getMessageID()
0809: + "]");
0810:
0811: suppressWarnings = true;
0812: value.activateWithOperationContext(this );
0813: suppressWarnings = false;
0814:
0815: if (messageContexts == null) {
0816: messageContexts = new HashMap();
0817: }
0818: }
0819:
0820: // put the entry in the "real" table
0821: // note that the key or the value could be null
0822: messageContexts.put(keyObj, value);
0823: }
0824: }
0825:
0826: //-------------------------------------------------------
0827: // done, reset the flag
0828: //-------------------------------------------------------
0829: needsToBeReconciled = false;
0830:
0831: }
0832:
0833: /**
0834: * Isolate the specified message context object
0835: * to prepare for serialization. Instead of
0836: * saving the entire message context object,
0837: * just setup some metadata about the message
0838: * context.
0839: * <p/>
0840: * Note: this will remove the specified
0841: * message context object from the message context
0842: * table.
0843: *
0844: * @param mc The message context object
0845: */
0846: public void isolateMessageContext(MessageContext mc) {
0847: if (mc == null) {
0848: return;
0849: }
0850:
0851: if ((messageContexts == null) || (messageContexts.isEmpty())) {
0852: return;
0853: }
0854:
0855: // get the message ID from the message context
0856: String messageID = mc.getMessageID();
0857:
0858: if (messageID == null) {
0859: // can't locate it without identification
0860: return;
0861: }
0862:
0863: Iterator it = messageContexts.keySet().iterator();
0864:
0865: while (it.hasNext()) {
0866: // get the key
0867: Object keyObj = it.next();
0868:
0869: // get the value associated with that key
0870: MessageContext value = (MessageContext) messageContexts
0871: .get(keyObj);
0872:
0873: if (value != null) {
0874: String valueID = value.getMessageID();
0875:
0876: if ((valueID != null) && valueID.equals(messageID)) {
0877: // found the input message context in our table
0878:
0879: if (metaMessageContextMap == null) {
0880: metaMessageContextMap = new HashMap();
0881: }
0882:
0883: // build a meta data entry
0884: // MessageContext class name
0885: // MessageContext messageID
0886: // key used in the original hashmap that is associated with this MessageContext
0887: // note: this is typically something like "In", "Out", "Fault"
0888: //
0889: MetaDataEntry metaData = new MetaDataEntry(value
0890: .getClass().getName(),
0891: value.getMessageID(), keyObj.toString());
0892:
0893: // put the meta data entry in the list
0894: // note that if the entry was already in the list,
0895: // this will replace that entry
0896: metaMessageContextMap.put(keyObj, metaData);
0897:
0898: // don't change the original table - there's potentially lots of areas that
0899: // grab the table
0900: // // now remove the original entry from the messageContexts table
0901: // messageContexts.remove(keyObj);
0902:
0903: // put the original entry in the temporary list
0904: if (isolatedMessageContexts == null) {
0905: isolatedMessageContexts = new HashMap();
0906: }
0907:
0908: // note that if the entry was already in the list,
0909: // this will replace that entry
0910: isolatedMessageContexts.put(keyObj, value);
0911:
0912: // trace point
0913: log
0914: .trace(logCorrelationIDString
0915: + ":isolateMessageContext(): set up message context id["
0916: + valueID
0917: + "] with key ["
0918: + keyObj.toString()
0919: + "] from messageContexts table to prepare for serialization.");
0920:
0921: break;
0922: }
0923: }
0924: }
0925: }
0926:
0927: /**
0928: * Restore the specified MessageContext object in the
0929: * table used to hold the message contexts associated
0930: * with this operation.
0931: *
0932: * @param msg The message context object
0933: */
0934: public void restoreMessageContext(MessageContext msg) {
0935: // see if the activation has been done
0936: if (needsToBeReconciled) {
0937: // nope, need to do the activation first
0938: log
0939: .trace(logCorrelationIDString
0940: + ":restoreMessageContext(): *** WARNING : need to invoke activate() prior to restoring the MessageContext to the list.");
0941:
0942: return;
0943: }
0944:
0945: if (msg == null) {
0946: return;
0947: }
0948:
0949: String msgID = msg.getMessageID();
0950:
0951: if (msgID == null) {
0952: // can't identify message context
0953: log
0954: .trace(logCorrelationIDString
0955: + ":restoreMessageContext(): *** WARNING : MessageContext does not have a message ID.");
0956: return;
0957: }
0958:
0959: // first check the metaMessageContextMap to see if
0960: // the specified message context object matches any
0961: // of the metadata entries.
0962:
0963: if ((metaMessageContextMap != null)
0964: && (!metaMessageContextMap.isEmpty())) {
0965: Iterator itMeta = metaMessageContextMap.keySet().iterator();
0966:
0967: while (itMeta.hasNext()) {
0968: String keyM = (String) itMeta.next();
0969:
0970: MetaDataEntry valueM = (MetaDataEntry) metaMessageContextMap
0971: .get(keyM);
0972: String valueM_ID;
0973:
0974: if (valueM != null) {
0975: valueM_ID = valueM.getQNameAsString();
0976:
0977: if (msgID.equals(valueM_ID)) {
0978: String label = valueM.getExtraName();
0979:
0980: if (messageContexts == null) {
0981: messageContexts = new HashMap();
0982: }
0983:
0984: // put the message context into the messageContexts table
0985: messageContexts.put(label, msg);
0986:
0987: // remove the metadata from the metadata table
0988: metaMessageContextMap.remove(keyM);
0989:
0990: log
0991: .trace(logCorrelationIDString
0992: + ":restoreMessageContext(): restored label ["
0993: + label + "] message ID ["
0994: + msg.getMessageID() + "]");
0995:
0996: break;
0997: }
0998: }
0999: }
1000: } else
1001: // see if we can put the msg directly in the messageContexts table
1002: if ((messageContexts != null) && (!messageContexts.isEmpty())) {
1003: Iterator itList = messageContexts.keySet().iterator();
1004:
1005: while (itList.hasNext()) {
1006: String key = (String) itList.next();
1007:
1008: MessageContext value = (MessageContext) messageContexts
1009: .get(key);
1010: String valueID;
1011:
1012: if (value != null) {
1013: valueID = value.getMessageID();
1014:
1015: if (msgID.equals(valueID)) {
1016: // update the entry
1017: messageContexts.put(key, msg);
1018: }
1019: }
1020: }
1021: }
1022:
1023: }
1024:
1025: /**
1026: * Get the name associated with the operation.
1027: *
1028: * @return The name String
1029: */
1030: public String getOperationName() {
1031: String opName = null;
1032:
1033: if (axisOperation != null) {
1034: QName qname = axisOperation.getName();
1035: if (qname != null) {
1036: opName = qname.getLocalPart();
1037: }
1038: }
1039:
1040: return opName;
1041: }
1042:
1043: /**
1044: * Get the name associated with the service.
1045: *
1046: * @return The name String
1047: */
1048: public String getServiceName() {
1049: String srvName = null;
1050:
1051: ServiceContext sc = (ServiceContext) getParent();
1052:
1053: if (sc == null) {
1054: sc = metaParent;
1055: }
1056:
1057: if (sc != null) {
1058: srvName = sc.getName();
1059: }
1060:
1061: return srvName;
1062: }
1063:
1064: /**
1065: * Get the name associated with the service group.
1066: *
1067: * @return The name String
1068: */
1069: public String getServiceGroupName() {
1070: String srvGroupName = null;
1071:
1072: ServiceContext sc = (ServiceContext) getParent();
1073:
1074: if (sc == null) {
1075: sc = metaParent;
1076: }
1077:
1078: if (sc != null) {
1079: srvGroupName = sc.getGroupName();
1080: }
1081:
1082: return srvGroupName;
1083: }
1084:
1085: /**
1086: * Compares key parts of the state from the current instance of
1087: * this class with the specified instance to see if they are
1088: * equivalent.
1089: * <p/>
1090: * This differs from the java.lang.Object.equals() method in
1091: * that the equals() method generally looks at both the
1092: * object identity (location in memory) and the object state
1093: * (data).
1094: * <p/>
1095: *
1096: * @param ctx The object to compare with
1097: * @return TRUE if this object is equivalent with the specified object
1098: * that is, key fields match
1099: * FALSE, otherwise
1100: */
1101: public boolean isEquivalent(OperationContext ctx) {
1102: // NOTE: the input object is expected to exist (ie, be non-null)
1103:
1104: if (this .isComplete != ctx.isComplete()) {
1105: return false;
1106: }
1107:
1108: if (!this .axisOperation.equals(ctx.getAxisOperation())) {
1109: return false;
1110: }
1111:
1112: // TODO: consider checking the parent objects for equivalency
1113:
1114: // TODO: consider checking fields from the super class for equivalency
1115:
1116: return true;
1117: }
1118:
1119: /**
1120: * Get the ID associated with this object instance.
1121: *
1122: * @return A string that can be output to a log file as an identifier
1123: * for this object instance. It is suitable for matching related log
1124: * entries.
1125: */
1126: public String getLogCorrelationIDString() {
1127: return logCorrelationIDString;
1128: }
1129:
1130: public ConfigurationContext getRootContext() {
1131: return this.getConfigurationContext();
1132: }
1133:
1134: }
|