View Javadoc

1   /*
2    * Created on 17 Nov 2007
3    * 
4    */
5   package org.sourceforge.jemm.comm.client;
6   
7   import java.util.HashMap;
8   import java.util.Map;
9   import java.util.concurrent.ExecutorService;
10  import java.util.concurrent.Executors;
11  
12  import org.apache.log4j.Logger;
13  import org.sourceforge.jemm.comm.connection.ClientConnectionFactory;
14  import org.sourceforge.jemm.comm.connection.ConnectionException;
15  import org.sourceforge.jemm.comm.connection.socket.SocketClientConnectionFactory;
16  import org.sourceforge.jemm.comm.shared.IFUtilities;
17  import org.sourceforge.jemm.comm.shared.RPCHandler;
18  import org.sourceforge.jemm.comm.shared.RPCHandlerListener;
19  
20  /**
21   * RPCClient is the client end of an interface RPC connection.  The class allows the client program
22   * to both make RPC calls to a server instance and also present interfaces for the server to call back
23   * on.
24   * See {@link org.sourceforge.jemm.comm.example.echo.EchoClient}/
25   * {@link org.sourceforge.jemm.comm.example.echo.EchoServer} for a simple example.
26   * 
27   * <i><P>Released under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License V2.0 license</a> 
28   * by the <a href="http://jemm.sourceforge.net">JEMM Project</a></i>
29   * 
30   * @author Rory Graves
31   */
32  public class RPCClient implements RPCHandlerListener {
33  	
34      protected static final Logger LOG = Logger.getLogger(RPCClient.class);
35  
36      /** A map of the local interfaces offered by the client to the server */
37      protected Map<Class<?>, Object> localIFMap = new HashMap<Class<?>, Object>();
38      
39      /** The underlying RPCHandler (calls are delegated) */
40      protected RPCHandler rpcHandler;
41      
42      /** A thread pool for handling server callback requests */
43      protected ExecutorService threadPool;
44  
45      protected volatile boolean connected;
46      
47      protected final ClientConnectionFactory connFactory;
48      
49      /**
50       * Creates an RPCClient instance. The client attempts to connect to the hostname/port specified
51       * and will throw an IOException on error
52       * 
53       * @param hostname The servers hostname
54       * @param port The server's port
55       */
56      public RPCClient(String hostname, int port) {
57      	this(new SocketClientConnectionFactory(hostname,port));
58      }
59      
60      /** Creates o RPCClient instance using the given connection factory.
61       * @param connFactory The connection factory to use to connect to the RPCServer.
62       */
63      public RPCClient(ClientConnectionFactory connFactory) {
64      	this.connFactory = connFactory;
65      	connected = false;
66  	}
67  
68  	/**
69       * Make the connection to the remote server. 
70       * @throws ConnectionException On connection error.
71       */
72      public void connect() throws ConnectionException {
73          LOG.info("Connecting to: " + connFactory.getConnectionAddress());
74          threadPool = Executors.newFixedThreadPool(10);
75          rpcHandler = new RPCHandler(true,connFactory.connect(),localIFMap,threadPool,null);
76          rpcHandler.setHandlerListener(this);
77          rpcHandler.initialise();
78          rpcHandler.start();
79          connected = true;
80      }
81  
82      /**
83       * Register an interface that the client offers for callback from the server.
84       * @param ifClass The interface being offered.
85       * @param ifImplentor The implementor of the interface that will process the requests 
86       */
87      public void registerIF(Class<?> ifClass,Object ifImplentor) {
88          IFUtilities.validateInterface(ifClass);
89          
90          if(ifImplentor.getClass().isInstance(ifClass))
91              throw new IllegalArgumentException("given object does not implement interface");
92      
93          if(connected)
94              throw new IllegalStateException("Can not register interface after connection to server established");
95          
96          localIFMap.put(ifClass, ifImplentor);
97      }
98      
99      /**
100      * Get a remote interface implemented by the server.
101      * @param ifClass The interface required.
102      * @return A proxy object implementing the remote interface.
103      */
104     public synchronized Object getServerIF(Class<?> ifClass) {
105         if(!connected)
106             throw new IllegalStateException("Can not get remote interfaces until connection to server established");
107 
108         return rpcHandler.getRemoteIF(ifClass);
109     }
110     
111     /**
112      * Close the connection to the server.
113      */
114     public void close() {
115         connected = false;
116         rpcHandler.close();
117         threadPool.shutdown();
118     }
119 
120     /**
121      * Returns whether the client is connected to the server
122      * @return True if the client is connected, false otherwise.
123      */
124     public boolean isConnected() {
125         return connected;
126     }
127 
128     @Override
129     public void connectionTerminated() {
130         connected = false;
131     }
132 }