All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.grinder.communication.MessageDispatchSender Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2005 - 2011 Philip Aston
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package net.grinder.communication;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.grinder.util.ListenerSupport;


/**
 * Passive {@link Sender}class that dispatches incoming messages to the
 * appropriate handler.
 *
 * @author Philip Aston
 */
public final class MessageDispatchSender
  implements Sender, MessageDispatchRegistry {

  /* Guarded by m_handlers. */
  private final Map, Handler> m_handlers =
    Collections.synchronizedMap(
      new HashMap, Handler>());

  /* Guarded by m_responders. */
  private final Map, BlockingHandler>
    m_responders =
      Collections.synchronizedMap(
        new HashMap, BlockingHandler>());

  private final ListenerSupport> m_fallbackHandlers =
    new ListenerSupport>();

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  @Override public 
    Handler set(Class messageType, Handler messageHandler) {

    return (Handler)
      m_handlers.put(messageType, (Handler) messageHandler);
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  @Override public 
  BlockingHandler
    set(Class messageType, BlockingHandler responder) {
    return (BlockingHandler)
      m_responders.put(messageType, (BlockingHandler)responder);
  }

  /**
   * Register a message handler that is called if no other handler or responder
   * is registered for the message type.
   *
   * @param messageHandler The sender.
   */
  public void addFallback(Handler messageHandler) {
    m_fallbackHandlers.add(messageHandler);
  }

  /**
   * Sends a message to each handler until one claims to have handled the
   * message.
   *
   * @param message The message.
   * @throws CommunicationException If one of the handlers failed.
   */
  public void send(final Message message) throws CommunicationException {

    if (message instanceof MessageRequiringResponse) {
      final MessageRequiringResponse messageRequringResponse =
        (MessageRequiringResponse)message;

      final Message requestMessage = messageRequringResponse.getMessage();

      final BlockingHandler responder =
        m_responders.get(requestMessage.getClass());

      if (responder != null) {
        messageRequringResponse.sendResponse(
          responder.blockingSend(requestMessage));
        return;
      }
    }
    else {
      final Handler handler = m_handlers.get(message.getClass());

      if (handler != null) {
        handler.handle(message);
        return;
      }
    }

    final CommunicationException[] exception = new CommunicationException[1];

    m_fallbackHandlers.apply(new ListenerSupport.Informer>() {
        public void inform(Handler handler) {
          try {
            handler.handle(message);
          }
          catch (CommunicationException e) {
            exception[0] = e;
          }
        }
      });

    if (message instanceof MessageRequiringResponse) {
      final MessageRequiringResponse messageRequringResponse =
        (MessageRequiringResponse)message;

      if (!messageRequringResponse.isResponseSent()) {
        // No one responded.
        messageRequringResponse.sendResponse(new NoResponseMessage());
      }
    }

    if (exception[0] != null) {
      throw exception[0];
    }
  }

 /**
  * Shutdown all our handlers.
  */
  public void shutdown() {
    final List> handlers;

    synchronized (m_handlers) {
      handlers = new ArrayList>(m_handlers.values());
    }

    for (Handler handler : handlers) {
      handler.shutdown();
    }

    final List> responders;

    synchronized (m_responders) {
      responders =
        new ArrayList>(
            m_responders.values());
    }

    for (BlockingHandler responder : responders) {
      responder.shutdown();
    }

    m_fallbackHandlers.apply(new ListenerSupport.Informer>() {
      public void inform(Handler handler) { handler.shutdown(); }
    });
  }
}