SocketTransport.java
/*
* IronJacamar, a Java EE Connector Architecture implementation
* Copyright 2014, Red Hat Inc, 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 Eclipse Public License 1.0 as
* published by the Free Software Foundation.
*
* 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 Eclipse
* Public License for more details.
*
* You should have received a copy of the Eclipse 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.ironjacamar.core.workmanager.transport.remote.socket;
import org.ironjacamar.core.CoreBundle;
import org.ironjacamar.core.CoreLogger;
import org.ironjacamar.core.spi.workmanager.Address;
import org.ironjacamar.core.workmanager.transport.remote.AbstractRemoteTransport;
import org.ironjacamar.core.workmanager.transport.remote.ProtocolMessages.Request;
import org.ironjacamar.core.workmanager.transport.remote.ProtocolMessages.Response;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.resource.spi.work.WorkException;
import org.jboss.logging.Logger;
import org.jboss.logging.Messages;
/**
* The socket transport
*
* @author <a href="mailto:jesper.pedersen@ironjacamar.org">Jesper Pedersen</a>
*/
public class SocketTransport extends AbstractRemoteTransport<String> implements Runnable
{
/** The logger */
private static CoreLogger log = Logger.getMessageLogger(CoreLogger.class, SocketTransport.class.getName());
/** Whether trace is enabled */
private static boolean trace = log.isTraceEnabled();
/** The bundle */
private static CoreBundle bundle = Messages.getBundle(CoreBundle.class);
/** The bind address */
private String host;
/** The bind port */
private int port;
/** The peers */
private Set<String> peers;
/** Is the server running ? */
private AtomicBoolean running;
/** The server socket */
private ServerSocket ss;
/** Is the transport initialized */
private boolean initialized;
/**
* Constructor
*/
public SocketTransport()
{
super();
this.host = null;
this.port = 0;
this.peers = null;
this.running = new AtomicBoolean(false);
this.ss = null;
this.initialized = false;
}
/**
* {@inheritDoc}
*/
public void startup() throws Throwable
{
if (!running.get())
{
InetSocketAddress address = new InetSocketAddress(host, port);
ss = new ServerSocket();
ss.bind(address);
running.set(true);
getExecutorService().submit(this);
}
}
/**
* {@inheritDoc}
*/
public boolean isInitialized()
{
return initialized;
}
/**
* {@inheritDoc}
*/
public void initialize() throws Throwable
{
if (peers != null && !initialized)
{
for (String addr : peers)
{
if (trace)
log.tracef("Peer: %s", addr);
try
{
// Let other node know of us
sendMessage(addr, Request.JOIN, getOwnAddress());
// Update the local information
Set<Address> workManagers = (Set<Address>)sendMessage(addr, Request.GET_WORKMANAGERS);
if (trace)
log.tracef("Peer WorkManagers: %s", workManagers);
if (workManagers != null)
{
for (Address a : workManagers)
{
join(a, addr);
long shortRunningFree =
(long)sendMessage(addr, Request.GET_SHORTRUNNING_FREE, a);
long longRunningFree =
(long)sendMessage(addr, Request.GET_LONGRUNNING_FREE, a);
localUpdateShortRunningFree(a, shortRunningFree);
localUpdateLongRunningFree(a, longRunningFree);
}
}
}
catch (Throwable t)
{
log.error(t.getMessage(), t);
}
}
}
initialized = true;
}
/**
* {@inheritDoc}
*/
public void shutdown() throws Throwable
{
running.set(false);
if (ss != null)
ss.close();
}
@Override
protected Serializable sendMessage(String address, Request request, Serializable... parameters)
throws WorkException
{
String[] addressPart = address.split(":");
Socket socket = null;
ObjectOutputStream oos = null;
if (trace)
log.tracef("%s:%d: sending message=%s to %s:%s", ss.getInetAddress().getHostName(),
ss.getLocalPort(), request, addressPart[0], addressPart[1]);
try
{
socket = new Socket(addressPart[0], Integer.valueOf(addressPart[1]));
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeInt(request.ordinal());
oos.writeInt(request.getNumberOfParameter());
if (parameters != null)
{
for (Serializable o : parameters)
{
oos.writeObject(o);
}
}
oos.flush();
return parseResponse(socket);
}
catch (Throwable t)
{
if (log.isDebugEnabled())
{
log.debug("Error sending command: " + t.getMessage(), t);
}
if (t instanceof WorkException)
{
throw (WorkException) t;
}
else
{
WorkException we = new WorkException(t.getMessage());
we.initCause(t);
throw we;
}
}
finally
{
if (oos != null)
{
try
{
oos.close();
}
catch (IOException e)
{
//ignore it
}
}
if (socket != null)
{
try
{
socket.close();
}
catch (IOException e)
{
//ignore it
}
}
}
}
private Serializable parseResponse(Socket socket) throws Throwable
{
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(socket.getInputStream());
int commandOrdinalPosition = ois.readInt();
int numberOfParameters = ois.readInt();
Serializable[] parameters = new Serializable[numberOfParameters];
for (int i = 0; i < numberOfParameters; i++)
{
Serializable parameter = (Serializable)ois.readObject();
parameters[i] = parameter;
}
Response response = Response.values()[commandOrdinalPosition];
switch (response)
{
case OK_VOID : {
return null;
}
case OK_SERIALIZABLE : {
return parameters[0];
}
case WORK_EXCEPTION : {
throw (WorkException)parameters[0];
}
case GENERIC_EXCEPTION : {
throw (Throwable)parameters[0];
}
default :
if (log.isDebugEnabled())
{
log.debug("Unknown response received on socket Transport");
}
throw new WorkException("Unknown response received on socket Transport");
}
}
finally
{
if (ois != null)
{
try
{
ois.close();
}
catch (IOException e)
{
//ignore it
}
}
}
}
/**
* Set the host.
*
* @param host The host to set.
*/
public void setHost(String host)
{
this.host = host;
}
/**
* Set the port.
*
* @param port The port to set.
*/
public void setPort(int port)
{
this.port = port;
}
/**
* Set the peers
* @param peers The peers
*/
public void setPeers(Set<String> peers)
{
this.peers = peers;
}
/**
* Get the physical address
* @return The value
*/
public String getOwnAddress()
{
return host + ":" + port;
}
@Override
public void run()
{
while (running.get())
{
try
{
Socket socket = ss.accept();
Runnable r = new Communication(this, socket);
this.getExecutorService().submit(r);
}
catch (Exception e)
{
if (log.isTraceEnabled())
log.trace(e.getMessage());
}
}
}
@Override
public String toString()
{
return "SocketTransport [host=" + host + ", port=" + port + ", running=" + running + ", ss=" + ss + "]";
}
}