Package net.sf.xbus.application

Source Code of net.sf.xbus.application.Router$InvokeInternalResult

package net.sf.xbus.application;

import net.sf.xbus.base.core.Constants;
import net.sf.xbus.base.core.XException;
import net.sf.xbus.base.core.config.Configuration;
import net.sf.xbus.base.core.trace.Trace;
import net.sf.xbus.base.xbussystem.XBUSSystem;
import net.sf.xbus.protocol.Message;
import net.sf.xbus.protocol.MessageFactory;

/**
* The <code>Router</code> routes a message to one or more systems. Three
* different strategies are implemented:
* <ul>
* <li>{@link #distribute(Message) distribute} sends the data to one or more
* systems and awaits no response data.
* <li>{@link #invoke(Message) invoke} implements a chain of senders. This
* means the response data of one sender is the request data of the following
* sender.
* <li>{@link #invokeAndDistribute(Message) invokeAndDistribute} is the
* combination of the both. First the data goes through the chain of sender
* invocations, then the response data of the last sender is distributed to one
* or more systems.
* </ul>
* <p>
*
* <b>Configuration:</b>
* <p>
* <table border>
* <tr>
* <th>Chapter</th>
* <th>Section</th>
* <th>Key</th>
* <th>Content</th>
* </tr>
* <tr>
* <td>Router</td>
* <td><code>message.getSource() + "." + message.getFunction()</code></td>
* <td>Invoke<i>n</i></td>
* <td>System where a message is sent to and from which a response is returned.</td>
* </tr>
* <tr>
* <td>Router</td>
* <td><code>message.getSource() + "." + message.getFunction()</code></td>
* <td>Distribute<i>n</i></td>
* <td>System where a message is sent to and from which no response is
* returned.</td>
* </tr>
* </table>
*/
public class Router
{
  public static final String CHAPTER = "Router";

  private boolean mResponseFilled = false;

  private class InvokeInternalResult
  {
    Message resultMessage;
    XBUSSystem lastSystem;
  }

  /**
   * The message will be routed depending on the entries of the configuration.
   *
   * @param message the request data of this <code>Message</code> is sent to
   *            the first system. It's response data is empty afterwards
   *            because the last step is the distribution without responses.
   */
  public void route(Message message) throws XException
  {
    if (getRouterEntryOptional(message, "Invoke1") != null)
    {
      if (getRouterEntryOptional(message,
          "Distribute1") != null)
      {
        invokeAndDistribute(message);
      }
      else
      {
        invoke(message);
      }
    }
    else
    {
      distribute(message);
    }
  }

  /**
   * The <code>Message</code> is distributed to one or more systens. This
   * means, that the given <code>Message</code> is sent to the systems (read
   * from the <code>Configuration</code>) one after the other. Because
   * there is no response data from the systems awaited, the response data in
   * the <code>Message</code> is empty after the distribution.
   * <p>
   *
   * If an error occurs when calling one sender, the processing stops, a
   * rollback is done and the returncode of the <code>Message</code> is set
   * to <code>RC_NOK</code>.
   *
   * @param message the request data of this <code>Message</code> is sent to
   *            the systems
   */
  public void distribute(Message message) throws XException
  {
    distributeInternal(message);
  }

  /**
   * A combination of {@link #invoke(Message) invoke} and
   * {@link #distribute(Message) distribute}. First the data goes through a
   * chain of sender invocations, then the response data of the last sender is
   * distributed to one or more systems.
   * <p>
   *
   * If an error occurs when calling one sender, the processing stops, a
   * rollback is done and the returncode of the <code>Message</code> is set
   * to <code>RC_NOK</code>.
   *
   * @param message the request data of this <code>Message</code> is sent to
   *            the first system. It's response data is empty afterwards
   *            because the last step is the distribution without responses.
   */
  public void invokeAndDistribute(Message message) throws XException
  {
    InvokeInternalResult invokeResult = invokeInternal(message);

    Message newMessage = invokeResult.resultMessage;

    if (newMessage.getReturncode() == Constants.RC_OK)
    {
      distributeInternal(newMessage);
    }

    message.setReturncode(newMessage.getReturncode());
    message.setErrorcode(newMessage.getErrorcode());
    message.setErrortext(newMessage.getErrortext());
  }

  /**
   * A chain of invocations of one or more senders. After a sender has been
   * called, the <code>Message</code> for the next sender is created with
   * the response data of the previous sender. After the invocation of the
   * last sender, the response data of the initial <code>Message</code> is
   * filled with the response data of the last sender.
   * <p>
   *
   * If an error occurs when calling one sender, the processing stops, a
   * rollback is done and the returncode of the initial <code>Message</code>
   * is set to <code>RC_NOK</code>.
   *
   * @param message the initial <code>Message</code>
   */
  public void invoke(Message message) throws XException
  {
    InvokeInternalResult invokeResult = invokeInternal(message);

    Message newMessage = invokeResult.resultMessage;
    XBUSSystem lastSystem = invokeResult.lastSystem;

    MessageFactory.transformResponse2Response(lastSystem, message
        .getSource(), newMessage, message);
  }

  /**
   * Routes the incoming <code>Message</code>-object to the systems, which
   * are read from the <code>Configuration</code>. For every system, a new
   * <code>Message</code>-object is created via the
   * {@link net.sf.xbus.protocol.MessageFactory} and is sent by the
   * {@link net.sf.xbus.technical.Adapter}.
   * <p>
   *
   * When an error occurs, the returncode of the initial <code>Message</code>-object
   * will be set to <code>RC_NOK</code>.
   */
  private void distributeInternal(Message message) throws XException
  {
    String errortext = null;

    String destString = getRouterEntry(message, "Distribute1");
    XBUSSystem destination;

    int countSystems = 1;
    boolean rollback = false;
    Message sendMessage = null;

    while ((destString != null) && (!rollback))
    {
      sendMessage = null;
      Configuration config = Configuration.getInstance();
      destination = new XBUSSystem(destString, message.getSource()
          .getAddresses(), config.getValueAsBooleanOptional("System",
          destString, "Broadcast"));
      // The last parameter instructs the sender to try a broadcast for
      // all configured addtional addresses. This will only be active if
      // the destination address really contains a reference to the
      // addtional address information.
      try
      {
        if (mResponseFilled)
        {
          sendMessage = MessageFactory.createSenderMessage(
              destination, message,
              MessageFactory.TRANSFORM_FROM_RESPONSE);
        }
        else
        {
          sendMessage = MessageFactory.createSenderMessage(
              destination, message,
              MessageFactory.TRANSFORM_FROM_REQUEST);
        }

        Adapter.callSender(sendMessage, destination);

        if (!Constants.RC_OK.equals(sendMessage.getReturncode()))
        {
          rollback = true;
        }
      }
      catch (XException e)
      {
        rollback = true;
        errortext = e.getMessage();
        Trace.error("Exception while routing messages");
      }
      countSystems++;
      destString = getRouterEntryOptional(message,
          new StringBuffer().append("Distribute")
              .append(countSystems).toString());
    }

    if (rollback)
    {
      if (sendMessage != null)
      {
        message.setReturncode(sendMessage.getReturncode());
        message.setErrorcode(sendMessage.getErrorcode());
        message.setErrortext(sendMessage.getErrortext());
      }
      else
      {
        message.setReturncode(Constants.RC_NOK);
        if (errortext != null)
        {
          message.setErrortext(errortext);
        }
        else
        {
          message.setErrortext(XException.getExceptionInformation());
        }
      }
    }
    else
    {
      message.setReturncode(Constants.RC_OK);
    }
  }

  /**
   * Calls <code>Metaphase</code> first and then calls the
   * <code>route()</code>-method of its superclass with the response from
   * <code>Metaphase</code>.
   */
  private InvokeInternalResult invokeInternal(Message message)
      throws XException
  {
    InvokeInternalResult result = new InvokeInternalResult();

    String destString = getRouterEntry(message,  "Invoke1");

    int countSystems = 1;
    boolean rollback = false;

    Message sendMessage = message;
    Message sendMessageNew = null;

    while ((destString != null) && (!rollback))
    {
      result.lastSystem = new XBUSSystem(destString, message.getSource()
          .getAddresses());
      try
      {
        if (countSystems == 1)
        {
          sendMessageNew = MessageFactory.createSenderMessage(
              result.lastSystem, sendMessage,
              MessageFactory.TRANSFORM_FROM_REQUEST);
        }
        else
        {
          sendMessageNew = MessageFactory.createSenderMessage(
              result.lastSystem, sendMessage,
              MessageFactory.TRANSFORM_FROM_RESPONSE);
        }

        Adapter.callSender(sendMessageNew, result.lastSystem);

        if (!sendMessageNew.getReturncode().equals(Constants.RC_OK))
        {
          rollback = true;
        }

        sendMessage = sendMessageNew;
      }
      catch (XException e)
      {
        rollback = true;
        sendMessage.setReturncode(Constants.RC_NOK);
        sendMessage.setErrortext(e.getMessage());
        Trace.error("Exception while routing messages");
      }
      countSystems++;
      destString = getRouterEntryOptional(message,
          new StringBuffer().append("Invoke").append(countSystems)
              .toString());
    }

    mResponseFilled = true;
    result.resultMessage = sendMessage;
    return result;
  }

  private String getRouterEntry(Message message, String key) throws XException
  {
    Configuration config = Configuration.getInstance();
    String retString = config.getValueOptional(CHAPTER, message.getSource().getName(), key);
    if (retString == null)
    {
      retString = config.getValue(CHAPTER, getSection(message), key);
    }
   
    return retString;
  }
 
  private String getRouterEntryOptional(Message message ,String key) throws XException
  {
    Configuration config = Configuration.getInstance();
    String retString = config.getValueOptional(CHAPTER, message.getSource().getName(), key);
    if (retString == null)
    {
      retString = config.getValueOptional(CHAPTER, getSection(message), key);
    }
   
    return retString;
  }
 
  private String getSection(Message message)
  {
   
    return new StringBuffer().append(message.getSource().getName()).append(
        ".").append(message.getFunction()).toString();
  }

}
TOP

Related Classes of net.sf.xbus.application.Router$InvokeInternalResult

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.