/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ha.singleton;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.List;
import org.jboss.ha.framework.interfaces.ClusterNode;
import org.jboss.logging.Logger;
/**
* Election policy that chooses the node where the singleton should run based on
* the given preferred master node in ip_address:port_number or
* host_name:port_number format. If the preferred master is null, or its
* ip_address does not resolve to a valid host name, or the port number is
* invalid, it delegates to the standard policy.
*
* @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
* @author Paul Ferraro
*/
public class PreferredMasterElectionPolicy
extends HASingletonElectionPolicySimple
implements PreferredMasterElectionPolicyMBean
{
private Logger log = Logger.getLogger(this.getClass());
private volatile InetSocketAddress preferredMaster;
// ------------------------------------------------------------- Properties
/**
* @see PreferredMasterElectionPolicyMBean#setPreferredMaster(String)
*/
public void setPreferredMaster(String value)
{
String node = (value != null) ? value.trim() : "";
if (node.length() > 0)
{
try
{
URI uri = new URI("cluster://" + node);
String host = uri.getHost();
if (host == null)
{
throw new IllegalArgumentException("Cannot extract host/address from " + node);
}
this.preferredMaster = new InetSocketAddress(InetAddress.getByName(host), uri.getPort());
}
catch (URISyntaxException e)
{
throw new IllegalArgumentException("Cannot extract URI from " + node, e);
}
catch (UnknownHostException e)
{
throw new IllegalArgumentException("Cannot resolve host from " + node, e);
}
}
else
{
this.preferredMaster = null;
}
}
/**
* @see PreferredMasterElectionPolicyMBean#getPreferredMaster()
*/
public String getPreferredMaster()
{
InetSocketAddress address = this.preferredMaster;
return (address != null) ? address.toString() : null;
}
// ----------------------------------------------------- HASingletonElector
@Override
public ClusterNode elect(List<ClusterNode> candidates)
{
InetSocketAddress sockAddress = this.preferredMaster;
ClusterNode master = null;
// If preferred master is defined and contained in cluster, return it
if (sockAddress != null)
{
InetAddress address = sockAddress.getAddress();
int port = sockAddress.getPort();
// First find by address
master = this.find(candidates, address.getHostAddress(), port);
if (master == null)
{
// Then try by hostname
master = this.find(candidates, address.getHostName(), port);
}
}
return (master != null) ? master : super.elect(candidates);
}
private ClusterNode find(List<ClusterNode> candidates, String host, int port)
{
String node = host + ":" + port;
this.log.debug("Checking if " + node + " is in candidate list: " + candidates);
for (ClusterNode candidate: candidates)
{
if (candidate.getName().equals(node))
{
return candidate;
}
}
return null;
}
}