001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.context;
021:
022: import org.apache.axiom.om.util.UUIDGenerator;
023: import org.apache.axis2.AxisFault;
024: import org.apache.axis2.addressing.EndpointReference;
025: import org.apache.axis2.description.AxisOperation;
026: import org.apache.axis2.description.AxisService;
027: import org.apache.axis2.description.TransportInDescription;
028: import org.apache.axis2.engine.AxisConfiguration;
029: import org.apache.axis2.engine.ListenerManager;
030: import org.apache.axis2.i18n.Messages;
031: import org.apache.axis2.util.LoggingControl;
032: import org.apache.axis2.util.MetaDataEntry;
033: import org.apache.axis2.util.ObjectStateUtils;
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036:
037: import javax.xml.namespace.QName;
038: import java.io.Externalizable;
039: import java.io.IOException;
040: import java.io.ObjectInput;
041: import java.io.ObjectOutput;
042: import java.util.HashMap;
043: import java.util.Map;
044:
045: /**
046: * Well this is never clearly defined, what it does or the life-cycle.
047: * So do NOT use this as it might not live up to your expectation.
048: */
049: public class ServiceContext extends AbstractContext implements
050: Externalizable {
051:
052: /*
053: * setup for logging
054: */
055: private static final Log log = LogFactory
056: .getLog(ServiceContext.class);
057:
058: private static final String myClassName = "ServiceContext";
059:
060: /**
061: * An ID which can be used to correlate operations on an instance of
062: * this object in the log files
063: */
064: private String logCorrelationIDString = myClassName + "@"
065: + UUIDGenerator.getUUID();
066:
067: /**
068: * @serial The serialization version ID tracks the version of the class.
069: * If a class definition changes, then the serialization/externalization
070: * of the class is affected. If a change to the class is made which is
071: * not compatible with the serialization/externalization of the class,
072: * then the serialization version ID should be updated.
073: * Refer to the "serialVer" utility to compute a serialization
074: * version ID.
075: */
076: private static final long serialVersionUID = 8265625275015738957L;
077:
078: /**
079: * @serial Tracks the revision level of a class to identify changes to the
080: * class definition that are compatible to serialization/externalization.
081: * If a class definition changes, then the serialization/externalization
082: * of the class is affected.
083: * Refer to the writeExternal() and readExternal() methods.
084: */
085: // supported revision levels, add a new level to manage compatible changes
086: private static final int REVISION_1 = 1;
087: // current revision level of this object
088: private static final int revisionID = REVISION_1;
089:
090: public static final String SERVICE_OBJECT = "serviceObject";
091:
092: private EndpointReference targetEPR;
093: private EndpointReference myEPR;
094:
095: private transient AxisService axisService;
096:
097: // the service group context is the same as the parent
098: private transient ServiceGroupContext serviceGroupContext;
099:
100: private transient ConfigurationContext configContext;
101:
102: /**
103: * Should we cache the last OperationContext?
104: */
105: private boolean cachingOperationContext;
106: /**
107: * A cache for the last OperationContext
108: */
109: private transient OperationContext lastOperationContext;
110:
111: //----------------------------------------------------------------
112: // MetaData for data to be restored in activate after readExternal
113: //----------------------------------------------------------------
114:
115: /**
116: * Indicates whether the message context has been reconstituted
117: * and needs to have its object references reconciled
118: */
119: private transient boolean needsToBeReconciled = false;
120:
121: /**
122: * The AxisService metadata will be used during
123: * activate to match up with an existing object
124: */
125: private transient MetaDataEntry metaAxisService = null;
126:
127: /**
128: * The ServiceGroupContext object will be used during
129: * activate to finish its restoration
130: */
131: private transient ServiceGroupContext metaParent = null;
132:
133: //----------------------------------------------------------------
134: // end MetaData section
135: //----------------------------------------------------------------
136:
137: /**
138: * Public constructor (only here because this class is Externalizable)
139: */
140: public ServiceContext() {
141: }
142:
143: /**
144: * Constructor (package access, should only be used by ServiceGroupContext)
145: *
146: * @param axisService the AxisService for which to create a context
147: * @param serviceGroupContext the parent ServiceGroupContext
148: */
149: ServiceContext(AxisService axisService,
150: ServiceGroupContext serviceGroupContext) {
151: super (serviceGroupContext);
152: this .serviceGroupContext = serviceGroupContext;
153: this .axisService = axisService;
154: this .configContext = (ConfigurationContext) parent.getParent();
155: }
156:
157: public OperationContext createOperationContext(QName name) {
158: AxisOperation axisOp = axisService.getOperation(name);
159: return createOperationContext(axisOp);
160: }
161:
162: public OperationContext createOperationContext(AxisOperation axisOp) {
163: OperationContext ctx = new OperationContext(axisOp, this );
164: configContext.contextCreated(ctx);
165: return ctx;
166: }
167:
168: public AxisService getAxisService() {
169: checkActivateWarning("getAxisService");
170: return axisService;
171: }
172:
173: public ConfigurationContext getConfigurationContext() {
174: checkActivateWarning("getConfigurationContext");
175: return configContext;
176: }
177:
178: public ServiceGroupContext getServiceGroupContext() {
179: checkActivateWarning("getServiceGroupContext");
180: return serviceGroupContext;
181: }
182:
183: /**
184: * To get the ERP for a given service , if the transport is present and not
185: * running then it will add as a listener to ListenerManager , there it will
186: * init that and start the listener , and finally ask the EPR from transport
187: * for a given service
188: *
189: * @param transport : Name of the transport
190: * @return
191: * @throws AxisFault
192: */
193: public EndpointReference getMyEPR(String transport)
194: throws AxisFault {
195: axisService.isEnableAllTransports();
196: ConfigurationContext configctx = this .configContext;
197: if (configctx != null) {
198: ListenerManager lm = configctx.getListenerManager();
199: if (!lm.isListenerRunning(transport)) {
200: TransportInDescription trsin = configctx
201: .getAxisConfiguration().getTransportIn(
202: transport);
203: if (trsin != null) {
204: lm.addListener(trsin, false);
205: } else {
206: throw new AxisFault(Messages.getMessage(
207: "transportnotfound", transport));
208: }
209: }
210: if (!lm.isStopped()) {
211: return lm.getEPRforService(axisService.getName(), null,
212: transport);
213: }
214: }
215: return null;
216: }
217:
218: public EndpointReference getTargetEPR() {
219: return targetEPR;
220: }
221:
222: public void setTargetEPR(EndpointReference targetEPR) {
223: this .targetEPR = targetEPR;
224: }
225:
226: public EndpointReference getMyEPR() {
227: if (myEPR == null) {
228: try {
229: if (ListenerManager.defaultConfigurationContext != null) {
230: ListenerManager listenerManager = ListenerManager.defaultConfigurationContext
231: .getListenerManager();
232: myEPR = listenerManager.getEPRforService(
233: axisService.getName(), null, null);
234: }
235: } catch (AxisFault axisFault) {
236: // what else I can do
237: myEPR = null;
238: }
239: }
240: return myEPR;
241: }
242:
243: public void setMyEPR(EndpointReference myEPR) {
244: this .myEPR = myEPR;
245: }
246:
247: public OperationContext getLastOperationContext() {
248: return lastOperationContext;
249: }
250:
251: public void setLastOperationContext(
252: OperationContext lastOperationContext) {
253: this .lastOperationContext = lastOperationContext;
254: }
255:
256: public boolean isCachingOperationContext() {
257: return cachingOperationContext;
258: }
259:
260: public void setCachingOperationContext(
261: boolean cacheLastOperationContext) {
262: this .cachingOperationContext = cacheLastOperationContext;
263: }
264:
265: /**
266: * Returns a name associated with this ServiceContext.
267: * <p/>
268: * Note: this name is from the corresponding
269: * AxisService object.
270: *
271: * @return The name string, or null if no name can be found
272: */
273: public String getName() {
274: if (axisService != null) {
275: return axisService.getName();
276: }
277:
278: if (metaAxisService != null) {
279: return metaAxisService.getName();
280: }
281:
282: return null;
283: }
284:
285: /**
286: * Returns a name associated with the ServiceGroupContext
287: * associated with this ServiceContext.
288: *
289: * @return The name string, or null if no name can be found
290: */
291: public String getGroupName() {
292: if (serviceGroupContext != null) {
293: return serviceGroupContext.getId();
294: }
295:
296: if (metaParent != null) {
297: return metaParent.getId();
298: }
299:
300: return null;
301: }
302:
303: /* ===============================================================
304: * Externalizable support
305: * ===============================================================
306: */
307:
308: /**
309: * Save the contents of this object.
310: * <p/>
311: * NOTE: Transient fields and static fields are not saved.
312: * Also, objects that represent "static" data are
313: * not saved, except for enough information to be
314: * able to find matching objects when the message
315: * context is re-constituted.
316: *
317: * @param out The stream to write the object contents to
318: * @throws IOException
319: */
320: public void writeExternal(ObjectOutput out) throws IOException {
321: //---------------------------------------------------------
322: // in order to handle future changes to the message
323: // context definition, be sure to maintain the
324: // object level identifiers
325: //---------------------------------------------------------
326: // serialization version ID
327: out.writeLong(serialVersionUID);
328:
329: // revision ID
330: out.writeInt(revisionID);
331:
332: //---------------------------------------------------------
333: // various simple fields
334: //---------------------------------------------------------
335:
336: out.writeLong(getLastTouchedTime());
337:
338: out.writeBoolean(cachingOperationContext);
339:
340: ObjectStateUtils.writeString(out, logCorrelationIDString,
341: logCorrelationIDString + ".logCorrelationIDString");
342:
343: // put some try..catch blocks around the following objects
344: // so that the writing to the output stream continues
345: // even if one of the objects can't be serialized
346:
347: try {
348: // EndpointReference targetEPR
349: ObjectStateUtils.writeObject(out, targetEPR,
350: "ServiceContext.targetEPR");
351: } catch (Exception e1) {
352: // note that the utility class will provide the trace for the
353: // exception so we won't have to
354: // so just consume the exception for now
355: }
356:
357: try {
358: // EndpointReference myEPR
359: ObjectStateUtils.writeObject(out, myEPR,
360: "ServiceContext.myEPR");
361: } catch (Exception e2) {
362: // note that the utility class will provide the trace for the
363: // exception so we won't have to
364: // so just consume the exception for now
365: }
366:
367: //---------------------------------------------------------
368: // properties
369: //---------------------------------------------------------
370: Map tmpMap = getProperties();
371:
372: HashMap tmpHashMap = null;
373:
374: if ((tmpMap != null) && (!tmpMap.isEmpty())) {
375: tmpHashMap = new HashMap(tmpMap);
376: }
377:
378: ObjectStateUtils.writeHashMap(out, tmpHashMap,
379: "ServiceContext.properties");
380:
381: //---------------------------------------------------------
382: // AxisService
383: //---------------------------------------------------------
384:
385: String axisServMarker = "ServiceContext.metaAxisService";
386: ObjectStateUtils.writeString(out, axisServMarker,
387: axisServMarker);
388:
389: if (axisService == null) {
390: out.writeBoolean(ObjectStateUtils.EMPTY_OBJECT);
391: } else {
392: out.writeBoolean(ObjectStateUtils.ACTIVE_OBJECT);
393: metaAxisService = new MetaDataEntry(axisService.getClass()
394: .getName(), axisService.getName());
395: ObjectStateUtils.writeObject(out, metaAxisService,
396: "ServiceContext.metaAxisService");
397: }
398:
399: //---------------------------------------------------------
400: // parent
401: //---------------------------------------------------------
402: // ServiceGroupContext serviceGroupContext;
403:
404: ServiceGroupContext myParent = (ServiceGroupContext) getParent();
405:
406: ObjectStateUtils.writeObject(out, myParent,
407: "ServiceContext.parent ServiceGroupContext");
408:
409: }
410:
411: /**
412: * Restore the contents of the object that was previously saved.
413: * <p/>
414: * NOTE: The field data must read back in the same order and type
415: * as it was written. Some data will need to be validated when
416: * resurrected.
417: *
418: * @param in The stream to read the object contents from
419: * @throws IOException
420: * @throws ClassNotFoundException
421: */
422: public void readExternal(ObjectInput in) throws IOException,
423: ClassNotFoundException {
424: // set the flag to indicate that the message context is being
425: // reconstituted and will need to have certain object references
426: // to be reconciled with the current engine setup
427: needsToBeReconciled = true;
428:
429: // trace point
430: if (LoggingControl.debugLoggingAllowed && log.isTraceEnabled()) {
431: log
432: .trace(myClassName
433: + ":readExternal(): BEGIN bytes available in stream ["
434: + in.available() + "] ");
435: }
436:
437: //---------------------------------------------------------
438: // object level identifiers
439: //---------------------------------------------------------
440:
441: // serialization version ID
442: long suid = in.readLong();
443:
444: // revision ID
445: int revID = in.readInt();
446:
447: // make sure the object data is in a version we can handle
448: if (suid != serialVersionUID) {
449: throw new ClassNotFoundException(
450: ObjectStateUtils.UNSUPPORTED_SUID);
451: }
452:
453: // make sure the object data is in a revision level we can handle
454: if (revID != REVISION_1) {
455: throw new ClassNotFoundException(
456: ObjectStateUtils.UNSUPPORTED_REVID);
457: }
458:
459: //---------------------------------------------------------
460: // various simple fields
461: //---------------------------------------------------------
462:
463: long time = in.readLong();
464: setLastTouchedTime(time);
465:
466: cachingOperationContext = in.readBoolean();
467:
468: logCorrelationIDString = ObjectStateUtils.readString(in,
469: myClassName + ".logCorrelationIDString");
470:
471: // trace point
472: if (LoggingControl.debugLoggingAllowed && log.isTraceEnabled()) {
473: log.trace(myClassName
474: + ":readExternal(): reading input stream for ["
475: + logCorrelationIDString + "] ");
476: }
477:
478: // EndpointReference targetEPR
479: targetEPR = (EndpointReference) ObjectStateUtils.readObject(in,
480: "ServiceContext.targetEPR");
481:
482: // EndpointReference myEPR
483: myEPR = (EndpointReference) ObjectStateUtils.readObject(in,
484: "ServiceContext.myEPR");
485:
486: //---------------------------------------------------------
487: // properties
488: //---------------------------------------------------------
489:
490: HashMap tmpHashMap = ObjectStateUtils.readHashMap(in,
491: "ServiceContext.properties");
492:
493: properties = new HashMap();
494: if (tmpHashMap != null) {
495: setProperties(tmpHashMap);
496: }
497:
498: //---------------------------------------------------------
499: // AxisService
500: //---------------------------------------------------------
501:
502: // axisService is not usable until the meta data has been reconciled
503:
504: ObjectStateUtils.readString(in, "ServiceContext.axisService");
505:
506: boolean metaAxisServiceIsActive = in.readBoolean();
507:
508: if (metaAxisServiceIsActive == ObjectStateUtils.ACTIVE_OBJECT) {
509: metaAxisService = (MetaDataEntry) ObjectStateUtils
510: .readObject(in, "ServiceContext.metaAxisService");
511: } else {
512: metaAxisService = null;
513: }
514:
515: //---------------------------------------------------------
516: // parent
517: //---------------------------------------------------------
518:
519: // ServiceGroupContext is not usable until it has been activated
520:
521: metaParent = (ServiceGroupContext) ObjectStateUtils.readObject(
522: in, "ServiceContext.parent ServiceGroupContext");
523:
524: //---------------------------------------------------------
525: // other
526: //---------------------------------------------------------
527:
528: // currently not saving this object
529: lastOperationContext = null;
530:
531: //---------------------------------------------------------
532: // done
533: //---------------------------------------------------------
534: }
535:
536: /**
537: * This method checks to see if additional work needs to be
538: * done in order to complete the object reconstitution.
539: * Some parts of the object restored from the readExternal()
540: * cannot be completed until we have a configurationContext
541: * from the active engine. The configurationContext is used
542: * to help this object to plug back into the engine's
543: * configuration and deployment objects.
544: *
545: * @param cc The configuration context object representing the active configuration
546: */
547: public void activate(ConfigurationContext cc) {
548: // see if there's any work to do
549: if (!needsToBeReconciled) {
550: // return quick
551: return;
552: }
553:
554: // use the supplied configuration context
555: configContext = cc;
556:
557: // get the axis configuration
558: AxisConfiguration axisConfig = cc.getAxisConfiguration();
559:
560: // We previously saved metaAxisService; restore it
561: axisService = null;
562:
563: if (metaAxisService != null) {
564: axisService = ObjectStateUtils.findService(axisConfig,
565: metaAxisService.getClassName(), metaAxisService
566: .getQNameAsString());
567: }
568:
569: // the parent ServiceGroupContext object was saved
570: // either use the restored object or sync up with
571: // an existing ServiceGroupContext object
572: if (metaParent != null) {
573: // find out if a copy of the ServiceGroupContext object exists on this
574: // engine where this ServiceContext is being restored/activated
575: // if so, use that object instead of the restored object
576: // in order to make sure that future changes to group-level
577: // properties are preserved for future operations
578: String groupName = metaParent.getId();
579:
580: ServiceGroupContext existingSGC = null;
581:
582: ServiceGroupContext sgc = cc
583: .getServiceGroupContext(groupName);
584:
585: if (existingSGC == null) {
586: // could not find an existing ServiceGroupContext
587: // use the restored object
588: metaParent.activate(cc);
589:
590: // set parent
591: this .setParent(metaParent);
592: } else {
593: // switch over to the existing object
594: this .setParent(existingSGC);
595:
596: // do a copy of the properties from the restored object
597: // to the existing ServiceContext
598: // Should the copy be a non-destructive one? That is,
599: // if the key already exists in the properties table of the
600: // existing object, should the value be overwritten from the
601: // restored ojbect? For now, the decision is that the state
602: // that has been preserved for a saved context object is
603: // is important to be restored.
604: metaParent.putContextProperties(existingSGC);
605: }
606:
607: } else {
608: // set parent to null
609: this .setParent(metaParent);
610: }
611:
612: // this is another pointer to our parent object
613: serviceGroupContext = (ServiceGroupContext) this .getParent();
614:
615: if (serviceGroupContext != null) {
616: // add the service context to the table
617: serviceGroupContext.addServiceContext(this );
618: }
619:
620: //-------------------------------------------------------
621: // done, reset the flag
622: //-------------------------------------------------------
623: needsToBeReconciled = false;
624:
625: // make sure this restored object is in the parent's list
626: if (metaParent != null) {
627: // make sure this restored object is in the parent's list
628: metaParent.addServiceContext(this );
629: }
630:
631: }
632:
633: /**
634: * This will do a copy of the properties from this context object
635: * to the properties of the specified context object.
636: *
637: * @param context The ServiceContext object to hold the merged properties
638: * @param doParentProperties Indicates whether to go up the context hierachy
639: * copy the properties at each level
640: */
641: public void putContextProperties(ServiceContext context,
642: boolean doParentProperties) {
643: if (context != null) {
644: // get the current properties on this context object
645: Map props = getProperties();
646:
647: // copy them to the specified context object
648: context.mergeProperties(props);
649:
650: if (doParentProperties) {
651: ServiceGroupContext mySGC = null;
652:
653: if (serviceGroupContext != null) {
654: mySGC = serviceGroupContext;
655: } else if (metaParent != null) {
656: mySGC = metaParent;
657: }
658:
659: if (mySGC != null) {
660: ServiceGroupContext sgc = context
661: .getServiceGroupContext();
662: mySGC.putContextProperties(sgc);
663: }
664: }
665: }
666: }
667:
668: /**
669: * Compares key parts of the state from the current instance of
670: * this class with the specified instance to see if they are
671: * equivalent.
672: * <p/>
673: * This differs from the java.lang.Object.equals() method in
674: * that the equals() method generally looks at both the
675: * object identity (location in memory) and the object state
676: * (data).
677: * <p/>
678: *
679: * @param ctx
680: * @return TRUE if this object is equivalent with the specified object
681: * that is, key fields match
682: * FALSE, otherwise
683: */
684: public boolean isEquivalent(ServiceContext ctx) {
685: // NOTE: the input object is expected to exist (ie, be non-null)
686:
687: if (!this .axisService.equals(ctx.getAxisService())) {
688: return false;
689: }
690:
691: EndpointReference targetEPR2 = ctx.getTargetEPR();
692:
693: if ((this .targetEPR != null) && (targetEPR2 != null)) {
694: if (!this .targetEPR.isEquivalent(targetEPR2)) {
695: return false;
696: }
697: } else if ((this .targetEPR == null) && (targetEPR2 == null)) {
698: // keep going
699: } else {
700: // one of the objects is null
701: return false;
702: }
703:
704: EndpointReference myEPR2 = ctx.getMyEPR();
705:
706: if ((this .myEPR != null) && (myEPR2 != null)) {
707: if (!this .myEPR.isEquivalent(myEPR2)) {
708: return false;
709: }
710: } else if ((this .myEPR == null) && (myEPR2 == null)) {
711: // keep going
712: } else {
713: // one of the objects is null
714: return false;
715: }
716:
717: // TODO: consider checking the parent objects for equivalency
718:
719: // TODO: consider checking fields from the super class for equivalency
720:
721: return true;
722: }
723:
724: /**
725: * Get the ID associated with this object instance.
726: *
727: * @return A string that can be output to a log file as an identifier
728: * for this object instance. It is suitable for matching related log
729: * entries.
730: */
731: public String getLogCorrelationIDString() {
732: return logCorrelationIDString;
733: }
734:
735: /**
736: * Trace a warning message, if needed, indicating that this
737: * object needs to be activated before accessing certain fields.
738: *
739: * @param methodname The method where the warning occurs
740: */
741: private void checkActivateWarning(String methodname) {
742: if (needsToBeReconciled) {
743: if (LoggingControl.debugLoggingAllowed
744: && log.isDebugEnabled()) {
745: log
746: .debug(logCorrelationIDString
747: + ":"
748: + methodname
749: + "(): ****WARNING**** "
750: + myClassName
751: + ".activate(configurationContext) needs to be invoked.");
752: }
753: }
754: }
755:
756: public ConfigurationContext getRootContext() {
757: return configContext;
758: }
759:
760: }
|