| /* |
| * 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.description; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.Set; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.apache.axiom.om.util.UUIDGenerator; |
| import org.apache.axis2.AxisFault; |
| import org.apache.axis2.client.OperationClient; |
| import org.apache.axis2.client.Options; |
| import org.apache.axis2.context.ConfigurationContext; |
| import org.apache.axis2.context.MessageContext; |
| import org.apache.axis2.context.OperationContext; |
| import org.apache.axis2.context.ServiceContext; |
| import org.apache.axis2.engine.AxisConfiguration; |
| import org.apache.axis2.engine.AxisError; |
| import org.apache.axis2.engine.MessageReceiver; |
| import org.apache.axis2.i18n.Messages; |
| import org.apache.axis2.phaseresolver.PhaseResolver; |
| import org.apache.axis2.wsdl.WSDLConstants; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| public abstract class AxisOperation extends AxisDescription |
| implements WSDLConstants { |
| |
| public static final String STYLE_RPC = "rpc"; |
| public static final String STYLE_MSG = "msg"; |
| public static final String STYLE_DOC = "doc"; |
| |
| private static final Log log = LogFactory.getLog(AxisOperation.class); |
| /** message exchange pattern */ |
| private int mep = WSDLConstants.MEP_CONSTANT_INVALID; |
| |
| // to hide control operation , operation which added by RM like module |
| private boolean controlOperation = false; |
| private String style = STYLE_DOC; |
| |
| // to store mepURL |
| protected String mepURI; |
| |
| private MessageReceiver messageReceiver; |
| |
| private HashMap<String, ModuleConfiguration> moduleConfigmap; |
| |
| // To store deploy-time module refs |
| private ArrayList<String> modulerefs; |
| |
| private ArrayList<AxisMessage> faultMessages; |
| |
| private QName name; |
| |
| private ArrayList<String> wsamappingList; |
| private String outputAction; |
| private LinkedHashMap<String, String> faultActions = new LinkedHashMap<String, String>(); |
| |
| private String soapAction; |
| |
| |
| /** Default constructor */ |
| public AxisOperation() { |
| mepURI = WSDL2Constants.MEP_URI_IN_OUT; |
| modulerefs = new ArrayList<String>(); |
| moduleConfigmap = new HashMap<String, ModuleConfiguration>(); |
| faultMessages = new ArrayList<AxisMessage>(); |
| //setup a temporary name |
| QName tmpName = new QName(this.getClass().getName() + "_" + UUIDGenerator.getUUID()); |
| this.setName(tmpName); |
| } |
| |
| public AxisOperation(QName name) { |
| this(); |
| this.setName(name); |
| } |
| |
| public abstract void addMessage(AxisMessage message, String label); |
| |
| /** |
| * Adds a message context into an operation context. Depending on MEPs, this method has to be |
| * overridden. Depending on the MEP operation description know how to fill the message context |
| * map in operationContext. As an example, if the MEP is IN-OUT then depending on messagable |
| * operation description should know how to keep them in correct locations. |
| * |
| * @param msgContext <code>MessageContext</code> |
| * @param opContext <code>OperationContext</code> |
| * @throws AxisFault <code>AxisFault</code> |
| */ |
| public abstract void addMessageContext(MessageContext msgContext, OperationContext opContext) |
| throws AxisFault; |
| |
| public abstract void addFaultMessageContext(MessageContext msgContext, |
| OperationContext opContext) |
| throws AxisFault; |
| |
| public void addModule(String moduleName) { |
| modulerefs.add(moduleName); |
| } |
| |
| /** |
| * Adds module configuration, if there is moduleConfig tag in operation. |
| * |
| * @param moduleConfiguration a ModuleConfiguration which will be added (by name) |
| */ |
| public void addModuleConfig(ModuleConfiguration moduleConfiguration) { |
| moduleConfigmap.put(moduleConfiguration.getModuleName(), moduleConfiguration); |
| } |
| |
| /** |
| * This is called when a module is engaged on this operation. Handle operation-specific tasks. |
| * |
| * @param axisModule AxisModule being engaged |
| * @param engager the AxisDescription where the engage occurred - could be us or a parent |
| * @throws AxisFault |
| */ |
| public final void onEngage(AxisModule axisModule, AxisDescription engager) throws AxisFault { |
| // Am I the source of this engagement? |
| boolean selfEngaged = (engager == this); |
| |
| // If I'm not, the operations will already have been added by someone above, so don't |
| // do it again. |
| if (selfEngaged) { |
| AxisService service = getAxisService(); |
| if (service != null) { |
| service.addModuleOperations(axisModule); |
| } |
| } |
| AxisConfiguration axisConfig = getAxisConfiguration(); |
| PhaseResolver phaseResolver = new PhaseResolver(axisConfig); |
| phaseResolver.engageModuleToOperation(this, axisModule); |
| } |
| |
| protected void onDisengage(AxisModule module) { |
| AxisService service = getAxisService(); |
| if (service == null) return; |
| |
| AxisConfiguration axisConfiguration = service.getAxisConfiguration(); |
| PhaseResolver phaseResolver = new PhaseResolver(axisConfiguration); |
| if (!service.isEngaged(module.getName()) && |
| (axisConfiguration != null && !axisConfiguration.isEngaged(module.getName()))) { |
| phaseResolver.disengageModuleFromGlobalChains(module); |
| } |
| phaseResolver.disengageModuleFromOperationChain(module, this); |
| |
| //removing operations added at the time of module engagemnt |
| HashMap<QName, AxisOperation> moduleOperations = module.getOperations(); |
| if (moduleOperations != null) { |
| Iterator<AxisOperation> moduleOperations_itr = moduleOperations.values().iterator(); |
| while (moduleOperations_itr.hasNext()) { |
| AxisOperation operation = (AxisOperation)moduleOperations_itr.next(); |
| service.removeOperation(operation.getName()); |
| } |
| } |
| } |
| |
| /** |
| * To remove module from engage module list |
| * |
| * @param module module to remove |
| * @deprecated please use disengageModule(), this method will disappear after 1.3 |
| */ |
| public void removeFromEngagedModuleList(AxisModule module) { |
| try { |
| disengageModule(module); |
| } catch (AxisFault axisFault) { |
| // Can't do much here... |
| log.error(axisFault.getMessage(), axisFault); |
| } |
| } |
| |
| // Note - removed this method which was dead code. |
| // private AxisOperation copyOperation(AxisOperation axisOperation) throws AxisFault { |
| |
| /** |
| * Returns as existing OperationContext related to this message if one exists. |
| * <p/> |
| * TODO - why both this and findOperationContext()? (GD) |
| * |
| * @param msgContext the MessageContext for which we'd like an OperationContext |
| * @return the OperationContext, or null |
| * @throws AxisFault |
| */ |
| public OperationContext findForExistingOperationContext(MessageContext msgContext) |
| throws AxisFault { |
| OperationContext operationContext; |
| |
| if ((operationContext = msgContext.getOperationContext()) != null) { |
| return operationContext; |
| } |
| |
| // If this message is not related to another one, or it is but not one emitted |
| // from the same operation, don't further look for an operation context or fault. |
| if (null != msgContext.getRelatesTo()) { |
| // So this message may be part of an ongoing MEP |
| ConfigurationContext configContext = msgContext.getConfigurationContext(); |
| |
| operationContext = |
| configContext.getOperationContext(msgContext.getRelatesTo().getValue()); |
| |
| if (null == operationContext && log.isDebugEnabled()) { |
| log.debug(msgContext.getLogIDString() + |
| " Cannot correlate inbound message RelatesTo value [" + |
| msgContext.getRelatesTo() + "] to in-progree MEP"); |
| } |
| } |
| |
| return operationContext; |
| } |
| |
| /** |
| * Finds an OperationContext for an incoming message. An incoming message can be of two states. |
| * <p/> |
| * 1)This is a new incoming message of a given MEP. 2)This message is a part of an MEP which has |
| * already begun. |
| * <p/> |
| * The method is special cased for the two MEPs |
| * <p/> |
| * #IN_ONLY #IN_OUT |
| * <p/> |
| * for two reasons. First reason is the wide usage and the second being that the need for the |
| * MEPContext to be saved for further incoming messages. |
| * <p/> |
| * In the event that MEP of this operation is different from the two MEPs defaulted above the |
| * decision of creating a new or this message relates to a MEP which already in business is |
| * decided by looking at the WSA Relates TO of the incoming message. |
| * |
| * @param msgContext MessageContext to search |
| * @param serviceContext ServiceContext (TODO - why pass this? (GD)) |
| * @return the active OperationContext |
| */ |
| public OperationContext findOperationContext(MessageContext msgContext, |
| ServiceContext serviceContext) |
| throws AxisFault { |
| OperationContext operationContext; |
| |
| if (null == msgContext.getRelatesTo()) { |
| |
| // Its a new incoming message so get the factory to create a new |
| // one |
| operationContext = serviceContext.createOperationContext(this); |
| } else { |
| |
| // So this message is part of an ongoing MEP |
| ConfigurationContext configContext = msgContext.getConfigurationContext(); |
| |
| operationContext = |
| configContext.getOperationContext(msgContext.getRelatesTo().getValue()); |
| |
| if (null == operationContext) { |
| throw new AxisFault(Messages.getMessage("cannotCorrelateMsg", |
| this.name.toString(), |
| msgContext.getRelatesTo().getValue())); |
| } |
| } |
| return operationContext; |
| } |
| |
| public void registerOperationContext(MessageContext msgContext, |
| OperationContext operationContext) |
| throws AxisFault { |
| msgContext.setAxisOperation(this); |
| msgContext.getConfigurationContext().registerOperationContext(msgContext.getMessageID(), |
| operationContext); |
| operationContext.addMessageContext(msgContext); |
| msgContext.setOperationContext(operationContext); |
| if (operationContext.isComplete()) { |
| operationContext.cleanup(); |
| } |
| } |
| |
| public void registerMessageContext(MessageContext msgContext, |
| OperationContext operationContext) throws AxisFault { |
| msgContext.setAxisOperation(this); |
| operationContext.addMessageContext(msgContext); |
| msgContext.setOperationContext(operationContext); |
| if (operationContext.isComplete()) { |
| operationContext.cleanup(); |
| } |
| } |
| |
| /** |
| * Maps the String URI of the Message exchange pattern to an integer. Further, in the first |
| * lookup, it will cache the looked up value so that the subsequent method calls are extremely |
| * efficient. |
| * |
| * @return an MEP constant from WSDLConstants |
| */ |
| public int getAxisSpecificMEPConstant() { |
| if (this.mep != WSDLConstants.MEP_CONSTANT_INVALID) { |
| return this.mep; |
| } |
| |
| int temp = WSDLConstants.MEP_CONSTANT_INVALID; |
| |
| if (WSDL2Constants.MEP_URI_IN_OUT.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_IN_OUT; |
| } else if (WSDL2Constants.MEP_URI_IN_ONLY.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_IN_ONLY; |
| } else if (WSDL2Constants.MEP_URI_IN_OPTIONAL_OUT.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_IN_OPTIONAL_OUT; |
| } else if (WSDL2Constants.MEP_URI_OUT_IN.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_OUT_IN; |
| } else if (WSDL2Constants.MEP_URI_OUT_ONLY.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_OUT_ONLY; |
| } else if (WSDL2Constants.MEP_URI_OUT_OPTIONAL_IN.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_OUT_OPTIONAL_IN; |
| } else if (WSDL2Constants.MEP_URI_ROBUST_IN_ONLY.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_ROBUST_IN_ONLY; |
| } else if (WSDL2Constants.MEP_URI_ROBUST_OUT_ONLY.equals(mepURI)) { |
| temp = WSDLConstants.MEP_CONSTANT_ROBUST_OUT_ONLY; |
| } |
| |
| if (temp == WSDLConstants.MEP_CONSTANT_INVALID) { |
| throw new AxisError(Messages.getMessage("mepmappingerror")); |
| } |
| |
| this.mep = temp; |
| |
| return this.mep; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.axis2.description.AxisService#getEngadgedModules() |
| */ |
| |
| public abstract AxisMessage getMessage(String label); |
| |
| public String getMessageExchangePattern() { |
| return mepURI; |
| } |
| |
| public MessageReceiver getMessageReceiver() { |
| return messageReceiver; |
| } |
| |
| public ModuleConfiguration getModuleConfig(String moduleName) { |
| return (ModuleConfiguration)moduleConfigmap.get(moduleName); |
| } |
| |
| public ArrayList<String> getModuleRefs() { |
| return modulerefs; |
| } |
| |
| public QName getName() { |
| return name; |
| } |
| |
| public abstract ArrayList getPhasesInFaultFlow(); |
| |
| public abstract ArrayList getPhasesOutFaultFlow(); |
| |
| public abstract ArrayList getPhasesOutFlow(); |
| |
| public abstract ArrayList getRemainingPhasesInFlow(); |
| |
| public String getStyle() { |
| return style; |
| } |
| |
| public ArrayList<String> getWSAMappingList() { |
| return wsamappingList; |
| } |
| |
| public boolean isControlOperation() { |
| return controlOperation; |
| } |
| |
| // to check whether a given parameter is locked |
| public boolean isParameterLocked(String parameterName) { |
| |
| // checking the locked value of parent |
| boolean locked = false; |
| |
| if (getParent() != null) { |
| locked = getParent().isParameterLocked(parameterName); |
| } |
| |
| if (locked) { |
| return true; |
| } else { |
| Parameter parameter = getParameter(parameterName); |
| |
| return (parameter != null) && parameter.isLocked(); |
| } |
| } |
| |
| public void setControlOperation(boolean controlOperation) { |
| this.controlOperation = controlOperation; |
| } |
| |
| public void setMessageExchangePattern(String mepURI) { |
| this.mepURI = mepURI; |
| } |
| |
| public void setMessageReceiver(MessageReceiver messageReceiver) { |
| this.messageReceiver = messageReceiver; |
| } |
| |
| public void setName(QName name) { |
| this.name = name; |
| } |
| |
| public abstract void setPhasesInFaultFlow(ArrayList list); |
| |
| public abstract void setPhasesOutFaultFlow(ArrayList list); |
| |
| public abstract void setPhasesOutFlow(ArrayList list); |
| |
| public abstract void setRemainingPhasesInFlow(ArrayList list); |
| |
| public void setStyle(String style) { |
| if (!"".equals(style)) { |
| this.style = style; |
| } |
| } |
| |
| public void setWsamappingList(ArrayList<String> wsamappingList) { |
| this.wsamappingList = wsamappingList; |
| } |
| |
| /** |
| * Return an OperationClient suitable for this AxisOperation. |
| * |
| * @param sc active ServiceContext |
| * @param options active Options |
| * @return an OperationClient set up appropriately for this operation |
| */ |
| public abstract OperationClient createClient(ServiceContext sc, Options options); |
| |
| public Object getKey() { |
| return this.name; |
| } |
| |
| public ArrayList<AxisMessage> getFaultMessages() { |
| return faultMessages; |
| } |
| |
| public void setFaultMessages(AxisMessage faultMessage) { |
| faultMessage.setParent(this); |
| faultMessages.add(faultMessage); |
| if (getFaultAction(faultMessage.getName()) == null) { |
| addFaultAction(faultMessage.getName(), |
| "urn:" + name.getLocalPart() + faultMessage.getName()); |
| } |
| } |
| |
| public void setSoapAction(String soapAction) { |
| this.soapAction = soapAction; |
| } |
| |
| /* |
| * Convenience method to access the WS-A Input Action per the |
| * WS-A spec. Effectively use the soapAction if available else |
| * use the first entry in the WSA Mapping list. |
| * |
| * Use getSoapAction when you want to get the soap action and this |
| * when you want to get the wsa input action. |
| */ |
| public String getInputAction() { |
| String result = null; |
| if (soapAction != null && !"".equals(soapAction)) { |
| result = soapAction; |
| } else { |
| if (wsamappingList != null && !wsamappingList.isEmpty()) { |
| result = (String)wsamappingList.get(0); |
| } |
| } |
| return result; |
| } |
| |
| public String getOutputAction() { |
| return outputAction; |
| } |
| |
| public void setOutputAction(String act) { |
| outputAction = act; |
| } |
| |
| public void addFaultAction(String faultName, String action) { |
| faultActions.put(faultName, action); |
| } |
| |
| public void removeFaultAction(String faultName) { |
| faultActions.remove(faultName); |
| } |
| |
| public String getFaultAction(String faultName) { |
| return (String)faultActions.get(faultName); |
| } |
| |
| public String[] getFaultActionNames() { |
| Set<String> keys = faultActions.keySet(); |
| String[] faultActionNames = new String[keys.size()]; |
| faultActionNames = (String[])keys.toArray(faultActionNames); |
| return faultActionNames; |
| } |
| |
| public String getFaultAction() { |
| String result = null; |
| Iterator<String> iter = faultActions.values().iterator(); |
| if (iter.hasNext()) { |
| result = (String)iter.next(); |
| } |
| return result; |
| } |
| |
| /** |
| * Get the messages referenced by this operation |
| * |
| * @return an Iterator of all the AxisMessages we deal with |
| */ |
| public Iterator<AxisMessage> getMessages() { |
| return (Iterator<AxisMessage>)getChildren(); |
| } |
| |
| /** |
| * Typesafe access to parent service |
| * |
| * @return the AxisService which contains this AxisOperation |
| */ |
| public AxisService getAxisService() { |
| return (AxisService)getParent(); |
| } |
| |
| public String getSoapAction() { |
| /* |
| * This AxisOperation instance may be used for the client OUT-IN or for |
| * the server IN-OUT. If the below code were changed to getInputActions, and the |
| * result of getInputAction were put in the SOAP action header on a client outbound |
| * message, the server would receive an INCORRECT SOAP action header. We should leave |
| * this as 'return soapAction;' OR make it client/server aware. |
| */ |
| return soapAction; |
| } |
| } |