/* * 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.client; import org.apache.axiom.om.OMElement; import org.apache.axiom.util.UIDGenerator; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.async.AxisCallback; 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.description.AxisOperation; import org.apache.axis2.description.ClientUtils; import org.apache.axis2.description.TransportOutDescription; import org.apache.axis2.i18n.Messages; import org.apache.axis2.util.TargetResolver; import org.apache.axis2.wsdl.WSDLConstants; import java.util.Iterator; import java.util.Map; import javax.xml.namespace.QName; /** * An operation client is the way an advanced user interacts with Axis2. Actual * operation clients understand a specific MEP and hence their behavior is * defined by their MEP. To interact with an operation client, you first get one * from a specific AxisOperation. Then you set the messages into it one by one * (whatever is available). Then, when you call execute() the client will * execute what it can at that point. If executing the operation client results * in a new message being created, then if a message receiver is registered with * the client then the message will be delivered to that client. */ public abstract class OperationClient { protected AxisOperation axisOp; protected ServiceContext sc; protected Options options; protected OperationContext oc; protected AxisCallback axisCallback; /* * indicates whether the MEP execution has completed (and hence ready for * resetting) */ protected boolean completed; protected OperationClient(AxisOperation axisOp, ServiceContext sc, Options options) { this.axisOp = axisOp; this.sc = sc; this.options = new Options(options); completed = false; oc = sc.createOperationContext(axisOp); } /** * Sets the options that should be used for this particular client. This * resets the entire set of options to use the new options - so you'd lose * any option cascading that may have been set up. * * @param options the options */ public void setOptions(Options options) { this.options = options; } /** * Return the options used by this client. If you want to set a single * option, then the right way is to do getOptions() and set specific * options. * * @return the options, which will never be null. */ public Options getOptions() { return options; } /** * Add a message context to the client for processing. This method must not * process the message - it only records it in the operation client. * Processing only occurs when execute() is called. * * @param messageContext the message context * @throws AxisFault if this is called inappropriately. */ public abstract void addMessageContext(MessageContext messageContext) throws AxisFault; /** * Return a message from the client - will return null if the requested * message is not available. * * @param messageLabel the message label of the desired message context * @return the desired message context or null if its not available. * @throws AxisFault if the message label is invalid */ public abstract MessageContext getMessageContext(String messageLabel) throws AxisFault; /** * Set the callback to be executed when a message comes into the MEP and the * operation client is executed. This is the way the operation client * provides notification that a message has been received by it. Exactly * when its executed and under what conditions is a function of the specific * operation client. * * @param callback the callback to be used when the client decides its time to * use it */ public final void setCallback(AxisCallback callback) { axisCallback = callback; } /** * Execute the MEP. This method is final and only serves to set (if appropriate) * the lastOperationContext on the ServiceContext, and then it calls * executeImpl(), which does the actual work. * * @param block Indicates whether execution should block or return ASAP. What * block means is of course a function of the specific operation * client. * @throws AxisFault if something goes wrong during the execution of the operation * client. */ public final void execute(boolean block) throws AxisFault { sc.setLastOperationContext(oc); executeImpl(block); } /** * Execute the MEP. What this does depends on the specific operation client. * The basic idea is to have the operation client execute and do something * with the messages that have been added to it so far. For example, if its * an Out-In MEP, then if the Out message has been set, then executing the * client asks it to send the message and get the In message, possibly using * a different thread. * * @param block Indicates whether execution should block or return ASAP. What * block means is of course a function of the specific operation * client. * @throws AxisFault if something goes wrong during the execution of the operation * client. */ public abstract void executeImpl(boolean block) throws AxisFault; /** * Reset the operation client to a clean status after the MEP has completed. * This is how you can reuse an operation client. NOTE: this does not reset * the options; only the internal state so the client can be used again. * * @throws AxisFault if reset is called before the MEP client has completed an * interaction. */ public void reset() throws AxisFault { if (!completed) { throw new AxisFault(Messages.getMessage("cannotreset")); } oc = null; completed = false; } /** * To close the transport if necessary , can call this method. The main * usage of this method is when client uses two tarnsports for sending and * receiving , and we need to remove entries for waiting calls in the * transport listener queue. * Note : DO NOT call this method if you are not using two transports to * send and receive * * @param msgCtxt : MessageContext# which has all the transport information * @throws AxisFault : throws AxisFault if something goes wrong */ public void complete(MessageContext msgCtxt) throws AxisFault { TransportOutDescription trsout = msgCtxt.getTransportOut(); if (trsout != null) { trsout.getSender().cleanup(msgCtxt); } } /** * To get the operation context of the operation client * * @return OperationContext */ public OperationContext getOperationContext() { return oc; } /** * Create a message ID for the given message context if needed. If user gives an option with * MessageID then just copy that into MessageContext , and with that there can be multiple * message with same MessageID unless user call setOption for each invocation. * <p/> * If user want to give message ID then the better way is to set the message ID in the option and * call setOption for each invocation then the right thing will happen. * <p/> * If user does not give a message ID then the new one will be created and set that into Message * Context. * * @param mc the message context whose id is to be set */ protected void setMessageID(MessageContext mc) { // now its the time to put the parameters set by the user in to the // correct places and to the // if there is no message id still, set a new one. String messageId = options.getMessageId(); if (messageId == null || "".equals(messageId)) { messageId = UIDGenerator.generateURNString(); } mc.setMessageID(messageId); } protected void addReferenceParameters(MessageContext msgctx) { EndpointReference to = msgctx.getTo(); if (options.isManageSession() || (options.getParent() != null && options.getParent().isManageSession())) { EndpointReference tepr = sc.getTargetEPR(); if (tepr != null) { Map<QName, OMElement> map = tepr.getAllReferenceParameters(); if (map != null) { Iterator<OMElement> valuse = map.values().iterator(); while (valuse.hasNext()) { Object refparaelement = valuse.next(); if (refparaelement instanceof OMElement) { to.addReferenceParameter((OMElement) refparaelement); } } } } } } /** * prepareMessageContext gets a fresh new MessageContext ready to be sent. * It sets up the necessary properties, transport information, etc. * * @param configurationContext the active ConfigurationContext * @param mc the MessageContext to be configured * @throws AxisFault if there is a problem */ protected void prepareMessageContext(ConfigurationContext configurationContext, MessageContext mc) throws AxisFault { // set options on the message context if (mc.getSoapAction() == null || "".equals(mc.getSoapAction())) { mc.setSoapAction(options.getAction()); } mc.setOptions(new Options(options)); mc.setAxisMessage(axisOp.getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE)); // do Target Resolution TargetResolver targetResolver = configurationContext.getAxisConfiguration().getTargetResolverChain(); if (targetResolver != null) { targetResolver.resolveTarget(mc); } // if the transport to use for sending is not specified, try to find it // from the URL TransportOutDescription senderTransport = options.getTransportOut(); if (senderTransport == null) { EndpointReference toEPR = (options.getTo() != null) ? options .getTo() : mc.getTo(); senderTransport = ClientUtils.inferOutTransport(configurationContext .getAxisConfiguration(), toEPR, mc); } mc.setTransportOut(senderTransport); if (options.getParent() !=null && options.getParent().isManageSession()) { mc.getOptions().setManageSession(true); } else if (options.isManageSession()) { mc.getOptions().setManageSession(true); } addReferenceParameters(mc); } }