All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.headlessintrace.client.connection.DefaultConnection Maven / Gradle / Ivy

package org.headlessintrace.client.connection;


import java.net.InetSocketAddress;

import java.net.Socket;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.headlessintrace.client.DefaultFactory;
import org.headlessintrace.client.HumanReadableMessages;
import org.headlessintrace.client.ITraceWriter;
import org.headlessintrace.client.connection.command.IAgentCommand;
import org.headlessintrace.client.model.ITraceEvent;
import org.headlessintrace.client.request.BadCompletedRequestListener;
import org.slf4j.LoggerFactory;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
/**
 * This class supports a simple use case where a single connection writes events to a single event list.
 * More complicated code can be written to
 * - have a single connection write to multiple event lists (pub-sub style)
 * - have multiple connections write to a single event list (two JVMs participate in a single workflow).
 * The "client" in the package name indicates that this class runs on the client side, maintaining a connection with something else (an intrace agent on a server).
 * @author erikostermueller
 *
 */
public class DefaultConnection implements IConnection {
//	private static final Logger LOG = Logger.getLogger( DefaultConnection.class.getName() );
	private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(DefaultConnection.class);	
	ConnectionDetail getConnectionDetail() {
		return m_connDetail;
	}

	@Override
	public String[] getModifiedClasses() {
		String modifiedClassesUnparsed = null;
		getConnectionDetail().getControlThread().sendMessage("[listmodifiedclasses");
		modifiedClassesUnparsed  = getConnectionDetail().getControlThread().getMessage();

		if (modifiedClassesUnparsed!=null && modifiedClassesUnparsed.length() >= 2) {
			if (modifiedClassesUnparsed.charAt(modifiedClassesUnparsed.length()-1)==']')
				modifiedClassesUnparsed = modifiedClassesUnparsed.substring(0, modifiedClassesUnparsed.length()-1);
			if (modifiedClassesUnparsed.charAt(0)=='[')
				modifiedClassesUnparsed = modifiedClassesUnparsed.substring(1);
		}

		String[] rc = null;
		if ("".equals(modifiedClassesUnparsed.trim()) )
			rc = null;
		else
			rc = modifiedClassesUnparsed.trim().split("\\s*,[,\\s]*");		
	
		return rc;
	}
	@Override
	public int getConnCallbackSize() {
		return getConnectionDetail().getConnCallbacks().size();
	}
	private void setConnectionDetail(ConnectionDetail connectionDetail) {
		this.m_connDetail = connectionDetail;
	}
	private ITraceWriter m_traceWriter = null;
	private IAgentCommand[] getCommandArray() {
		return getConnectionDetail().getStartupCommands();
	}
	@Override
	public void setCommandArray(IAgentCommand[] commandArray) {
		getConnectionDetail().setCommandArray(commandArray);
	}
	@Override
	public IConnectionStateCallback getMasterCallback() {
		return getConnectionDetail();
	}
	@Override
	public void addCallback(IConnectionStateCallback callback) {
		getConnectionDetail().addConnCallback(callback);
	}
	private ConnectionDetail m_connDetail = null;
	HostPort m_hostPort = null;
	public DefaultConnection() {
		setConnectionDetail(new ConnectionDetail());
		setTraceWriter(DefaultFactory.getFactory().getTraceWriter());
		getTraceWriter().setTraceEvents(new BasicEventList());
	}
	@Override
	public EventList getTraceEvents() {
		return m_traceWriter.getTraceEvents();
		//return traceEvents;
	}

	@Override
	public boolean connect(String host, int port) throws ConnectionTimeout, ConnectionException, BadCompletedRequestListener {
		return connect(host,port, null);
	}

	/**
	 * The elegant implementation of the connection timeout was stolen from here:
	 * 	http://stackoverflow.com/questions/2275443/how-to-timeout-a-thread
	 */
	@Override
	public boolean connect(HostPort hostPort, IAgentCommand[] startupCommandAry ) throws ConnectionTimeout, ConnectionException {
		boolean ynRC = false;
		setHostPort( hostPort );
		List errors = getHostPort().validate();
		
		if (errors.size()>0) { 
			ConnectionException e = new ConnectionException(getHostPort(), errors.toString() ); 
			throw e;
		} else {
	        HumanReadableMessages msgs = DefaultFactory.getFactory().getMessages();
	        long lngTimeoutMs = DefaultFactory.getFactory().getConfig().getConnectWaitMs();
			setCommandArray(startupCommandAry);
		
	        ExecutorService executor = Executors.newSingleThreadExecutor();
	        Future future = executor.submit(new Task());
	        try {
	            getMasterCallback().setConnectionStatusMsg(msgs.getAttemptingToConnect( getHostPort()) );
	            getMasterCallback().setConnectState(ConnectState.CONNECTING);

	            Boolean ynTaskRC = future.get(lngTimeoutMs, TimeUnit.MILLISECONDS); 
	            if (ynTaskRC.equals(Boolean.TRUE)) {
	        		NetworkDataReceiverThread2 ntt2 = getConnectionDetail().getNetworkTraceThread2();
	        		ntt2.addTraceWriter(m_traceWriter);
	        		ynRC = true;
	            }
	        } catch (TimeoutException e) {
	            getMasterCallback().setConnectionStatusMsg( e.toString() ); 
	            getMasterCallback().setConnectState(ConnectState.DISCONNECTED_ERR);
	        } catch (InterruptedException e) {
	            getMasterCallback().setConnectionStatusMsg( e.toString() ); 
	            getMasterCallback().setConnectState(ConnectState.DISCONNECTED_ERR);
			} catch (ExecutionException e) {
	            getMasterCallback().setConnectionStatusMsg( e.toString() ); 
	            getMasterCallback().setConnectState(ConnectState.DISCONNECTED_ERR);
			} finally {
		        executor.shutdownNow();
			}
		}
        return ynRC;
	}
	class Task implements Callable {
	    @Override
	    public Boolean call() throws Exception {
	    	Boolean ynRC = Boolean.FALSE;
	    	final Socket socket = new Socket();
	    	HumanReadableMessages msgs = DefaultFactory.getFactory().getMessages();
	        try {
	            socket.connect(new InetSocketAddress(getHostPort().hostNameOrIpAddress, getHostPort().port));
	            getHostPort().setIp(socket.getInetAddress().getHostAddress());
	            getConnectionDetail().setSocket(socket);
	            getMasterCallback().setConnectionStatusMsg( 
	            		msgs.getConnectionSuccessful( getHostPort() ) );
	            getMasterCallback().setConnectState(ConnectState.CONNECTED);
	            ynRC = Boolean.TRUE;
	        } catch (Exception e) {
	        	  getMasterCallback().setConnectionStatusMsg( msgs.getFailedConnection(getHostPort(), e) );
	        	  getMasterCallback().setConnectState(ConnectState.DISCONNECTED_ERR);
	        	  getConnectionDetail().setSocket(null);
	        	  ynRC = Boolean.FALSE;
	        }
	        return ynRC;
	    }
	}	
	public void connect_ORIG(String host, int port, IAgentCommand[] startupCommandAry ) throws ConnectionTimeout, ConnectionException, BadCompletedRequestListener {
		setHostPort( new HostPort(host,port));
		
		addCallback(new DefaultCallback());
		try {
			DefaultConnectionList.getSingleton().connect(getMasterCallback(), m_hostPort , startupCommandAry);
			Thread.sleep(DefaultFactory.getFactory().getConfig().getConnectWaitMs());
		} catch (InterruptedException e) {
			throw new ConnectionTimeout(m_hostPort, DefaultFactory.getFactory().getConfig().getConnectWaitMs());
		}
		
		IConnection c = DefaultConnectionList.getSingleton().locateConnection(m_hostPort);

		//TODO TODO TODO
//		NetworkDataReceiverThread2 ntt2 = c.getConn.getNetworkTraceThread2();
//		ntt2.addTraceWriter(m_traceWriter);
	}
	
	@Override
	public HostPort getHostPort() {
		return m_hostPort;
	}
	@Override
	public void setHostPort(HostPort hostPort) {
		this.m_hostPort = hostPort;
	}
	@Override
	public void disconnect() {
		IConnectionList connectionList = DefaultConnectionList.getSingleton();
		//IConnection cpt = connectionList.locateConnection(m_hostPort);
		
		try {
			this.getConnectionDetail().disconnect();
			//this.getNetworkTraceThread2().disconnect();
			connectionList.disconnect(this, getMasterCallback());
		} catch(DisconnectionException de) {
			//Since our goal is to disconnect, no need to do anything with the exception.
		}
	}
	@Override
	public ITraceWriter getTraceWriter() {
		return m_traceWriter;
	}
	@Override
	public void setTraceWriter(ITraceWriter traceWriter) {
		this.m_traceWriter = traceWriter;
	}
	@Override
	public boolean connect(String host, int port, IAgentCommand[] startupCommandAry)
			throws ConnectionTimeout, ConnectionException,
			BadCompletedRequestListener {
		HostPort hostPort = new HostPort(host,port);
		return connect(hostPort,startupCommandAry);
		
	}
	  /**
	   * Returns the count of callbacks still listening to 'this'.
	   * This method will perform a hard disconnect if 0 is returned.
	   * @param criteria
	   * @return
	   */
	  public int removeCallback(IConnectionStateCallback criteria) {
		  
		  List listCallbacks = getConnectionDetail().getConnCallbacks();
		  /**
		   * If this method is about to delete the last callback, then
		   * there are no windows left listening, so it is safe to
		   * do a hard disconnect.
		   */
		  if (listCallbacks.size() <= 1) {
			  getConnectionDetail().unHappyDisconnect();
			  listCallbacks.remove(criteria);
			  
			  DefaultConnectionList connList = (DefaultConnectionList) DefaultConnectionList.getSingleton();
			  connList.remove(this);
			  
		  } else {
			//utter a last dying gasp (DISCONNECTED status) before removing the callback.
			  //criteria.setConnectionState(ConnectState.DISCONNECTED);
			  //broadcastConnectionState(criteria);
			  listCallbacks.remove(criteria);
		  }
		  return listCallbacks.size();
	  }
	
	@Override
	public int removeConnectionStatusCallback(IConnectionStateCallback cb) {
		return removeCallback(cb);
		
	}
	@Override
	public boolean isConnected() {
		boolean ynRC = false;
		if (getConnectionDetail().getConnectState().equals(ConnectState.CONNECTED))
			ynRC = true;
		return ynRC;
	}
	@Override
	public void executeStartupCommands() {
		getConnectionDetail().executeStartupCommands();
		
	}
	@Override
	public NetworkDataReceiverThread2 getNetworkTraceThread2() {
		return getConnectionDetail().getNetworkTraceThread2();
	}
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("hash [" + this.hashCode() + "]\n");
		sb.append("isConnected [" + isConnected() + "]\n");
		sb.append("count of callbacks [" + getConnCallbackSize() + "]");
		if (this.getConnectionDetail() !=null)
			sb.append("detail [" + this.getConnectionDetail().toString() + "]\n");
		return sb.toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy