Package org.atmosphere.plugin.jgroups

Source Code of org.atmosphere.plugin.jgroups.JGroupsChannel

/*
* Copyright 2014 Jean-Francois Arcand
*
* Licensed 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.atmosphere.plugin.jgroups;

import org.atmosphere.cpr.Broadcaster;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.ReceiverAdapter;
import org.jgroups.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
* JGroupsChannel establishes a connection to a
* JGroups cluster.  It sends/receives over that and forwards
* the received messages to the appropriate Broadcaster on its
* node.
*
* Best practice would have only 1 of these per Atmosphere application.
* Each JGroupsFilter instance has a reference to the
* singleton JGroupsChannel object and registers its broadcaster via
* the addBroadcaster() method.
*
* @author westraj
*
*/
public class JGroupsChannel extends ReceiverAdapter {
  private static final Logger logger = LoggerFactory
      .getLogger(JGroupsChannel.class);
     
  /** JGroups  JChannel object */
  private final JChannel jchannel;
 
  /** JChannel cluster name */
  private final String clusterName;
 
  /** registers all the Broadcasters that are filtered via a JGroupsFilter */
  private final Map<String, Broadcaster> broadcasters = new HashMap<String, Broadcaster>();
 
  /** Holds original messages (not BroadcastMessage) received over a cluster broadcast */
  private final ConcurrentLinkedQueue<Object> receivedMessages = new ConcurrentLinkedQueue<Object>();
 
  /**
   * Constructor
   *
   * @param jchannel  unconnected JGroups  JChannel object
   * @param clusterName  name of the group to connect the JChannel to
   */
  public JGroupsChannel(JChannel jchannel, String clusterName) {
    if (jchannel.isConnected()) throw new IllegalArgumentException("JChannel already connected");
   
    this.jchannel = jchannel;
    this.clusterName = clusterName;
  }
 
  /**
   * Connect to the cluster
   * @throws Exception
   */
  public void init() throws Exception {
    logger.info(
        "Starting Atmosphere JGroups Clustering support with group name {}",
        this.clusterName);
    try {
      this.jchannel.setReceiver(this);
      this.jchannel.connect(clusterName);
      this.jchannel.setDiscardOwnMessages(true);
    } catch (Exception e) {
      logger.warn("Failed to connect to cluster: " + this.clusterName, e);
      throw e;
    }
   
  }

  /**
     * Shutdown the cluster.
     */
    public void destroy() {
        try {
            Util.shutdown(jchannel);
        } catch (Throwable t) {
            Util.close(jchannel);
            logger.warn("failed to properly shutdown jgroups channel, closing abnormally", t);
        }
        receivedMessages.clear();
        broadcasters.clear();
    }
   
  /**
   * {@inheritDoc}
   */
  @Override
  public void receive(final Message jgroupMessage) {
    final Object payload = jgroupMessage.getObject();
   
    if (payload == null) return;
   
    if (BroadcastMessage.class.isAssignableFrom(payload.getClass())) {
      BroadcastMessage broadcastMsg = BroadcastMessage.class.cast(payload);
     
      // original message from the sending node's JGroupsFilter.filter() method
      Object origMessage = broadcastMsg.getMessage();
     
      // add original message to list to check re-broadcast logic in send()
      receivedMessages.offer(origMessage);
     
      String topicId = broadcastMsg.getTopic();
      if (broadcasters.containsKey(topicId)) {
        Broadcaster bc = broadcasters.get(topicId);
        try {
          bc.broadcast(origMessage).get();
        } catch(Exception ex) {
          logger.error("Failed to broadcast message received over the JGroups cluster "+this.clusterName, ex);
        }
      }
     
    }
  }
 
  /**
   * Called from a ClusterBroadcastFilter filter() method
   * to send the message over to other Atmosphere cluster nodes
   *
   * @param topic
   * @param message
   */
  public void send(String topic, Object message) {
    if (jchannel.isConnected()) {
      // Avoid re-broadcasting to cluster by checking if the message was
      // one already received from another cluster node
          if (!receivedMessages.remove(message)) {
              try {
               
                BroadcastMessage broadcastMsg = new BroadcastMessage(topic, message);
                Message jgroupMsg = new Message(null, null, broadcastMsg);
               
                  jchannel.send(jgroupMsg);
              } catch (Exception e) {
                  logger.warn("Failed to send message {}", message, e);
                }
          }
    }
  }
 
  /**
   * Adds/replaces the broadcaster to the JGroupsChannel
   * @param broadcaster
   */
  public void addBroadcaster(Broadcaster broadcaster) {
    this.broadcasters.put(broadcaster.getID(), broadcaster);
  }
 
  /**
   * Removes the broadcaster from the JGroupsChannel
   * @param broadcaster
   */
  public void removeBroadcaster(Broadcaster broadcaster) {
    this.broadcasters.remove(broadcaster.getID());
  }
 
 
}
TOP

Related Classes of org.atmosphere.plugin.jgroups.JGroupsChannel

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.