Package net.sf.hajdbc.distributed.jgroups

Source Code of net.sf.hajdbc.distributed.jgroups.JGroupsCommandDispatcher

/*
* HA-JDBC: High-Availability JDBC
* Copyright (C) 2012  Paul Ferraro
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.hajdbc.distributed.jgroups;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;

import net.sf.hajdbc.Messages;
import net.sf.hajdbc.distributed.Command;
import net.sf.hajdbc.distributed.CommandDispatcher;
import net.sf.hajdbc.distributed.Member;
import net.sf.hajdbc.distributed.MembershipListener;
import net.sf.hajdbc.distributed.Stateful;
import net.sf.hajdbc.logging.Level;
import net.sf.hajdbc.logging.Logger;
import net.sf.hajdbc.logging.LoggerFactory;
import net.sf.hajdbc.util.Objects;

import org.jgroups.Address;
import org.jgroups.Channel;
import org.jgroups.Message;
import org.jgroups.MessageListener;
import org.jgroups.View;
import org.jgroups.blocks.MessageDispatcher;
import org.jgroups.blocks.RequestHandler;
import org.jgroups.blocks.RequestOptions;
import org.jgroups.blocks.ResponseMode;
import org.jgroups.util.Rsp;

/**
* A JGroups-based command dispatcher.
*
* @author Paul Ferraro
* @see org.jgroups.blocks.MessageDispatcher
* @param <C> the execution context type
*/
public class JGroupsCommandDispatcher<C> implements RequestHandler, CommandDispatcher<C>, org.jgroups.MembershipListener, MessageListener
{
  private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
  private final String id;
  private final long timeout;
  private final MessageDispatcher dispatcher;
  private final C context;
  private final AtomicReference<View> viewReference = new AtomicReference<View>();
  private final MembershipListener membershipListener;
  private final Stateful stateful;
 
  /**
   * Constructs a new ChannelCommandDispatcher.
   * @param id the channel name
   * @param channel a JGroups channel
   * @param timeout the command timeout
   * @param context the execution context
   * @param stateful the state transfer handler
   * @param membershipListener notified of membership changes
   * @throws Exception if channel cannot be created
   */
  public JGroupsCommandDispatcher(String id, Channel channel, long timeout, C context, Stateful stateful, MembershipListener membershipListener) throws Exception
  {
    this.id = id;
    this.context = context;
    this.stateful = stateful;
    this.membershipListener = membershipListener;
   
    this.dispatcher = new MessageDispatcher(channel, this, this, this);
    this.timeout = timeout;
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.Lifecycle#start()
   */
  @Override
  public void start() throws Exception
  {
    Channel channel = this.dispatcher.getChannel();
   
    channel.setDiscardOwnMessages(true);
   
    // Connect and fetch state
    channel.connect(this.id, null, 0);
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.Lifecycle#stop()
   */
  @Override
  public void stop()
  {
    Channel channel = this.dispatcher.getChannel();
   
    if (channel.isOpen())
    {
      if (channel.isConnected())
      {
        channel.disconnect();
      }
     
      channel.close();
    }
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.distributed.CommandDispatcher#executeAll(net.sf.hajdbc.distributed.Command)
   */
  @Override
  public <R> Map<Member, R> executeAll(Command<R, C> command)
  {
    Message message = new Message(null, this.getLocalAddress(), Objects.serialize(command));
   
    try
    {
      Map<Address, Rsp<R>> responses = this.dispatcher.castMessage(null, message, new RequestOptions(ResponseMode.GET_ALL, this.timeout));
     
      if (responses == null) return Collections.emptyMap();
     
      Map<Member, R> results = new TreeMap<Member, R>();
     
      for (Map.Entry<Address, Rsp<R>> entry: responses.entrySet())
      {
        Rsp<R> response = entry.getValue();
 
        results.put(new AddressMember(entry.getKey()), response.wasReceived() ? response.getValue() : null);
      }
     
      return results;
    }
    catch (Exception e)
    {
      return null;
    }
  }
 
  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.distributed.CommandDispatcher#executeCoordinator(net.sf.hajdbc.distributed.Command)
   */
  @Override
  public <R> R executeCoordinator(Command<R, C> command)
  {
    while (true)
    {
      Message message = new Message(this.getCoordinatorAddress(), this.getLocalAddress(), Objects.serialize(command));

      try
      {
        return this.dispatcher.sendMessage(message, new RequestOptions(ResponseMode.GET_ALL, this.timeout));
      }
      catch (Exception e)
      {
        return null;
      }
    }
  }

  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.distributed.CommandDispatcher#isCoordinator()
   */
  @Override
  public boolean isCoordinator()
  {
    return this.getLocalAddress().equals(this.getCoordinatorAddress());
  }
 
  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.distributed.CommandDispatcher#getLocal()
   */
  @Override
  public Member getLocal()
  {
    return new AddressMember(this.getLocalAddress());
  }
 
  private Address getLocalAddress()
  {
    return this.dispatcher.getChannel().getAddress();
  }
 
  /**
   * {@inheritDoc}
   * @see net.sf.hajdbc.distributed.CommandDispatcher#getCoordinator()
   */
  @Override
  public Member getCoordinator()
  {
    return new AddressMember(this.getCoordinatorAddress());
  }

  private Address getCoordinatorAddress()
  {
    return this.dispatcher.getChannel().getView().getMembers().get(0);
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.blocks.RequestHandler#handle(org.jgroups.Message)
   */
  @Override
  public Object handle(Message message)
  {
    Command<Object, C> command = Objects.deserialize(message.getRawBuffer());

    this.logger.log(Level.DEBUG, Messages.COMMAND_RECEIVED.getMessage(command, message.getSrc()));
   
    return command.execute(this.context);
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MembershipListener#viewAccepted(org.jgroups.View)
   */
  @Override
  public void viewAccepted(View view)
  {
    if (this.membershipListener != null)
    {
      View oldView = this.viewReference.getAndSet(view);
     
      for (Address address: view.getMembers())
      {
        if ((oldView == null) || !oldView.containsMember(address))
        {
          this.membershipListener.added(new AddressMember(address));
        }
      }
     
      if (oldView != null)
      {
        for (Address address: oldView.getMembers())
        {
          if (!view.containsMember(address))
          {
            this.membershipListener.removed(new AddressMember(address));
          }
        }
      }
    }
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MessageListener#getState(java.io.OutputStream)
   */
  @Override
  public void getState(OutputStream output) throws Exception
  {
    ObjectOutput out = new ObjectOutputStream(output);
    this.stateful.writeState(out);
    out.flush();
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MessageListener#setState(java.io.InputStream)
   */
  @Override
  public void setState(InputStream input) throws Exception
  {
    this.stateful.readState(new ObjectInputStream(input));
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MembershipListener#suspect(org.jgroups.Address)
   */
  @Override
  public void suspect(Address member)
  {
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MembershipListener#block()
   */
  @Override
  public void block()
  {
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MembershipListener#unblock()
   */
  @Override
  public void unblock()
  {
  }

  /**
   * {@inheritDoc}
   * @see org.jgroups.MessageListener#receive(org.jgroups.Message)
   */
  @Override
  public void receive(Message message)
  {
  }
}
TOP

Related Classes of net.sf.hajdbc.distributed.jgroups.JGroupsCommandDispatcher

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.