This topic has not yet been written. The content below is from the topic description.
Transporter sample - clustered In the previous examples, there has been one and only one target POJO to make calls upon. If that target POJO was not available, the client call would fail. In the transporter clustered example (found in org.jboss.remoting.samples.transporter.clustered package), will show how to use the transporter in clustered mode so that if one target POJO becomes unavailable, the client call can be seamlessly failed over to another available target POJO on the network, regardless of network transport type. This example uses the domain objects from the first, basic example, so only need to cover the client and server code. For this example, there are three different server classes. The first class is the SocketServer class, which is the exact same as the Server class in the basic example, except for the call to the TransportServer's createTransportServer() method. public class SocketServer { public static String locatorURI = "socket://localhost:5400"; private TransporterServer server = null; public void start() throws Exception { server = TransporterServer.createTransporterServer(getLocatorURI(), new CustomerProcessorImpl(), CustomerProcessor.class.getName(), true); } protected String getLocatorURI() { return locatorURI; } public void stop() { if(server != null) { server.stop(); } } public static void main(String[] args) { SocketServer server = new SocketServer(); try { server.start(); Thread.currentThread().sleep(60000); } catch(Exception e) { e.printStackTrace(); } finally { server.stop(); } } } Notice that are now calling on the TransportServer to create a server with the locator uri and target POJO (CustomerProcessorImpl) as before, but have also added the interface type of the target POJO (CustomerProcessor) and that want clustering turned on (via the last true parameter). The interface type of the target POJO is needed because this will be used as the subsystem within the remoting server for the target POJO. The subsystem value will be what the client uses to determine if discovered remoting server is for the target POJO they are looking for. The transporter uses the MulticastDetector from JBoss Remoting for automatic discovery when in clustered mode. The actual detection of remote servers that come online can take up to a few seconds once started. There is a JNDI based detector provided within JBoss Remoting, but has not been integrated within the transporters yet. The second server class is the RMIServer class. The RMIServer class extends the SocketServer class and uses a different locator uri to specify rmi as the transport protocol and a different port (5500). public class RMIServer extends SocketServer { private String localLocatorURI = "rmi://localhost:5500"; protected String getLocatorURI() { return localLocatorURI; } public static void main(String[] args) { SocketServer server = new RMIServer(); try { server.start(); Thread.currentThread().sleep(60000); } catch(Exception e) { e.printStackTrace(); } finally { server.stop(); } } } The last server class is the HTTPServer class. The HTTPServer class also extends the SocketServer class and specifies http as the transport protocol and 5600 as the port to listen for requests on. public class HTTPServer extends SocketServer { private String localLocatorURI = "http://localhost:5600"; protected String getLocatorURI() { return localLocatorURI; } public static void main(String[] args) { SocketServer server = new HTTPServer(); try { server.start(); Thread.currentThread().sleep(60000); } catch(Exception e) { e.printStackTrace(); } finally { server.stop(); } } } On the client side, there is only the Client class. This class is very similar to the one from the basic example. The main exceptions are (1) the addition of a TransporterClient call to create a transporter client and (2) the fact that it continually loops, making calls on its customerProcessor variable to process customers. This is done so that when we run the client, we can kill the different servers and see that the client continues to loop making its calls without any exceptions or errors. public class Client { private String locatorURI = SocketServer.locatorURI; private CustomerProcessor customerProcessor = null; public void makeClientCall() throws Exception { Customer customer = createCustomer(); System.out.println("Customer to be processed: " + customer); Customer processedCustomer = customerProcessor.processCustomer(customer); System.out.println("Customer is now: " + processedCustomer); //TransporterClient.destroyTransporterClient(customerProcessor); } public void getCustomerProcessor() throws Exception { customerProcessor = (CustomerProcessor) TransporterClient.createTransporterClient(locatorURI, CustomerProcessor.class, true); } private Customer createCustomer() { Customer cust = new Customer(); cust.setFirstName("Bob"); cust.setLastName("Smith"); Address addr = new Address(); addr.setStreet("101 Oak Street"); addr.setCity("Atlanata"); addr.setState("GA"); addr.setZip(30249); cust.setAddr(addr); return cust; } public static void main(String[] args) { Client client = new Client(); try { client.getCustomerProcessor(); while(true) { try { client.makeClientCall(); Thread.currentThread().sleep(5000); } catch(Exception e) { e.printStackTrace(); } } } catch(Exception e) { e.printStackTrace(); } } } The first item of note is that the locator uri from the SocketServer class is being used. Technically, this is not required as once the clustered TransporterClient is started, it will start to discover the remoting servers that exist on the network. However, this process can take several seconds to occur, so unless it is known that no calls will be made on the remote proxy right away, it is best to bootstrap with a known target server. Can also see that in the main() method, the first call on the Client instance is to getCustomerProcessor(). This method will call the TransporterClient's createTransporterClient() method and passes the locator uri for the target POJO server, the type of POJO's remote proxy, and that clustering should be enabled. After getting the customer processor remote proxy, will continually loop making calls using the remote proxy (via the processCustomer() method on the customerProcessor variable). To run this example, all the servers need to be started (by running the SocketServer, RMIServer, and HTTPServer classes). Then run the Client class. This can be done via ant targets as well. So for example, could open four console windows and enter the ant targets as follows: ant run-transporter-clustered-socket-server ant run-transporter-clustered-http-server ant run-transporter-clustered-rmi-server ant run-transporter-clustered-client Once the client starts running, should start to see output logged to the SocketServer, since this is the one used to bootstrap. This output would look like: processed customer with new id of 378 processed customer with new id of 487 processed customer with new id of 980 Once the SocketServer instance has received a few calls, kill this instance. The next time the client makes a call on its remote proxy, which happens every five seconds, it should fail over to another one of the servers (and will see similar output on that server instance). After that server has received a few calls, kill it and should see it fail over once again to the last server instance that is still running. Then, if kill that server instance, will see a CannotConnectException and stack trace similar to the following: ... org.jboss.remoting.CannotConnectException: Can not connect http client invoker. at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:147) at org.jboss.remoting.transport.http.HTTPClientInvoker.transport(HTTPClientInvoker.java:56) at org.jboss.remoting.RemoteClientInvoker.invoke(RemoteClientInvoker.java:112) at org.jboss.remoting.Client.invoke(Client.java:226) at org.jboss.remoting.Client.invoke(Client.java:189) at org.jboss.remoting.Client.invoke(Client.java:174) at org.jboss.remoting.transporter.TransporterClient.invoke(TransporterClient.java:219) at $Proxy0.processCustomer(Unknown Source) at org.jboss.remoting.samples.transporter3.client.Client.makeClientCall(Client.java:29) at org.jboss.remoting.samples.transporter3.client.Client.main(Client.java:64) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:86) Caused by: java.net.ConnectException: Connection refused: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182) at java.net.Socket.connect(Socket.java:507) at java.net.Socket.connect(Socket.java:457) at sun.net.NetworkClient.doConnect(NetworkClient.java:157) at sun.net.www.http.HttpClient.openServer(HttpClient.java:365) at sun.net.www.http.HttpClient.openServer(HttpClient.java:477) at sun.net.www.http.HttpClient. (HttpClient.java:214) at sun.net.www.http.HttpClient.New(HttpClient.java:287) at sun.net.www.http.HttpClient.New(HttpClient.java:299) at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:792) at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:744) at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:669) at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:836) at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:117) ... 14 more since there are no target servers left to make calls on. Notice that earlier in the client output there were no errors while was failing over to the different servers as they were being killed. Because the CannotConnectException is being caught within the while loop, the client will continue to try calling the remote proxy and getting this exception. Now re-run any of the previously killed servers and will see that the client will discover that server instance and begin to successfully call on that server. The output should look something like: ... at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:669) at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:836) at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:117) ... 14 more Customer to be processed: Customer: customer id: -1 first name: Bob last name: Smith street: 101 Oak Stree city: Atlanata state: null zip: 30249 Customer is now: Customer: customer id: 633 first name: Bob last name: Smith street: 101 Oak Stree city: Atlanata state: null zip: 30249 ... As demonstrated in this example, fail over can occur across any of the JBoss Remoting transports. Clustered transporters is also supported using JBoss Serialization, which was introduced in the previous example. It is important to understand that in the context of transporters, clustering means invocation fail over. The JBoss Remoting transporters themselves do not handle any form of state replication. If this feature were needed, could use JBoss Cache to store the target POJO instances so that when their state changed, that change would be replicated to the other target POJO instances running in other processes. 12.9.6. Transporters sample - multiple The multiple transporter example (found in org.jboss.remoting.samples.transporter.multiple package) shows how can have a multiple target pojos exposed via the same TransporterServer. In this example, will be two pojos being exposed, CustomerProcessorImpl and AccountProcessorImpl. Since the domain objects for this example is similar to the others discussed in previous examples, will just focus on the server and client code. On the server side, need to create the TransporterServer so that will included both of the target pojos. public class Server { private String locatorURI = "socket://localhost:5400"; private TransporterServer server = null; public void start() throws Exception { server = TransporterServer.createTransporterServer(locatorURI, new CustomerProcessorImpl(), CustomerProcessor.class.getName()); server.addHandler(new AccountProcessorImpl(), AccountProcessor.class.getName()); } public void stop() { if(server != null) { server.stop(); } } public static void main(String[] args) { Server server = new Server(); try { server.start(); Thread.currentThread().sleep(60000); } catch(Exception e) { e.printStackTrace(); } finally { server.stop(); } } } The TransporterServer is created with the CustomerProcessorImpl as the inital target pojo. Now that have a live TransporterServer, can add other pojos as targets. This is done using the addHandler() method where the target pojo instance is passed and then the interface type to be exposed as. Next have the Client that makes the call to both pojos. public class Client { private String locatorURI = "socket://localhost:5400"; public void makeClientCall() throws Exception { Customer customer = createCustomer(); CustomerProcessor customerProcessor = (CustomerProcessor) TransporterClient.createTransporterClient(locatorURI, CustomerProcessor.class); System.out.println("Customer to be processed: " + customer); Customer processedCustomer = customerProcessor.processCustomer(customer); System.out.println("Customer is now: " + processedCustomer); AccountProcessor accountProcessor = (AccountProcessor) TransporterClient.createTransporterClient(locatorURI, AccountProcessor.class); System.out.println("Asking for a new account to be created for customer."); Account account = accountProcessor.createAccount(processedCustomer); System.out.println("New account: " + account); TransporterClient.destroyTransporterClient(customerProcessor); TransporterClient.destroyTransporterClient(accountProcessor); } private Customer createCustomer() { Customer cust = new Customer(); cust.setFirstName("Bob"); cust.setLastName("Smith"); Address addr = new Address(); addr.setStreet("101 Oak Street"); addr.setCity("Atlanta"); addr.setState("GA"); addr.setZip(30249); cust.setAddr(addr); return cust; } public static void main(String[] args) { org.jboss.remoting.samples.transporter.multiple.client.Client client = new org.jboss.remoting.samples.transporter.multiple.client.Client(); try { client.makeClientCall(); } catch (Exception e) { e.printStackTrace(); } } } Notice that TransporterClients are created for each target pojo want to call upon, they just happen to share the same locator uri. These are independant instances so need to both be destroyed on their own when finished with them. To run this example, run the Server class and then the Client class. This can be done via ant targets 'run-transporter-multiple-server' and then 'run-transporter-multiple-client'. For example: ant run-transporter-multiple-server and then: ant run-transporter-multiple-client The output for the server should look similar to: processed customer with new id of 980 Created new account with account number: 1 and for customer: Customer: customer id: 980 first name: Bob last name: Smith street: 101 Oak Street city: Atlanta state: GA zip: 30249 and the output from the client should look similar to: Customer to be processed: Customer: customer id: -1 first name: Bob last name: Smith street: 101 Oak Street city: Atlanta state: GA zip: 30249 Customer is now: Customer: customer id: 980 first name: Bob last name: Smith street: 101 Oak Street city: Atlanta state: GA zip: 30249 Asking for a new account to be created for customer. New account: Account - account number: 1 Customer: Customer: customer id: 980 first name: Bob last name: Smith street: 101 Oak Street city: Atlanta state: GA zip: 30249