Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ow2.cmi.ha.JGMessageManager Maven / Gradle / Ivy
/**
* High Availability Service (HA) for JOnAS
*
* Copyright (C) 2007,2008 Bull S.A.S.
* Contact: [email protected]
*
* Copyright (C) 2006 Distributed Systems Lab.
* Universidad Politecnica de Madrid (Spain)
* Contact: http://lsd.ls.fi.upm.es/lsd
*
* This library 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 2.1 of the License, or any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: JGMessageManager.java 2438 2010-02-24 16:20:30Z benoitf $
* --------------------------------------------------------------------------
*/
package org.ow2.cmi.ha;
import java.io.File;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import org.jgroups.Address;
import org.jgroups.Channel;
import org.jgroups.ChannelException;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.blocks.GroupRequest;
import org.jgroups.blocks.RequestHandler;
import org.jgroups.jmx.JmxConfigurator;
import org.jgroups.util.RspList;
import org.ow2.cmi.admin.MBeanUtils;
import org.ow2.cmi.controller.common.IConfig;
import org.ow2.cmi.controller.factory.ClusterViewManagerFactory;
import org.ow2.util.cluster.jgroups.ConnectionManager;
import org.ow2.util.cluster.jgroups.IMessageDispatcher;
import org.ow2.util.cluster.jgroups.MessageDispatcherWrapper;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
/**
* This class processes the HA messages received through JGroups.
* @author Francisco Perez-Sorrosal (fpsorrosal@[email protected] )
* @author Alberto Paz-Jimenez (apaz@[email protected] )
*/
public class JGMessageManager implements RequestHandler, MessageManager {
/**
* Logger.
*/
private static Log logger = LogFactory.getLog(JGMessageManager.class);
/**
* Default stack to configure JGroups.
*/
private static final String JGROUPS_STACK = "UDP(mcast_addr=224.0.0.40" + ";mcast_port=30001" + ";ip_ttl=32;"
+ "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" + "PING(timeout=2000;num_initial_members=3):"
+ "MERGE2(min_interval=5000;max_interval=10000):" + "FD(timeout=2000;max_tries=3;shun=true):"
+ "VERIFY_SUSPECT(timeout=1500):" + "pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):"
+ "UNICAST(timeout=1200,2400,3600):" + "pbcast.STABLE(stability_delay=1000;desired_avg_gossip=2000):"
+ "FRAG(frag_size=4096;down_thread=false;up_thread=false):"
+ "pbcast.GMS(join_timeout=3000;join_retry_timeout=2000;" + "shun=false;print_local_addr=true)";
/**
* Default group name.
*/
private static final String DEFAULT_GROUP_NAME = "jonas-rep";
private final ReplicationManager replicationManager;
/**
* JGroups related classes.
*/
private JChannel channel;
private IMessageDispatcher dispatcher;
private JGViewManager viewMgr;
private Address address;
private LinkedList messages;
private ProcessThread processThread;
private long messagesNumber;
private long messagesSize;
private final String jgroupsHAConfFilename;
private final String jgroupsHAGroupName;
/**
* Constructor.
*/
public JGMessageManager(final String jgroupsConf,
final String jgroupsGroupname,
final ReplicationManager replicationManager,
final long timeout) {
this.replicationManager = replicationManager;
if(jgroupsConf == null) {
jgroupsHAGroupName = DEFAULT_GROUP_NAME;
} else {
jgroupsHAGroupName = jgroupsGroupname;
}
logger.info("jgroups HA group name is: " + jgroupsHAGroupName);
jgroupsHAConfFilename = jgroupsConf;
logger.info("jgroups HA configuration file is: " + jgroupsHAConfFilename);
IConfig config = ClusterViewManagerFactory.getFactory().getConfig();
String confDir = config.getConfDir();
URL file = null;
if(confDir != null) {
URI uri = new File(confDir, jgroupsHAConfFilename).toURI();
try {
file = uri.toURL();
} catch (MalformedURLException e) {
logger.warn("Cannot get the url for the uri: {0}", uri, e);
}
}
if(file == null) {
file = ClassLoader.getSystemClassLoader().getResource(jgroupsHAConfFilename);
if(file == null) {
file = Thread.currentThread().getContextClassLoader().getResource(jgroupsHAConfFilename);
if(file == null) {
file = getClass().getResource(jgroupsHAConfFilename);
}
}
}
try {
if (file != null) {
channel = new JChannel(file);
} else {
logger.info("error accesing jgroups HA configuration file, using defaults");
channel = new JChannel(JGROUPS_STACK);
}
channel.setOpt(Channel.VIEW, true);
// Avoid our own messages
channel.setOpt(Channel.LOCAL, false);
// Set the auto-reconnect option for enabling a node to leave and re-join the cluster
channel.setOpt(Channel.AUTO_RECONNECT, true);
viewMgr = new JGViewManager();
IMessageDispatcher messageDispatcher =
new MessageDispatcherWrapper(channel, null, viewMgr, this);
ConnectionManager connectionManager =
new ConnectionManager(timeout, messageDispatcher, IMessageDispatcher.class);
channel.addChannelListener(connectionManager);
dispatcher = (IMessageDispatcher) Proxy.newProxyInstance(
IMessageDispatcher.class.getClassLoader(), new Class[]{IMessageDispatcher.class}, connectionManager);
channel.connect(jgroupsHAGroupName);
if(config.isAdminEnabled()) {
// Register the JMX MBeans
try {
JmxConfigurator.registerChannel(
channel, MBeanUtils.getMBeanServer(),
MBeanUtils.getMBeanDomainName(), channel.getClusterName() + ",name=HA", true);
} catch (Exception e) {
logger.warn("Unable to register the channel to the MBean Server", e);
}
}
messages = new LinkedList();
processThread = new ProcessThread(messages);
processThread.setDaemon(true);
processThread.start();
address = channel.getLocalAddress();
logger.debug(address + " joined group " + jgroupsHAGroupName);
// Initialize statistics
messagesNumber = 0;
messagesSize = 0;
} catch (ChannelException e) {
logger.error("Error creating JGroups channel", e);
}
}
/* (non-Javadoc)
* @see org.ow2.cmi.ha.MessageManager#sendMessage(org.ow2.cmi.ha.HaMessageData)
*/
public void sendMessage(final HaMessageData messageData) {
Message message = new Message(null, null, messageData);
// Compute statistics
messagesNumber++;
messagesSize += message.size();
RspList rspList = dispatcher.castMessage(null, message, GroupRequest.GET_FIRST, 0);
if (logger.isDebugEnabled()) {
Address localAddress = dispatcher.getChannel().getLocalAddress();
logger.debug("Message sended. Length: " + message.getBuffer().length + " From: " + localAddress);
logger.debug("Response: " + rspList.toString());
}
}
/**
* Processes the replication messages received. Depending on the message's type
* a concrete process will be performed
*/
public Object handle(final Message message) {
if (logger.isDebugEnabled()) {
logger.debug("-----------------------------------------------");
logger.debug("Processing message: " + message + " in: " + dispatcher.getChannel().getLocalAddress());
}
Object o = message.getObject();
if (o instanceof HaMessageData) {
synchronized (messages) {
messages.add((HaMessageData) o);
// COMPLETE: Check if this should be > 0
if (messages.size() == 1) {
processThread.resumeExecution();
}
}
} else {
logger.debug("\tNo action performed, unknown message format!!!");
}
logger.debug("-----------------------------------------------");
return null;
}
/* (non-Javadoc)
* @see org.ow2.cmi.ha.MessageManager#clear()
*/
public void clear() {
dispatcher.stop();
if(ClusterViewManagerFactory.getFactory().getConfig().isAdminEnabled()) {
String domain = MBeanUtils.getMBeanDomainName();
String clusterName = channel.getClusterName();
String name = domain + ":type=channel,cluster=" + clusterName
+ ",name=HA";
String protos = domain + ":type=protocol,cluster=" + clusterName
+ ",name=HA" + ",*";
try {
JmxConfigurator.unregisterChannel(MBeanUtils.getMBeanServer(), name);
JmxConfigurator.unregister(MBeanUtils.getMBeanServer(), protos);
} catch (Exception e) {
logger.warn(
"Error when unregistering the channel with name {0} from the MBean server",
clusterName, e);
}
}
channel.disconnect();
channel.close();
processThread.stopExecution();
}
/**
* Get the number of replicated messages sent.
* @return the number of replicated messages
*/
public long getNumberofReplicatedMessages() {
return messagesNumber;
}
/**
* Get the average size of the replicated messages sent.
* @return the average size of the replicated messages sent.
*/
public double getAvgSizeofReplicatedMessages() {
if (messagesNumber > 0) {
return messagesSize / messagesNumber;
} else {
return 0;
}
}
/**
* Get the total size of the replicated messages sent.
* @return the total size of the replicated messages
*/
public double getTotSizeofReplicatedMessages() {
return messagesSize;
}
/**
* Get the JGroups configuration file name.
* @return the JGroups configuration file name
*/
public String jgroupsConfFileName() {
return jgroupsHAConfFilename;
}
/**
* This Thread process messages in messages list.
* @author Francisco Perez-Sorrosal (fpsorrosal@[email protected] )
* @author Alberto Paz-Jimenez (apaz@[email protected] )
*/
private final class ProcessThread extends Thread {
private volatile Thread test;
private final LinkedList messages;
private volatile boolean suspended;
ProcessThread(final LinkedList messages) {
this.messages = messages;
}
@Override
public void run() {
logger.debug("ProcessMessage thread started");
suspended = false;
test = Thread.currentThread();
while (test == Thread.currentThread()) {
try {
HaMessageData o = null;
synchronized (messages) {
if (messages.size() > 0) {
o = messages.removeFirst();
} else {
suspendExecution();
}
}
if (o != null) {
replicationManager.processMessage(o);
}
} catch (NoSuchElementException e) {
// If there are no messages suspend the thread
suspendExecution();
}
if (suspended) {
synchronized(this) {
try {
while (suspended && test == Thread.currentThread()) {
wait();
}
} catch (InterruptedException e1) {
;
}
}
}
}
}
void stopExecution() {
logger.debug("ProcessMessage thread stoped");
synchronized (this) {
test = null;
notify();
}
}
void suspendExecution() {
logger.debug("ProcessMessage thread suspended");
synchronized (this) {
suspended = true;
}
}
void resumeExecution() {
logger.debug("ProcessMessage thread resumed");
synchronized (this) {
suspended = false;
notify();
}
}
}
}