Package org.apache.synapse.core.axis2

Source Code of org.apache.synapse.core.axis2.DynamicAxisOperation$DynamicOperationClient$NonBlockingInvocationWorker

/*
*  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.synapse.core.axis2;

import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.transport.TransportUtils;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.util.UUIDGenerator;
import org.apache.axis2.util.CallbackReceiver;
import org.apache.axis2.util.TargetResolver;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.OperationClient;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.async.Callback;
import org.apache.axis2.client.async.AsyncResult;
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.*;
import org.apache.axis2.engine.AxisEngine;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.synapse.SynapseException;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFault;
import org.apache.axiom.soap.SOAPBody;
import org.apache.axiom.om.OMElement;

import javax.xml.namespace.QName;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;

/**
* DynamicAxisOperation which switch dynamically between MEPs
*/
public class DynamicAxisOperation extends OutInAxisOperation {

  public DynamicAxisOperation() {
    super();
  }

  public DynamicAxisOperation(QName name) {
    super(name);
  }

  public OperationClient createClient(ServiceContext sc, Options options) {
    return new DynamicOperationClient(this, sc, options);
  }

  class DynamicOperationClient implements OperationClient {

    private AxisOperation axisOp;

    protected ServiceContext sc;

    protected Options options;

    protected OperationContext oc;

    protected Callback callback;

    /*
     * indicates whether the MEP execution has completed (and hence ready
     * for resetting)
     */
    boolean completed;

    DynamicOperationClient(OutInAxisOperation axisOp, ServiceContext sc,
        Options options) {
      this.axisOp = axisOp;
      this.sc = sc;
      this.options = options;
      this.completed = false;
      this.oc = new OperationContext(axisOp);
      this.oc.setParent(this.sc);
    }

    /**
     * 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;
    }

    /**
     * Returns the options used by this client. If you want to set a single
     * option, then the right way is to call getOptions() and set specific
     * options.
     *
     * @return Returns the options, which will never be null.
     */
    public Options getOptions() {
      return options;
    }

    /**
     * Adds message context to operation context , so that it will handle
     * the logic correctly if the OperationContext is null then new one will
     * be created , and Operation Context will become null when some one
     * calls reset().
     *
     * @param mc
     * @throws AxisFault
     */
    public void addMessageContext(MessageContext mc) throws AxisFault {
      mc.setServiceContext(sc);
      if (mc.getMessageID() == null) {
        setMessageID(mc);
      }
      axisOp.registerOperationContext(mc, oc);
    }

    /**
     * Returns the message context for a given message label.
     *
     * @param messageLabel :
     *            label of the message and that can be either "Out" or "In"
     *            and nothing else
     * @return Returns MessageContext.
     * @throws AxisFault
     */
    public MessageContext getMessageContext(String messageLabel)
        throws AxisFault {
      return oc.getMessageContext(messageLabel);
    }

    public void setCallback(Callback callback) {
      this.callback = callback;
    }

    /**
     * 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 mutiple 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
     */
    private 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 = UUIDGenerator.getUUID();
      }
      mc.setMessageID(messageId);
    }

    /**
     * Executes the MEP. What this does depends on the specific MEP client.
     * The basic idea is to have the MEP 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
     *            MEP client. IGNORED BY THIS MEP CLIENT.
     * @throws AxisFault
     *             if something goes wrong during the execution of the MEP.
     */
    public void execute(boolean block) throws AxisFault {
      if (completed) {
        throw new AxisFault(Messages.getMessage("mepiscomplted"));
      }
      ConfigurationContext cc = sc.getConfigurationContext();

      // copy interesting info from options to message context.
      MessageContext mc = oc
          .getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
      if (mc == null) {
        throw new AxisFault(Messages.getMessage("outmsgctxnull"));
      }

      mc.setOptions(options);

      // do Target Resolution
      TargetResolver tr = cc.getAxisConfiguration().getTargetResolverChain();
            if (tr != null) {
                tr.resolveTarget(mc);
            }

            // if the transport to use for sending is not specified, try to find
      // it
      // from the URL
      TransportOutDescription transportOut = options.getTransportOut();
      if (transportOut == null) {
        EndpointReference toEPR = (options.getTo() != null) ? options
            .getTo() : mc.getTo();
        transportOut = ClientUtils.inferOutTransport(cc
            .getAxisConfiguration(), toEPR, mc);
      }
      mc.setTransportOut(transportOut);

      if (options.getTransportIn() == null && mc.getTransportIn() == null) {
        mc.setTransportIn(ClientUtils.inferInTransport(cc
            .getAxisConfiguration(), options, mc));
      } else if (mc.getTransportIn() == null) {
        mc.setTransportIn(options.getTransportIn());
      }

      if (mc.getSoapAction() == null || "".equals(mc.getSoapAction())) {
        String soapaction = axisOp.getSoapAction();
        if (soapaction != null) {
          mc.setSoapAction(soapaction);
        }
      }
      addReferenceParameters(mc);
      if (options.isUseSeparateListener()) {

        // options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
        options.setTransportIn(mc.getConfigurationContext()
            .getAxisConfiguration().getTransportIn(
                new QName(Constants.TRANSPORT_HTTP)));

        SynapseCallbackReceiver callbackReceiver = (SynapseCallbackReceiver) axisOp
            .getMessageReceiver();
        callbackReceiver.addCallback(mc.getMessageID(), callback);
        EndpointReference replyToFromTransport = mc
            .getConfigurationContext().getListenerManager()
            .getEPRforService(sc.getAxisService().getName(),
                axisOp.getName().getLocalPart(),
                mc.getTransportOut().getName().getLocalPart());

        if (mc.getReplyTo() == null) {
          mc.setReplyTo(replyToFromTransport);
        } else {
          mc.getReplyTo().setAddress(
              replyToFromTransport.getAddress());
        }
        // if dont do this , this guy will wait till its gets HTTP 202
        // in the case
        // HTTP
        mc.setProperty(MessageContext.TRANSPORT_NON_BLOCKING,
            Boolean.TRUE);
        AxisEngine engine = new AxisEngine(cc);
        mc.getConfigurationContext().registerOperationContext(
            mc.getMessageID(), oc);
        engine.send(mc);

        // Options object reused so soapAction needs to be removed so
        // that soapAction+wsa:Action on response don't conflict
        options.setAction("");
      } else {
        if (block) {
          // Send the SOAP Message and receive a response
          MessageContext response = send(mc);
          // check for a fault and return the result
          if (response != null) {
            SOAPEnvelope resEnvelope = response.getEnvelope();
            if (resEnvelope.getBody().hasFault()) {
              SOAPFault soapFault = resEnvelope.getBody()
                  .getFault();

              // we need to call engine.receiveFault
              AxisEngine engine = new AxisEngine(mc
                  .getConfigurationContext());
              engine.receiveFault(response);
            }
          }
          completed = true;
        } else {
          sc.getConfigurationContext().getThreadPool().execute(
              new NonBlockingInvocationWorker(callback, mc));
        }
      }
    }

    private void addReferenceParameters(MessageContext msgctx) {
      EndpointReference to = msgctx.getTo();
      if (options.isManageSession()) {
        EndpointReference tepr = sc.getTargetEPR();
        if (tepr != null) {
          Map map = tepr.getAllReferenceParameters();
          if (map != null) {
            Iterator valuse = map.values().iterator();
            while (valuse.hasNext()) {
              Object refparaelement = valuse.next();
              if (refparaelement instanceof OMElement) {
                to
                    .addReferenceParameter((OMElement) refparaelement);
              }
            }
          }
        }
      }
    }

    /**
     * Sends the message using a two way transport and waits for a response
     *
     * @param msgctx
     * @return Returns MessageContext.
     * @throws AxisFault
     */
    protected MessageContext send(MessageContext msgctx) throws AxisFault {

      AxisEngine engine = new AxisEngine(msgctx.getConfigurationContext());

      // create the responseMessageContext
      MessageContext responseMessageContext = new MessageContext();

      // This is a hack - Needs to change
      responseMessageContext.setOptions(options);

      responseMessageContext.setServerSide(false);
      responseMessageContext.setMessageID(msgctx.getMessageID());
      addMessageContext(responseMessageContext);

      // sending the message
      engine.send(msgctx);

      // fix case where there is no response message (in-only)
      if (msgctx.getOperationContext().getMessageContext(
          WSDL2Constants.MESSAGE_LABEL_OUT).getProperty(
          MessageContext.TRANSPORT_IN) == null)
        return null;

      responseMessageContext.setDoingREST(msgctx.isDoingREST());

      responseMessageContext.setProperty(MessageContext.TRANSPORT_IN,
          msgctx.getProperty(MessageContext.TRANSPORT_IN));
      responseMessageContext.setTransportIn(msgctx.getTransportIn());
      responseMessageContext.setTransportOut(msgctx.getTransportOut());

      // Options object reused above so soapAction needs to be removed so
      // that soapAction+wsa:Action on response don't conflict
      responseMessageContext.setSoapAction("");

      if (responseMessageContext.getEnvelope() == null) {
        // If request is REST we assume the responseMessageContext is
        // REST, so
        // set the variable

        SOAPEnvelope resenvelope = TransportUtils.createSOAPMessage(
            responseMessageContext, msgctx.getEnvelope()
                .getNamespace().getNamespaceURI());
        if (resenvelope != null) {
          responseMessageContext.setEnvelope(resenvelope);
          engine = new AxisEngine(msgctx.getConfigurationContext());
          engine.receive(responseMessageContext);
          if (responseMessageContext.getReplyTo() != null) {
            sc.setTargetEPR(responseMessageContext.getReplyTo());
          }
        } else {
          throw new AxisFault(Messages
              .getMessage("blockingInvocationExpectsResponse"));
        }
      }
      return responseMessageContext;
    }

    /**
     * Resets the MEP client to a clean status after the MEP has completed.
     * This is how you can reuse a MEP 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;
    }

    public void complete(MessageContext msgCtxt) throws AxisFault {
      TransportOutDescription trsout = msgCtxt.getTransportOut();
      if (trsout != null) {
        trsout.getSender().cleanup(msgCtxt);
      }
    }

    public OperationContext getOperationContext() {
      return oc;
    }

    /**
     * This class is the workhorse for a non-blocking invocation that uses a
     * two way transport.
     */
    private class NonBlockingInvocationWorker implements Runnable {
      private Callback callback;

      private MessageContext msgctx;

      public NonBlockingInvocationWorker(Callback callback,
          MessageContext msgctx) {
        this.callback = callback;
        this.msgctx = msgctx;
      }

      public void run() {
        try {
          // send the request and wait for reponse
          MessageContext response = send(msgctx);
          // call the callback
          if (response != null) {
            SOAPEnvelope resenvelope = response.getEnvelope();
            SOAPBody body = resenvelope.getBody();
            if (body.hasFault()) {
              Exception ex = body.getFault().getException();

              if (ex != null) {
                callback.onError(ex);
              } else {
                callback.onError(new Exception(body.getFault()
                    .getReason().getText()));
              }
            } else {
              AsyncResult asyncResult = new AsyncResult(response);

              callback.onComplete(asyncResult);
            }
          }

          callback.setComplete(true);
        } catch (Exception e) {
          callback.onError(e);
        }
      }
    }
  }

}
TOP

Related Classes of org.apache.synapse.core.axis2.DynamicAxisOperation$DynamicOperationClient$NonBlockingInvocationWorker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.