/*
* 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 org.apache.axis2.AxisFault;
import org.apache.axis2.description.OperationDescription;
import org.apache.axis2.description.ServiceDescription;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.engine.AxisError;
import org.apache.axis2.i18n.Messages;
import org.apache.wsdl.WSDLConstants;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
/**
* An OperationContext represents a running "instance" of an operation, which is
* represented by an OperationDescription object. This concept is needed to allow
* messages to be grouped into operations as in WSDL 2.0-speak operations are
* essentially arbitrary message exchange patterns. So as messages are being
* exchanged the OperationContext remembers the state of where in the message
* exchange pattern it is in.
* <p/>
* OperationContextFactory factory. 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 {
// the in and out messages that may be present
private MessageContext inMessageContext;
private MessageContext outMessageContext;
// the OperationDescription of which this is a running instance. The MEP of this
// OperationDescription must be one of the 8 predefined ones in WSDL 2.0.
private transient OperationDescription axisOperation;
private int operationMEP;
private boolean isComplete = false;
// this is the global MessageID -> OperationContext map which is stored in
// the EngineContext. We're caching it here for faster acccess.
private Map operationContextMap;
private QName operationDescName = null;
private QName serviceDescName = null;
/**
* The method is used to do the intialization of the EngineContext
* @throws AxisFault
*/
public void init(AxisConfiguration axisConfiguration) throws AxisFault {
if (operationDescName!=null && serviceDescName!=null){
//todo this lead to NPE : Chamikara
axisOperation = axisConfiguration.getService(serviceDescName.getLocalPart()).
getOperation(operationDescName);
}
if (inMessageContext!=null)
inMessageContext.init(axisConfiguration);
if (outMessageContext!=null)
outMessageContext.init(axisConfiguration);
}
private void writeObject(ObjectOutputStream out) throws IOException {
if (axisOperation!=null)
operationDescName = axisOperation.getName();
if (axisOperation.getParent()!=null)
serviceDescName = axisOperation.getParent().getName();
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
}
/**
* Construct a new OperationContext.
*
* @param axisOperation the OperationDescription whose running instances' state this
* OperationContext represents.
* @param serviceContext the parent ServiceContext representing any state related to
* the set of all operations of the service.
*/
public OperationContext(OperationDescription axisOperation,
ServiceContext serviceContext) {
super(serviceContext);
this.axisOperation = axisOperation;
this.operationMEP = axisOperation.getAxisSpecifMEPConstant();
this.operationContextMap = getServiceContext().getEngineContext()
.getOperationContextMap();
operationDescName = axisOperation.getName();
ServiceDescription serviceDescription = axisOperation.getParent();
if (serviceDescription!=null)
serviceDescName = serviceDescription.getName();
}
public OperationContext(OperationDescription axisOperation) {
super(null);
this.axisOperation = axisOperation;
this.operationMEP = axisOperation.getAxisSpecifMEPConstant();
operationDescName = axisOperation.getName();
ServiceDescription serviceDescription = axisOperation.getParent();
if (serviceDescription!=null)
serviceDescName = serviceDescription.getName();
}
/**
* @return Returns the axisOperation.
*/
public OperationDescription getAxisOperation() {
return axisOperation;
}
/**
* Return the ServiceContext in which this OperationContext lives.
*
* @return parent ServiceContext
*/
public ServiceContext getServiceContext() {
return (ServiceContext) parent;
}
/**
* Return the EngineContext in which the parent ServiceContext lives.
*
* @return parent ServiceContext's parent EngineContext
*/
public ConfigurationContext getEngineContext() {
return (ConfigurationContext) parent.parent;
}
/**
* When a new message is added to the <code>MEPContext</code> the logic
* should be included remove the MEPContext from the table in the
* <code>EngineContext</code>. Example: IN_IN_OUT At the second IN
* message the MEPContext should be removed from the OperationDescription
*
* @param msgContext
*/
public synchronized void addMessageContext(MessageContext msgContext) throws AxisFault {
// this needs to store the msgContext in either inMessageContext or
// outMessageContext depending on the MEP of the OperationDescription
// and on the current state of the operation.
if (WSDLConstants.MEP_CONSTANT_IN_OUT == operationMEP
|| WSDLConstants.MEP_CONSTANT_IN_OPTIONAL_OUT == operationMEP
|| WSDLConstants.MEP_CONSTANT_ROBUST_IN_ONLY == operationMEP) {
if (inMessageContext == null) {
inMessageContext = msgContext;
} else {
outMessageContext = msgContext;
isComplete = true;
}
} else if (WSDLConstants.MEP_CONSTANT_IN_ONLY == operationMEP) {
inMessageContext = msgContext;
isComplete = true;
} else if (WSDLConstants.MEP_CONSTANT_OUT_ONLY == operationMEP) {
outMessageContext = msgContext;
isComplete = true;
} else if (WSDLConstants.MEP_CONSTANT_OUT_IN == operationMEP
|| WSDLConstants.MEP_CONSTANT_OUT_OPTIONAL_IN == operationMEP
|| WSDLConstants.MEP_CONSTANT_ROBUST_IN_ONLY == operationMEP) {
if (outMessageContext == null) {
outMessageContext = msgContext;
} else {
inMessageContext = msgContext;
isComplete = true;
}
} else {
// NOT REACHED: the factory created this context incorrectly
throw new AxisError("Invalid behavior of OperationContextFactory");
}
}
/**
* @param messageLabel
* @return
* @throws AxisFault
*/
public MessageContext getMessageContext(int messageLabel) throws AxisFault {
if (messageLabel == WSDLConstants.MESSAGE_LABEL_IN) {
return inMessageContext;
} else if (messageLabel == WSDLConstants.MESSAGE_LABEL_OUT) {
return outMessageContext;
} else {
throw new AxisFault(Messages.getMessage("unknownMsgLabel"));
}
}
/**
* Checks to see if the MEP is complete. i.e. whether all the messages that
* are associated with the MEP has arrived and MEP is complete.
*
* @return
*/
public boolean isComplete() {
return isComplete;
}
/**
* Removes the pointers to this <code>OperationContext</code> in the
* <code>EngineContext</code>'s OperationContextMap so that this
* <code>OperationContext</code> will eventually get garbage collected
* along with the <code>MessageContext</code>'s it contains. Note that if
* the caller wants to make sure its safe to clean up this OperationContext
* he should call isComplete() first. However, in cases like IN_OPTIONAL_OUT
* and OUT_OPTIONAL_IN, it is possibe this will get called without the MEP
* being complete due to the optional nature of the MEP.
*/
public void cleanup() {
if (null != this.inMessageContext && operationContextMap != null) {
operationContextMap.remove(inMessageContext.getMessageID());
}
if (null != this.outMessageContext && operationContextMap != null) {
operationContextMap.remove(outMessageContext.getMessageID());
}
}
// public MessageContext createMessageContext(AxisM){
//
// }
public void setParent(AbstractContext context) {
super.setParent(context);
this.operationContextMap = getServiceContext().getEngineContext()
.getOperationContextMap();
}
}