/** {@inheritDoc} */
 @Override
 public void handleMessage(Exchange exchange) throws HandlerException {
   if (!ExchangePhase.IN.equals(exchange.getPhase())) {
     return;
   }
   Context context = exchange.getContext();
   ServiceOperation serviceOperation = exchange.getContract().getServiceOperation();
   ProcessActionModel processActionModel = _actionModels.get(serviceOperation.getName());
   ProcessActionType processActionType = getProcessActionType(context, processActionModel);
   Message messageIn = exchange.getMessage();
   Long processInstanceId = null;
   ProcessInstance processInstance = null;
   switch (processActionType) {
     case START_PROCESS:
       if (_processId != null) {
         Object messageContentIn = messageIn.getContent();
         if (messageContentIn != null) {
           Map<String, Object> parameters = new HashMap<String, Object>();
           parameters.put(_messageContentInName, messageContentIn);
           processInstance = _ksession.startProcess(_processId, parameters);
         } else {
           processInstance = _ksession.startProcess(_processId);
         }
         processInstanceId = Long.valueOf(processInstance.getId());
       } else {
         throwNullParameterException(processActionType, PROCESS_ID_VAR);
       }
       break;
     case SIGNAL_EVENT:
       String processEventType = getProcessEventType(context, processActionModel);
       Object processEvent = getProcessEvent(context, messageIn);
       processInstanceId = getProcessInstanceId(context);
       if (processInstanceId != null) {
         _ksession.signalEvent(processEventType, processEvent, processInstanceId.longValue());
       } else {
         throwNullParameterException(processActionType, PROCESS_INSTANCE_ID_VAR);
       }
       break;
     case ABORT_PROCESS_INSTANCE:
       processInstanceId = getProcessInstanceId(context);
       if (processInstanceId != null) {
         _ksession.abortProcessInstance(processInstanceId.longValue());
       } else {
         throwNullParameterException(processActionType, PROCESS_INSTANCE_ID_VAR);
       }
       break;
   }
   if (processInstanceId != null) {
     context.setProperty(PROCESS_INSTANCE_ID_VAR, processInstanceId, Scope.EXCHANGE);
     ExchangePattern exchangePattern = serviceOperation.getExchangePattern();
     if (ExchangePattern.IN_OUT.equals(exchangePattern)) {
       if (processInstance == null) {
         processInstance = _ksession.getProcessInstance(processInstanceId.longValue());
       }
       Message messageOut = exchange.createMessage();
       Object messageContentOut = null;
       if (processInstance != null) {
         messageContentOut =
             ((WorkflowProcessInstance) processInstance).getVariable(_messageContentOutName);
       }
       if (messageContentOut != null) {
         messageOut.setContent(messageContentOut);
       }
       exchange.send(messageOut);
     }
   }
 }
  /**
   * Send a message hash to the specified operation.
   *
   * @param operationName The operation name.
   * @param rubyHash The message hash.
   * @return The response object if an IN_OUT operation was invoked, otherwise null.
   * @throws Throwable An exception occurred while invoking the target operation.
   */
  public Object send(String operationName, RubyHash rubyHash) throws Throwable {
    if (operationName == null) {
      throw new IllegalArgumentException("null 'operationName' argument.");
    }
    if (rubyHash == null) {
      throw new IllegalArgumentException("null 'rubyHash' argument.");
    }

    ServiceOperation operation = _serviceReference.getInterface().getOperation(operationName);

    if (operation == null) {
      throw new IllegalArgumentException(
          "Unknown operation name '"
              + operationName
              + "' on Service '"
              + _serviceReference.getName()
              + "'.");
    }

    // Clone the RubyHash to convert it to a normal Map based graph.  This makes it possible
    // to more safely transport the payload data out of the ruby app via a SwitchYard Exchange...
    Map<String, Object> payload = deepClone(rubyHash);

    // Create the exchange contract...
    BaseExchangeContract exchangeContract = new BaseExchangeContract(operation);

    // Set the input type...
    exchangeContract
        .getInvokerInvocationMetaData()
        .setInputType(JavaService.toMessageType(payload.getClass()));

    if (operation.getExchangePattern() == ExchangePattern.IN_OUT) {
      final BlockingQueue<Exchange> responseQueue = new ArrayBlockingQueue<Exchange>(1);

      AtomicReference<ExchangeHandler> responseExchangeHandler =
          new AtomicReference<ExchangeHandler>(
              new ExchangeHandler() {
                public void handleMessage(Exchange exchange) throws HandlerException {
                  responseQueue.offer(exchange);
                }

                public void handleFault(Exchange exchange) {
                  responseQueue.offer(exchange);
                }
              });

      Exchange exchange =
          _serviceReference.createExchange(exchangeContract, responseExchangeHandler.get());
      Message message = exchange.createMessage().setContent(payload);

      exchange.send(message);
      Exchange exchangeOut = null;
      try {
        exchangeOut = responseQueue.take();
      } catch (InterruptedException e) {
        throw new SwitchYardException(
            "Operation '"
                + operationName
                + "' on Service '"
                + _serviceReference.getName()
                + "' interrupted.",
            e);
      }

      if (exchangeOut.getState() == ExchangeState.OK) {
        return exchangeOut.getMessage().getContent();
      } else {
        Object failureObj = exchangeOut.getMessage().getContent();
        if (failureObj instanceof Throwable) {
          if (failureObj instanceof InvocationTargetException) {
            throw ((Throwable) failureObj).getCause();
          } else {
            throw (Throwable) failureObj;
          }
        } else {
          throw new SwitchYardException(
              "Service invocation failure.  Service '"
                  + _serviceReference.getName()
                  + "', operation '"
                  + operationName
                  + "'.  Non Throwable failure message payload: "
                  + failureObj);
        }
      }
    } else {
      Exchange exchange = _serviceReference.createExchange(exchangeContract);
      Message message = exchange.createMessage().setContent(payload);

      exchange.send(message);
    }

    return null;
  }