| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.axiom.util.UIDGenerator; |
| import org.apache.axis2.AxisFault; |
| import org.apache.axis2.addressing.EndpointReference; |
| import org.apache.axis2.context.externalize.ActivateUtils; |
| import org.apache.axis2.context.externalize.ExternalizeConstants; |
| import org.apache.axis2.context.externalize.SafeObjectInputStream; |
| import org.apache.axis2.context.externalize.SafeObjectOutputStream; |
| import org.apache.axis2.context.externalize.SafeSerializable; |
| 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.LoggingControl; |
| 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.ObjectOutput; |
| import java.util.Map; |
| import java.util.HashMap; |
| |
| /** |
| * 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 |
| implements Externalizable, SafeSerializable { |
| |
| /* |
| * setup for logging |
| */ |
| private static final Log log = LogFactory.getLog(ServiceContext.class); |
| |
| private static final String myClassName = "ServiceContext"; |
| |
| /** |
| * An ID which can be used to correlate operations on an instance of |
| * this object in the log files |
| */ |
| private String logCorrelationIDString = null; |
| |
| |
| /** |
| * @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_2 = 2; |
| // current revision level of this object |
| private static final int revisionID = REVISION_2; |
| |
| |
| public static final String SERVICE_OBJECT = "serviceObject"; |
| |
| private EndpointReference targetEPR; |
| private EndpointReference myEPR; |
| |
| private transient AxisService axisService; |
| |
| // 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 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 |
| //---------------------------------------------------------------- |
| |
| /** |
| * Public constructor (only here because this class is Externalizable) |
| */ |
| public ServiceContext() { |
| } |
| |
| /** |
| * Constructor (package access, should only be used by ServiceGroupContext) |
| * |
| * @param axisService the AxisService for which to create a context |
| * @param serviceGroupContext the parent ServiceGroupContext |
| */ |
| ServiceContext(AxisService axisService, ServiceGroupContext serviceGroupContext) { |
| super(serviceGroupContext); |
| this.serviceGroupContext = serviceGroupContext; |
| this.axisService = axisService; |
| this.configContext = (ConfigurationContext) parent.getParent(); |
| } |
| |
| public OperationContext createOperationContext(QName name) { |
| AxisOperation axisOp = axisService.getOperation(name); |
| return createOperationContext(axisOp); |
| } |
| |
| public OperationContext createOperationContext(AxisOperation axisOp) { |
| OperationContext ctx = new OperationContext(axisOp, this); |
| configContext.contextCreated(ctx); |
| return ctx; |
| } |
| |
| public AxisService getAxisService() { |
| checkActivateWarning("getAxisService"); |
| return axisService; |
| } |
| |
| public ConfigurationContext getConfigurationContext() { |
| checkActivateWarning("getConfigurationContext"); |
| return configContext; |
| } |
| |
| public ServiceGroupContext getServiceGroupContext() { |
| checkActivateWarning("getServiceGroupContext"); |
| return serviceGroupContext; |
| } |
| |
| /** |
| * To get the ERP for a given service , if the transport is present and not |
| * running then it will add as a listener to ListenerManager , there it will |
| * init that and start the listener , and finally ask the EPR from transport |
| * for a given service |
| * |
| * @param transport : Name of the transport |
| * @return |
| * @throws AxisFault |
| */ |
| public EndpointReference getMyEPR(String transport) throws AxisFault { |
| axisService.isEnableAllTransports(); |
| ConfigurationContext configctx = this.configContext; |
| if (configctx != null) { |
| ListenerManager lm = configctx.getListenerManager(); |
| if (!lm.isListenerRunning(transport)) { |
| TransportInDescription trsin = |
| configctx.getAxisConfiguration().getTransportIn(transport); |
| if (trsin != null) { |
| lm.addListener(trsin, false); |
| } else { |
| throw new AxisFault(Messages.getMessage("transportnotfound", |
| transport)); |
| } |
| } |
| if (!lm.isStopped()) { |
| return lm.getEPRforService(axisService.getName(), null, transport); |
| } |
| } |
| return null; |
| } |
| |
| public EndpointReference getTargetEPR() { |
| return targetEPR; |
| } |
| |
| public void setTargetEPR(EndpointReference targetEPR) { |
| this.targetEPR = targetEPR; |
| } |
| |
| public void setMyEPR(EndpointReference myEPR) { |
| this.myEPR = myEPR; |
| } |
| |
| public OperationContext getLastOperationContext() { |
| return lastOperationContext; |
| } |
| |
| public void setLastOperationContext(OperationContext lastOperationContext) { |
| this.lastOperationContext = lastOperationContext; |
| } |
| |
| public boolean isCachingOperationContext() { |
| return cachingOperationContext; |
| } |
| |
| 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 |
| * @throws IOException |
| */ |
| public void writeExternal(ObjectOutput o) throws IOException { |
| SafeObjectOutputStream out = SafeObjectOutputStream.install(o); |
| //--------------------------------------------------------- |
| // 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); |
| out.writeObject(getLogCorrelationIDString()); |
| |
| // EndpointReference targetEPR |
| out.writeObject(targetEPR); |
| |
| // EndpointReference myEPR |
| out.writeObject(myEPR); |
| |
| //--------------------------------------------------------- |
| // properties |
| //--------------------------------------------------------- |
| out.writeMap(getProperties()); |
| |
| //--------------------------------------------------------- |
| // AxisService |
| //--------------------------------------------------------- |
| metaAxisService = null; |
| if (axisService != null) { |
| String serviceAndPortNames = ActivateUtils.getAxisServiceExternalizeExtraName(axisService); |
| // If there is a service & port QName stored on the AxisService then write it out so |
| // it can be used during deserialization to hook up the message context to the |
| // correct AxisService. |
| metaAxisService = |
| new MetaDataEntry(axisService.getClass().getName(), axisService.getName(), |
| serviceAndPortNames); |
| } |
| out.writeObject(metaAxisService); |
| |
| //--------------------------------------------------------- |
| // parent |
| //--------------------------------------------------------- |
| out.writeObject(getParent()); |
| } |
| |
| |
| /** |
| * 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 |
| * @throws IOException |
| * @throws ClassNotFoundException |
| */ |
| public void readExternal(ObjectInput inObject) throws IOException, ClassNotFoundException { |
| SafeObjectInputStream in = SafeObjectInputStream.install(inObject); |
| // 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 (LoggingControl.debugLoggingAllowed && log.isTraceEnabled()) { |
| log.trace(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(ExternalizeConstants.UNSUPPORTED_SUID); |
| } |
| |
| // make sure the object data is in a revision level we can handle |
| if (revID != REVISION_2) { |
| throw new ClassNotFoundException(ExternalizeConstants.UNSUPPORTED_REVID); |
| } |
| |
| //--------------------------------------------------------- |
| // various simple fields |
| //--------------------------------------------------------- |
| |
| long time = in.readLong(); |
| setLastTouchedTime(time); |
| cachingOperationContext = in.readBoolean(); |
| logCorrelationIDString = (String) in.readObject(); |
| |
| // trace point |
| if (LoggingControl.debugLoggingAllowed && log.isTraceEnabled()) { |
| log.trace(myClassName + ":readExternal(): reading input stream for [" + |
| getLogCorrelationIDString()+ "] "); |
| } |
| |
| // EndpointReference targetEPR |
| targetEPR = (EndpointReference) in.readObject(); |
| |
| // EndpointReference myEPR |
| myEPR = (EndpointReference) in.readObject(); |
| |
| //--------------------------------------------------------- |
| // properties |
| //--------------------------------------------------------- |
| properties = in.readMap(new HashMap()); |
| |
| //--------------------------------------------------------- |
| // AxisService |
| //--------------------------------------------------------- |
| |
| // axisService is not usable until the meta data has been reconciled |
| metaAxisService = (MetaDataEntry) in.readObject(); |
| |
| //--------------------------------------------------------- |
| // parent |
| //--------------------------------------------------------- |
| |
| // ServiceGroupContext is not usable until it has been activated |
| metaParent = (ServiceGroupContext) in.readObject(); |
| |
| //--------------------------------------------------------- |
| // other |
| //--------------------------------------------------------- |
| |
| // currently not saving this object |
| lastOperationContext = null; |
| |
| //--------------------------------------------------------- |
| // done |
| //--------------------------------------------------------- |
| } |
| |
| |
| /** |
| * 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) { |
| // return quick |
| return; |
| } |
| |
| // 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 = ActivateUtils.findService(axisConfig, metaAxisService.getClassName(), |
| metaAxisService.getQNameAsString(), |
| metaAxisService.getExtraName()); |
| } |
| |
| // 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 = 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); |
| } |
| |
| } |
| |
| /** |
| * 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<String, Object> 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); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Get the ID associated with this object instance. |
| * |
| * @return A string that can be output to a log file as an identifier |
| * for this object instance. It is suitable for matching related log |
| * entries. |
| */ |
| public String getLogCorrelationIDString() { |
| if (logCorrelationIDString == null) { |
| logCorrelationIDString = myClassName + "@" + UIDGenerator.generateUID(); |
| } |
| return logCorrelationIDString; |
| } |
| |
| |
| /** |
| * Trace a warning message, if needed, indicating that this |
| * object needs to be activated before accessing certain fields. |
| * |
| * @param methodname The method where the warning occurs |
| */ |
| private void checkActivateWarning(String methodname) { |
| if (needsToBeReconciled) { |
| if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled()) { |
| log.debug(getLogCorrelationIDString()+ ":" + methodname + "(): ****WARNING**** " |
| + myClassName + ".activate(configurationContext) needs to be invoked."); |
| } |
| } |
| } |
| |
| public ConfigurationContext getRootContext() { |
| return configContext; |
| } |
| |
| |
| } |