From jboss-remoting-commits at lists.jboss.org Tue Nov 18 15:39:57 2008 Content-Type: multipart/mixed; boundary="===============1445728459829918377==" MIME-Version: 1.0 From: jboss-remoting-commits at lists.jboss.org To: jboss-remoting-commits at lists.jboss.org Subject: [jboss-remoting-commits] JBoss Remoting SVN: r4701 - remoting2/branches/2.x/docs/guide/en. Date: Tue, 18 Nov 2008 15:39:57 -0500 Message-ID: --===============1445728459829918377== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: ron.sigal(a)jboss.com Date: 2008-11-18 15:39:56 -0500 (Tue, 18 Nov 2008) New Revision: 4701 Modified: remoting2/branches/2.x/docs/guide/en/chap10.xml Log: JBREM-1057: Replacing screwed up chapter. Modified: remoting2/branches/2.x/docs/guide/en/chap10.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- remoting2/branches/2.x/docs/guide/en/chap10.xml 2008-11-18 20:39:41 UTC= (rev 4700) +++ remoting2/branches/2.x/docs/guide/en/chap10.xml 2008-11-18 20:39:56 UTC= (rev 4701) @@ -1,2634 +1,19 @@ - - - How to use it - sample code + + Transporters - beaming POJOs = - Sample code demonstrating different remoting features can be found= in - the examples directory. They can be compiled and run manually via your I= DE - or via an ant build file found in the examples directory. There are many - sets of sample code, each with their own package. Within most of these - packages, there will be a server and a client class that will need to be - executed + There are many ways in which to expose a remote interface to a j= ava + object. Some require a complex framework API based on a standard + specification and some require new technologies like annotations and A= OP. + Each of these have their own benefits. JBoss Remoting transporters pro= vide + the same behavior via a simple API without the need for any of the new= er + technologies. = -
- Simple invocation - - The simple invocation sample (found in the - org.jboss.remoting.samples.simple package), has two classes; SimpleCli= ent - and SimpleServer. It demonstrates making a simple invocation from a - remoting client to a remoting server. The SimpleClient class will crea= te - an InvokerLocator object from a simple url-like string that identifies= the - remoting server to call upon (which will be socket://localhost:5400 by - default). Then the SimpleClient will create a remoting Client class, - passing the newly created InvokerLocator. Next the Client will be call= ed - to make an invocation on the remoting server, passing the request payl= oad - object (which is a String with the value of "Do something"). The server - will return a response from this call which is printed to standard - output. - - Within the SimpleServer, a remoting server is created and starte= d. - This is done by first creating an InvokerLocator, just like was done in - the SimpleClient. Then constructing a Connector, passing the - InvokerLocator. Next, need to call create() on the Connector to initia= lize - all the resources, such as the remoting server invoker. Once created, = need - to create the invocation handler. The invocation handler is the class = that - the remoting server will pass client requests on to. The invocation - handler in this sample simply returns the simple String "This is the - return to SampleInvocationHandler invocation". Once created, the handl= er - is added to the Connector. Finally, the Connector is started and will - start listening for incoming client requests. - - To run this example, can compile both the SimpleClient and - SimpleServer class, then first run the SimpleServer and then the - SimpleClient. Or can go to the examples directory and run the ant targ= et - 'run-simple-server' and then in another console window run the ant tar= get - 'run-simple-client'. For example: - - ant run-simple-serverant - then: - - ant run-simple-clientThe output - when running the SimpleClient should look like: - - Calling remoting server with locator uri of: socket://= localhost:5400 -Invoking server with request of 'Do something' -Invocation response: This is the return to SampleInvocationHandler invocat= ion - - The output when running the SimpleServer should look like: - - Starting remoting server with locator uri of: socket:/= /localhost:5400 -Invocation request is: Do something -Returning response of: This is the return to SampleInvocationHandler invoc= ation - - Note: will have to manually shut down the SimpleServer once - started. -
- -
- HTTP invocation - - This http invocation sample (found in the - org.jboss.remoting.samples.http package), demonstrates how the http - invoker can be used for a variety of http based invocations. This time, - will start with the server side. The SimpleServer class is much like t= he - one from the previous simple invocation example, except that instead of - using the 'socket' transport, will be using the 'http' transport. Also, - instead of using the SampleInvocationHandler class as the handler, wil= l be - using the WebInvocationHandler (code shown below). - - public class WebInvocationHand= ler implements ServerInvocationHandler -{ - // Pre-defined returns to be sent back to client based on type of reque= st. - public static final String RESPONSE_VALUE =3D "This is the return to si= mple text based http invocation."; - public static final ComplexObject OBJECT_RESPONSE_VALUE =3D new Complex= Object(5, "dub", false); - public static final String HTML_PAGE_RESPONSE =3D "<html><head= ><title>Test HTML page</title></head><body>" + - "<h1>HTTP/Servlet= Test HTML page</h1><p>This is a simple page served for test." + - "<p>Should show u= p in browser or via invoker client</body></html>"; - - // Different request types that client may make - public static final String NULL_RETURN_PARAM =3D "return_null"; - public static final String OBJECT_RETURN_PARAM =3D "return_object"; - public static final String STRING_RETURN_PARAM =3D "return_string"; - - - /** - * called to handle a specific invocation - * - * @param invocation - * @return - * @throws Throwable - */ - public Object invoke(InvocationRequest invocati= on) throws Throwable - { - // Print out the invocation request - System.out.println("Invocation request from client is: " + invocatio= n.getParameter()); - if(NULL_RETURN_PARAM.equals(invocation.getParameter())) - { - return null; - } - else if(invocation.getParameter() instanceof ComplexObject) - { - return OBJECT_RESPONSE_VALUE; - } - else if(STRING_RETURN_PARAM.equals(invocation.getParameter())) - { - Map responseMetadata =3D invocation.getReturnPayload(); - responseMetadata.put(HTTPMetadataConstants.RESPONSE_CODE, new In= teger(207)); - responseMetadata.put(HTTPMetadataConstants.RESPONSE_CODE_MESSAGE,= "Custom response code and message from remoting server"); - // Just going to return static string as this is just simple exam= ple code. - return RESPONSE_VALUE; - } - else - { - return HTML_PAGE_RESPONSE; - } - } - - - The most interesting part of the WebInvocationHandler is its - invoke() method implementation. First it will check to see what the - request parameter was from the InvocationRequest and based on what the - value is, will return different responses. The first check is to see if - the client passed a request to return a null value. The second will ch= eck - to see if the request parameter from the client was of type ComplexObj= ect. - If so, return the pre-built ComplexObject that was created as a static - variable. - - After that, will check to see if the request parameter was for - returning a simple String. Notice in this block, will set the desired - response code and message to be returned to the client. In this case, = are - setting the response code to be returned to 207 and the response messa= ge - to "Custom response code and message from remoting server". These are - non-standard code and message, but can be anything desired. - - Last, if have not found a matching invocation request parameter, - will just return some simple html. - - Now onto the client side for making the calls to this handler, w= hich - can be found in SimpleClient (code shown below). - - public class SimpleClient -{ - // Default locator values - private static String transport =3D "http"; - private static String host =3D "localhost"; - private static int port =3D 5400; - - public void makeInvocation(String locatorURI) throws Throwable - { - // create InvokerLocator with the url type string - // indicating the target remoting server to call upon. - InvokerLocator locator =3D new InvokerLocator(locatorURI); - System.out.println("Calling remoting server with locator uri of: " += locatorURI); - - Client remotingClient =3D new Client(locator); - - // make invocation on remoting server and send complex data object - // by default, the remoting http client invoker will use method type= of POST, - // which is needed when ever sending objects to the server. So no m= etadata map needs - // to be passed to the invoke() method. - Object response =3D remotingClient.invoke(ne= w ComplexObject(2, "foo", true), null); - - System.out.println("\nResponse from remoting http server when making= http POST request and sending a complex data object:\n" + response); - - - Map metadata =3D new HashMap(); - // set the metadata so remoting client knows to use http GET method = type - metadata.put("TYPE", "GET"); - // not actually sending any data to the remoting server, just want t= o get its response - response =3D remotingClient.invoke((Object) = null, metadata); - - System.out.println("\nResponse from remoting http server when making= GET request:\n" + response); - - // now set type back to POST and send a plain text based request - metadata.put("TYPE", "POST"); - response =3D remotingClient.invoke(WebInvoca= tionHandler.STRING_RETURN_PARAM, metadata); - - System.out.println("\nResponse from remoting http server when making= http POST request and sending a text based request:\n" + response); - - // notice are getting custom response code and message set by web in= vocation handler - Integer responseCode =3D (Integer) metadata.= get(HTTPMetadataConstants.RESPONSE_CODE); - String responseMessage =3D (String) metadata.get(HTTPMetadataConstan= ts.RESPONSE_CODE_MESSAGE); - System.out.println("Response code from server: " + responseCode); - System.out.println("Response message from server: " + responseMessag= e); - - } - - - This SimpleClient, like the one before in the simple invocation - example, starts off by creating an InvokerLocator and remoting Client - instance, except is using http transport instead of socket. The first - invocation made is to send a newly constructed ComplexObject. If remem= ber - from the WebInvocationHandler above, will expect this invocation to re= turn - a different ComplexObject, which can be seen in the following system - output line. - - The next invocation to be made is a simple http GET request. To = do - this, must first let the remoting client know that the method type nee= ds - to be changed from the default, which is POST, to be GET. Then make the - invocation with a null payload (since not wanting to send any data, ju= st - get data in response) and the metadata map just populated with the GET - type. This invocation request will return a response of html. - - Then, will change back to being a POST type request and will pas= s a - simple String as the payload to the invocation request. This will retu= rn a - simple String as the response from the WebInvocationHandler. Afterward, - will see the specific response code and message printed to standard - output, as well as the exception itself. - - To run this example, can compile all the classes in the package, - then first run the SimpleServer and then the SimpleClient. Or can go to - the examples directory and run the ant target 'run-http-server' and th= en - in another console window run the ant target 'run-http-client'. For - example: - - ant run-http-server - - and then: - - ant run-http-client - - The output when running the SimpleClient should look like: - - Response from remoting http server when making http PO= ST request and sending a complex data object: -ComplexObject (i =3D 5, s =3D dub, b =3D false, bytes.length =3D 0) - -Response from remoting http server when making GET request: -<html><head><title>Test HTML page</title></head= ><body><h1>HTTP/Servlet Test HTML page</h1><p>Th= is is a simple page served for test.<p>Should show up in browser or v= ia invoker client</body></html> - -Response from remoting http server when making http POST request and sendi= ng a text based request: -This is the return to simple text based http invocation. -Response code from server: 207 -Response message from server: Custom response code and message from remoti= ng server - - Notice that the first response is the ComplexObject from the sta= tic - variable returned within WebInvocationHandler. The next response is ht= ml - and then simple text from the WebInvocationHandler. Can see the specif= ic - response code and message set in the WebInvocationHandler. - - The output from the SimpleServer should look like: - - Starting remoting server with locator uri of: http://l= ocalhost:5400 -Jan 26, 2006 11:39:53 PM org.apache.coyote.http11.Http11BaseProtocol init -INFO: Initializing Coyote HTTP/1.1 on http-127.0.0.1-5400 -Jan 26, 2006 11:39:53 PM org.apache.coyote.http11.Http11BaseProtocol start -INFO: Starting Coyote HTTP/1.1 on http-127.0.0.1-5400 -Invocation request from client is: ComplexObject (i =3D 2, s =3D foo, b = =3D true, bytes.length =3D 0) -Invocation request from client is: null -Invocation request from client is: return_string - - First the information for the http server invoker is written, wh= ich - includes the locator uri used to start the server and the output from - starting the Tomcat connector. Then will see the invocation parameter - passed for each client request. - - Since the SimpleServer should still be running, can open a web - browser and enter the locator uri, http://localhost:5400. This should - cause the browser to render the html returned from the - WebInvocationHandler. -
- -
- Oneway invocation - - The oneway invocation sample (found in the - org.jboss.remoting.samples.oneway package) is very similar to the simp= le - invocation example, except in this sample, the client will make - asynchronous invocations on the server. - - The OnewayClient class sets up the remoting client as in the sim= ple - invocation sample, but instead of using the invoke() method, it uses t= he - invokeOneway() method on the Client class. There are two basic modes w= hen - making a oneway invocation in remoting. The first is to have the calli= ng - thread to be the one that makes the actual call to the server. This al= lows - the caller to ensure that the invocation request at least made it to t= he - server. Once the server receives the invocation request, the call will - return (and the request will be processed by a separate worker thread = on - the server). The other mode, which is demonstrated in the second call = to - invokeOneway, allows for the calling thread to return immediately and a - worker thread on the client side will make the actual invocation on the - server. This is faster of the two modes, but if there is a problem mak= ing - the request on the server, the original caller will be unaware. - - The OnewayServer is exactly the same as the SimpleServer from the - previous example, with the exception that invocation handler returns n= ull - (since even if did return a response, would not be delivered to the - original caller). - - To run this example, can compile both the OnewayClient and - OnewayServer class, then run the OnewayServer and then the OnewayClien= t. - Or can go to the examples directory and run the ant target - 'run-oneway-server' and then in another console window run the ant tar= get - 'run-oneway-client'. For example: - - ant run-oneway-server - - and then: - - ant run-oneway-client - - The output when running the OnewayClient should look like: - - Calling remoting server with locator uri of: socket://= localhost:5400 -Making oneway invocation with payload of 'Oneway call 1.' -Making oneway invocation with payload of 'Oneway call 2.' - - The output when running the OnewayServer should look like: - - Starting remoting server with locator uri of: socket:/= /localhost:5400 -Invocation request is: Oneway call 1. -Invocation request is: Oneway call 2. - - Note: will have to manually shut down the OnewayServer once - started. - - Although this example only demonstrates making one way invocatio= ns, - could include this with callbacks (see further down) to have asynchron= ous - invocations with callbacks to verify was processed. -
- -
- Discovery and invocation - - The discovery sample (found in the - org.jboss.remoting.samples.detection package) is similar to the simple - invocation example in that it makes a simple invocation from the clien= t to - the server. However, in this example, instead of explicitly specifying= the - invoker locator to use for the target remoting server, it is discovered - dynamically during runtime. This example is composed of two classes; - SimpleDetectorClient and SimpleDetectorServer. - - The SimpleDetectorClient starts off by setting up the remoting - detector. Detection on the client side requires a few components; a JMX - MBeanServer, one or more Detectors, and a NetworkRegistry. The Detecto= rs - will listen for detection messages from remoting servers and then add = the - information for the detected servers to the NetworkRegistry. They use = JMX - to lookup and call on the NetworkRegistry. The NetworkRegistry uses JMX - Notifications to emit changes in network topology (remoting servers be= ing - added or removed). - - In this particular example, the SimpleDetectorClient is register= ed - with the NetworkRegistry as a notification listener. When it receives - notifications from the NetworkRegistry (via the handleNotification() - method), it will check to see if the notification is for adding or - removing a remoting server. If it is for adding a remoting server, the - SimpleDetectorClient will get the array of InvokerLocators from the - NetworkNotification and make a remote call for each. If the notificati= on - is for removing a remoting server, the SimpleDetectorClient will simply - print out a message saying which server has been removed. - - The biggest change between the SimpleDetectorServer and the - SimpleServer from the first sample is that have added a method, - setupDetector(), to create and start a remoting Detector. On the server - side, only two components are needed for detection; the Detector and a= JMX - MBeanServer. As for the setup of the Connector, it is exactly the same= as - before. Notice that even though we have added a Detector on the server - side, the Connector is not directly aware of either Detector or the - MBeanServer, so no code changes for the Connector setup is - required. - - To run this example, can compile both the SimpleDetectorClient a= nd - SimpleDetectorServer class, then run the SimpleDetectorServer and then= the - SimpleDetectorClient. Or can go to the examples directory and run the = ant - target 'run-detector-server' and then in another window run the ant ta= rget - 'run-detector-client'. For example: - - ant run-detector-server - - and then: - - ant run-detector-client - - The initial output when running the SimpleDetectorClient should = look - like: - - ri Jan 13 09:36:50 EST 2006: [CLIENT]: Starting JBoss/= Remoting client... to stop this client, kill it manually via Control-C -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: NetworkRegistry has been created -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: NetworkRegistry has added the clie= nt as a listener -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: MulticastDetector has been created= and is listening for new NetworkRegistries to come online -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: GOT A NETWORK-REGISTRY NOTIFICATIO= N: jboss.network.server.added -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: New server(s) have been detected -= getting locators and sending welcome messages -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: Sending welcome message to remotin= g server with locator uri of: socket://127.0.0.1:5400/ -Fri Jan 13 09:36:50 EST 2006: [CLIENT]: The newly discovered server sent t= his response to our welcome message: Received your welcome message. Thank = you! - - The output when running the SimpleDetectorServer should look - like: - - Fri Jan 13 09:36:46 EST 2006: [SERVER]: Starting JBoss= /Remoting server... to stop this server, kill it manually via Control-C -Fri Jan 13 09:36:46 EST 2006: [SERVER]: This server's endpoint will be: so= cket://localhost:5400 -Fri Jan 13 09:36:46 EST 2006: [SERVER]: MulticastDetector has been created= and is listening for new NetworkRegistries to come online -Fri Jan 13 09:36:46 EST 2006: [SERVER]: Starting remoting server with loca= tor uri of: socket://localhost:5400 -Fri Jan 13 09:36:46 EST 2006: [SERVER]: Added our invocation handler; we a= re now ready to begin accepting messages from clients -Fri Jan 13 09:36:50 EST 2006: [SERVER]: RECEIVED A CLIENT MESSAGE: Welcome= Aboard! -Fri Jan 13 09:36:50 EST 2006: [SERVER]: Returning the following message ba= ck to the client: Received your welcome message. Thank you! - - At this point, try stopping the SimpleDetectorServer (notice that - the SimpleDetectorClient should still be running). After a few seconds, - the client detector should detect that the server is no longer availab= le - and will see something like the following appended in the - SimpleDetectorClient console window: - - Fri Jan 13 09:37:04 EST 2006: [CLIENT]: GOT A NETWORK-= REGISTRY NOTIFICATION: jboss.network.server.removed -Fri Jan 13 09:37:04 EST 2006: [CLIENT]: It has been detected that a server= has gone down with a locator of: InvokerLocator [socket://127.0.0.1:5400/]= -
- -
- Callbacks - - The callback sample (found in the - org.jboss.remoting.samples.callback package) illustrates how to perform - callbacks from a remoting server to a remoting client. This example is - composed of two classes; CallbackClient and CallbackServer. - - Within remoting, there are two approaches in which a callback ca= n be - received. The first is to actively ask for callback messages from the - remoting server, which is called a pull callback (since are pulling the - callbacks from the server). The second is to have the server send the - callbacks to the client as they are generated, which is called a push - callback. This sample demonstrates how to do both pull and push - callbacks. - - Looking at the CallbackClient class, will see that the first thi= ng - done is to create a remoting Client, which is done in the same manner = as - previous examples. Next, we'll perform a pull callback, which requires= the - creation of a CallbackHandler. The CallbackHandler, which implements t= he - InvokerCallbackHandler interface, is what is called upon with a Callba= ck - object when a callback is received. The Callback object contains - information such as the callback message (in Object form), the server - locator from where the callback originally came from, and a handle obj= ect - which can help to identify callback context (similar to the handle obj= ect - within a JMX Notification). Once created, the CallbackHandler is then - registered as a listener within the Client. This will cause the client= to - make a call to the server to notify the server it has a callback liste= ner - (more on this below in the server section). Although the CallbackHandl= er - is not called upon directly when doing pull callbacks, it is needed as= an - identifier for the callbacks. - - Then the client will wait a few seconds, make a simple invocatio= n on - the server, and then call on the remoting Client instance to get any - callbacks that may be available for our CallbackHandler. This will ret= urn - a list of callbacks, if any exist. The list will be iterated and each - callback will be printed to standard output. Finally, the callback han= dler - will be removed as a listener from the remoting Client (which in turns - removes it from the remoting server). - - After performing a pull callback, will perform a push callback. = This - is a little more involved as requires creating a callback server to wh= ich - the remoting target server can callback on when it generates a callback - message. To do this, will need to create a remoting Connector, just as - have seen in previous examples. For this particular example, we use the - same locator url as our target remoting server, but increment the port= to - listen on by one. Will also notice that use the SampleInvocationHandler - hander from the CallbackServer (more in this in a minute). After creat= ing - our callback server, a CallbackHandler and callback handle object is - created. Next, remoting Client is called to add our callback listener. - Here we pass not only the CallbackHandler, but the InvokerLocator for = the - callback server (so the target server will know where to deliver callb= ack - messages to), and the callback handle object (which will be included in - all the callback messages delivered for this particular callback - listener). - - Then the client will wait a few seconds, to allow the target ser= ver - time to generate and deliver callback messages. After that, we remove = the - callback listener and clean up our callback server. - - The CallbackServer is pretty much the same as the previous sampl= es - in setting up the remoting server, via the Connector. The biggest chan= ge - resides in the ServerInvocationHandler implementation, - SampleInvocationHandler (which is an inner class to CallbackServer). T= he - first thing to notice is now have a variable called listeners, which i= s a - List to hold any callback listeners that get registered. Also, in the - constructor of the SampleInvocationHandler, we set up a new thread to = run - in the background. This thread, executing the run() method in - SampleInvocationHandler, will continually loop looking to see if the - shouldGenerateCallbacks has been set. If it has been, will create a - Callback object and loop through its list of listeners and tell each - listener to handle the newly created callback. Have also added - implementation to the addListener() and removeListener() methods where - will either add or remove specified callback listener from the internal - callback listener list and set the shouldGenerateCallbacks flag - accordingly. The invoke() method remains the same as in previous - samples. - - To run this example, can compile both the CallbackClient and - CallbackServer class, then run the CallbackServer and then the - CallbackClient. Or can go to the examples directory and run the ant ta= rget - 'run-callback-server' and then in another window run the ant target - 'run-callback-client. For example: - - ant run-callback-server - - and then: - - ant run-callback-client - - The output in the CallbackClient console window should look - like: - - Calling remoting server with locator uri of: socket://= localhost:5400 -Invocation response: This is the return to SampleInvocationHandler invocat= ion -Pull Callback value =3D Callback 1: This is the payload of callback invoca= tion. -Pull Callback value =3D Callback 2: This is the payload of callback invoca= tion. -Starting remoting server with locator uri of: InvokerLocator [socket://127= .0.0.1:5401/] -Received push callback. -Received callback value of: Callback 3: This is the payload of callback in= vocation. -Received callback handle object of: myCallbackHandleObject -Received callback server invoker of: InvokerLocator [socket://127.0.0.1:54= 00/] -Received push callback. -Received callback value of: Callback 4: This is the payload of callback in= vocation. -Received callback handle object of: myCallbackHandleObject -Received callback server invoker of: InvokerLocator [socket://127.0.0.1:54= 00/] - - This output shows that client first pulled two callbacks generat= ed - from the server. Then, after creating and registering our second callb= ack - handler and a callback server, two callbacks were received from the ta= rget - server. - - The output in the CallbackServer console window should look - like: - - Starting remoting server with locator uri of: socket:/= /localhost:5400 -Adding callback listener. -Invocation request is: Do something -Removing callback listener. -Adding callback listener. -Removing callback listener. - - This output shows two distinct callback handlers being added and - removed (with an invocation request being received after the first was - added). - - There are a few important points to mention about this example. - First, notice that in the client, the same callback handle object in t= he - push callbacks was received as was registered with the callback listen= er. - However, there was no special code required to facilitate this within = the - SampleInvocationHandler. This is handled within remoting automatically. - Also notice when the callback server was created within the client, no - special coding was required to register the callback handler with it, = both - were simply passed to the remoting Client instance when registering the - callback listener and was handled internally. -
- -
- Streaming - - The streaning sample (found in the org.jboss.remoting.samples.st= ream - package) illustrates how a java.io.InputStream can be sent from a clie= nt - and read on demand from a server. This example is composed of two clas= ses: - StreamingClient and StreamingServer. - - Unlike the previous examples that sent plain old java objects as= the - payload, this example will be sending a java.io.FileInputStream as the - payload to the server. This is a special case because streams can not = be - serialized. One approach to this might be to write out the contents of= a - stream to a byte buffer and send the whole data content to the server. - However, this approach can be dangerous because if the data content of= the - stream is large, such as an 800MB file, would run the risk of causing = an - out of memory error (since are loading all 800MB into memory). Another - approach, which is used by JBossRemoting, is to create a proxy to the - original stream. This proxy can then be called upon for reading, same = as - the original stream. When this happens, the proxy will call back the - original stream for the requested data. - - Looking at the StreamingClient, the remoting Client is created a= s in - previous samples. Next, will create a java.io.FileInputStream to the - sample.txt file on disk (which is in the same directory as the test - classes). Finally, will call the remoting Client to do its invocation, - passing the new FileInputStream and the name of the file. The second - parameter could be of any Object type and is meant to supply some - meaningful context to the server in regards to the stream being passed, - such as the file name to use when writing to disk on the server side. = The - response from the server, in this example, is the size of the file it - wrote to disk. - - The StreamingServer sets up the remoting server as was done in - previous examples. However, instead of using an implementation of the - ServerInvocationHandler class as the server handler, an implementation= of - the StreamInvocationHandler (which extends the ServerInvocationHandler= ) is - used. The StreamInvocationHandler includes an extra method called - handleStream() especially for processing requests with a stream as the - payload. In this example, the class implementing the - StreamInvocationHandler is the TestStreamInvocationHandler class, whic= h is - an inner class to the StreamingServer. The handleStream() method within - the TestStreamInvocationHandler will use the stream passed to it to wr= ite - out its contents to a file on disk, as specified by the second paramet= er - passed to the handleStream() method. Upon writing out the file to disk, - the handleStream() method will return to the client caller the size of= the - file. - - To run this example, can compile both the StreamingClient and - StreamingServer class, then run the StreamingServer and then the - StreamingClient. Or can go to the examples directory and run the ant - target 'run-stream-server' and then in another window run the ant targ= et - 'run-stream-client'. For example: - - ant run-stream-server - - and then: - - ant run-stream-client - - The output in the StreamingClient console window should look - like: - - Calling on remoting server with locator uri of: socket= ://localhost:5400 -Sending input stream for file sample.txt to server. -Size of file sample.txt is 987 -Server returned 987 as the size of the file read. - - The output in the StreamingServer console window should look - like: - - Starting remoting server with locator uri of: socket:/= /localhost:5400 -Received input stream from client to write out to file server_sample.txt -Read stream of size 987. Now writing to server_sample.txt -New file server_sample.txt has been written out to C:\tmp\JBossRemoting_1_= 4_0_final\examples\server_sample.txt - - After running this example, there should be a newly created - server_sample.txt file in the root examples directory. The contents of= the - file should look exactly like the contents of the sample.txt file loca= ted - in the examples\org\jboss\remoting\samples\stream directory. -
- -
- JBoss Serialization - - The serialization sample (found in the - org.jboss.remoting.samples.serialization package) illustrates how JBoss - Serialization can be used in place of the standard java serialization = to - allow for sending of invocation payload objects that do not implement = the - java.io.Serializable interface. This example is composed of three clas= ses: - SerializationClient, SerializationServer, and - NonSerializablePayload. - - This example is exactly like the one from the simple example with - two differences. The first difference is the use of JBoss Serializatio= n to - convert object instances to binary data format for wire transfer. This= is - accomplished by adding an extra parameter (serializationtype) to the - locator url with a value of 'jboss'. Is important to note that use of - JBoss Serialization requires JDK 1.5, so this example will need to be = run - using JDK 1.5. The second difference is instead of sending and receivi= ng a - simple String type for the remote invocation payload, will be sending = and - receiving an instance of the NonSerializablePayload class. - - There are a few important points to notice with the - NonSerializablePayload class. The first is that it does NOT implement = the - java.io.Serializable interface. The second is that it has a void param= eter - constructor. This is a requirement of JBoss Serialization for object - instances that do not implement the Serializable interface. However, t= his - void parameter constructor can be private, as in the case of - NonSerializablePayload, as to not change the external API of the - class. - - To run this example, can compile both the SerializationClient and - SerializationServer class, then run the SerializationServer and then t= he - SerializationClient. Or can go to the examples directory and run the a= nt - target 'run-serialization-server' and then in another window run the a= nt - target 'run-serialization-client'. For example: - - ant run-serialization-server - - and then: - - ant run-serialization-client - - The output in the SerializationClient console window should look - like: - - Calling remoting server with locator uri of: socket://= localhost:5400/?serializationtype=3Djboss -Invoking server with request of 'NonSerializablePayload - name: foo, id: 1' -Invocation response: NonSerializablePayload - name: bar, id: 2 - - The output in the SerializationServer console window should look - like: - - Starting remoting server with locator uri of: socket:/= /localhost:5400/?serializationtype=3Djboss -Invocation request is: NonSerializablePayload - name: foo, id: 1 -Returning response of: NonSerializablePayload - name: bar, id: 2 - - Note: will have to manually shut down the SerializationServer on= ce - started. -
- -
- Transporters - -
- Transporters - beaming POJOs - - There are many ways in which to expose a remote interface to a - java object. Some require a complex framework API based on a standard - specification and some require new technologies like annotations and - AOP. Each of these have their own benefits. JBoss Remoting transport= ers - provide the same behavior via a simple API without the need for any = of - the newer technologies. - - When boiled down, transporters take a plain old java object (P= OJO) - and expose a remote proxy to it via JBoss Remoting. Dynamic proxies = and - reflection are used to make the typed method calls on that target PO= JO. - Since JBoss Remoting is used, can select from a number of different - network transports (i.e. rmi, http, socket, multiplex, etc.), includ= ing - support for SSL. Even clustering features can be included. - - How it works - - In this section will discuss how remoting transporters can be - used, some requirments for usage, and a little detail on the - implementation. For greater breath on usage, please review the - transporter samples as most use cases are covered there. - - To start, will need to have a plain old java object that - implements one or more interfaces that want to expose for remote met= hod - invocation. Then will need to create a - org.jboss.remoting.transporter.TransporterServer to wrap - around it, so that can be exposed remotely. This can be done in one = of - two basic ways. The first is to use a static - createTransporterServer() method of the TransporterServ= er - class. There are many of these create methods, but all basically do = that - same thing in that they take a remoting locator and target pojo and = will - return a TransporterServer instance that has been started and ready = to - receive remote invocations (see javadoc for TransporterServer for all - the different static createTransporterServer() methods). The other w= ay - to create a TransporterServer for the target pojo is to construct an - instance of it. This provides a little more flexibility as are able = to - control more aspects of the TransporterServer, such as when it will = be - started. - - When a TransporterServer is created, it will create a remoting - Connector using the locator provided. It will generate a server - invocation handler that wraps the target pojo provided and use - reflection to make the calls on it based on the invocations it recei= ves - from clients. By default, the subsystem underwhich the server invoca= tion - handler is registered is the interface class name for which the targ= et - pojo is exposing. If the target implements multiple interfaces, and a - specific one to use is not specified, all the interfaces will be - registered as subsystems for the same server invocation handler. - Whenever no long want the target pojo to receive remote method - invocations, will need to call the stop() method on the - TransporterServer for the target pojo (this is very important, as - otherwise will never be released from memory and will continue to - consume network and memory resources). - - On the client side, in order to be able to call on the target = pojo - remotely, will need to use the - org.jboss.remoting.transporter.TransporterClient. Unlike - the TransporterServer, can only use the static create methods of the - TransporterClient (this is because the return to the static create - method is a typed dynamic proxy). The static method to call on the - TransportClient is createTransporterClient(), where will - pass the locator to find the target pojo (same as one used when crea= ting - the TransporterServer) and the interface for the target pojo that wa= nt - to make remote method invocations on. The return from this create ca= ll - will be a dynamic proxy which you can cast to to same interface type - supplied. At that point, can make typed method invocations on the - returned object, which will then make the remote invocations under t= he - covers. Note that can have multiple transporter clients to the same - target pojo, each using different interface types for making - calls. - - When no longer need to make invocations on the target pojo, the - resources associated with the remoting client will need to be cleaned - up. This is done by calling the destroyTransporterClient() - method of the TransporterClient. This is important to remember to do= , as - will otherwise leave network resources active even though not in - use. - - One of the features of using remoting transporters is location - transparency. By this mean that client proxies returned by the - TransporterClient can be passed over the network. For example, can h= ave - a target pojo that returns from a method call a client proxy (that it - created using the TransporterClient) in which the client can call on - directly as well. See the transporter proxy sample code to see how t= his - can be done. - - Another nice feature when using transporters is the ability to - cluster. To be more specific, can create multiple target pojos using= the - TransporterServer in clustered mode and then use the TransporterClie= nt - in clustered mode to create a client proxy that will discover the - location of the target pojos are wanting to call on. Will also provi= de - automatic, seemless failover of remote method invocations in the case - that a particular target pojo instance fails. However, note that only - provide invocation failover and does not take into account state - transfer between target pojos (would need addition of JBoss Cache or - some other state synchronization tool). -
- - The transporter sample spans several examples showing different = ways - to use the transporter. Each specific example is within its own package - under the org.jboss.remoting.samples.transporter package. Since each of - the transporter examples includes common objects, as well as client and - server classes, the common objects will be found under the main - transporter sub-package and the client and server classes in their - respective sub-packages (named client and server). - -
- Transporters sample - simple - - The simple transporter example (found in - org.jboss.remoting.samples.transporter.simple package) demonstrates a - very simple example of how to use the transporters to expose a plain= old - java object for remote method invocations. - - In this simple transporter example, will be taking a class that - formats a java.util.Date into a simple String representation and - exposing it so can call on the remotely. The target object in this c= ase, - org.jboss.remoting.samples.transporter.simple.DateProcessorImpl, - implements the - org.jboss.remoting.samples.transporter.simple.DateProcessor interfac= es - (as shown below): - - public interface DateProcessor -{ - public String formatDate(Date dateToConvert); -} - - -public class DateProcessorImpl implements DateProcessor -{ - public String formatDate(Date dateToConvert) - { - DateFormat dateFormat =3D DateFormat.getDateInstance(DateFormat.MEDI= UM); - return dateFormat.format(dateToConvert); - } -} - - This is then exposed using the TransporterServer by the - org.jboss.remoting.samples.transporter.simple.Server class. - - public class Server -{ - public static void main(String[] args) throws Exception - { - TransporterServer server =3D TransporterServer.createTransporterServ= er("socket://localhost:5400", new DateProcessorImpl(), DateProcessor.class.= getName()); - Thread.sleep(10000); - server.stop(); - } -} - - The Server class simply creates a TransporterServer by indicat= ing - the locator url would like to use for the remoting server, a newly - created instance of DataProcessorImpl, and the interface type would = like - to expose remotely. The TransporterServer returned from the - createTransporterServer call is live and ready to receive incoming - method invocation requests. Will then wait 10 seconds for a request, - then stop the server. - - Next need to have client to make the remote invocation. This c= an - be found within - org.jboss.remoting.samples.transporter.simple.Client. - - public class Client -{ - public static void main(String[] args) throws Exception - { - DateProcessor dateProcessor =3D (DateProcessor) TransporterClient.cr= eateTransporterClient("socket://localhost:5400", DateProcessor.class); - String formattedDate =3D dateProcessor.formatDate(new Date()); - System.out.println("Current date: " + formattedDate); - } -} - - In the Client class, create a TransporterClient which can be c= ast - to the desired type, which is DataProcessor in this case. In calling= the - createTransporterClient, need to specify the locator ulr (same as was - used for the TransporterServer), and the interface type will be call= ing - on for the target pojo. Once have the DateProcessor variable, will m= ake - the call to formatDate() and pass a newly created Date object. The - return will be a formated String of the date passed. - - To run this example, can run the Server and then the Client. Or - can go to the examples directory and run the ant target - 'run-transporter-simple-server' and then in another window run the a= nt - target 'run-transporter-simple-client'. For example: - - ant run-transporter-simple-server - - and then: - - ant run-transporter-simple-client - - The output from the client window should look similar to: - - Current date: Jul 31, 2006 -
- -
- Transporter sample - basic - - The basic transporter example (found in - org.jboss.remoting.samples.transporter.basic package) illustrates ho= w to - build a simple transporter for making remote invocations on plain old - java objects. - - In this basic transporter example, will be using a few domain - objects; Customer and Address, which are just data - objects. - - public class Customer implements Serializable -{ - private String firstName =3D null; - private String lastName =3D null; - private Address addr =3D null; - private int customerId =3D -1; - - public String getFirstName() - { - return firstName; - } - - public void setFirstName(String firstName) - { - this.firstName =3D firstName; - } - - public String getLastName() - { - return lastName; - } - - public void setLastName(String lastName) - { - this.lastName =3D lastName; - } - - public Address getAddr() - { - return addr; - } - - public void setAddr(Address addr) - { - this.addr =3D addr; - } - - public int getCustomerId() - { - return customerId; - } - - public void setCustomerId(int customerId) - { - this.customerId =3D customerId; - } - - public String toString() - { - StringBuffer buffer =3D new StringBuffer(); - buffer.append("\nCustomer:\n"); - buffer.append("customer id: " + customerId + "\n"); - buffer.append("first name: " + firstName + "\n"); - buffer.append("last name: " + lastName + "\n"); - buffer.append("street: " + addr.getStreet() + "\n"); - buffer.append("city: " + addr.getCity() + "\n"); - buffer.append("state: " + addr.getState() + "\n"); - buffer.append("zip: " + addr.getZip() + "\n"); - - return buffer.toString(); - } -} - - public class Address implements Serializable -{ - private String street =3D null; - private String city =3D null; - private String state =3D null; - private int zip =3D -1; - - public String getStreet() - { - return street; - } - - public void setStreet(String street) - { - this.street =3D street; - } - - public String getCity() - { - return city; - } - - public void setCity(String city) - { - this.city =3D city; - } - - public String getState() - { - return state; - } - - public void setState(String state) - { - this.state =3D state; - } - - public int getZip() - { - return zip; - } - - public void setZip(int zip) - { - this.zip =3D zip; - } -} - - Next comes the POJO that we want to expose a remote proxy for, - which is CustomerProcessorImpl class. This implementati= on - has one method to process a Customer object. It also - implements the CustomerProcessor interface. - - public class CustomerProcess= orImpl implements CustomerProcessor -{ - /** - * Takes the customer passed, and if not null and customer id - * is less than 0, will create a new random id and set it. - * The customer object returned will be the modified customer - * object passed. - * - * @param customer - * @return - */ - public Customer processCustomer(Customer customer) - { - if(customer !=3D null && customer.getCustomerId() < 0) - { - customer.setCustomerId(new Random().nextInt(1000)); - } - System.out.println("processed customer with new id of " + customer.g= etCustomerId()); - return customer; - } -} - - public interface CustomerPro= cessor -{ - /** - * Process a customer object. Implementors - * should ensure that the customer object - * passed as parameter should have its internal - * state changed somehow and returned. - * - * @param customer - * @return - */ - public Customer processCustomer(Customer customer); -} - - So far, nothing special, just plain old java objects. Next nee= d to - create the server component that will listen for remote request to - invoke on the target POJO. This is where the transporter comes - in. - - public class Server -{ - private String locatorURI =3D "socket://localhost:5400"; - private TransporterServer server =3D null; - - public void start() throws Exception - { - server =3D TransporterServer.createTransport= erServer(locatorURI, new CustomerProcessorImpl()); - } - - public void stop() - { - if(server !=3D null) - { - server.stop(); - } - } - - public static void main(String[] args) - { - Server server =3D new Server(); - try - { - server.start(); - - Thread.currentThread().sleep(60000); - - } - catch(Exception e) - { - e.printStackTrace(); - } - finally - { - server.stop(); - } - } -} - - The Server class is a pretty simple one. It calls= the - TransporterServer factory method to create the server - component for the CustomerProcessorImpl instance using = the - specified remoting locator information. - - The TransporterServer returned from the - createTransporterServer() call will be a running instan= ce - of a remoting server using the socket transport t= hat - is bound to localhost and listening for remote - requests on port 5400. The requests that come in = will - be forwarded to the remoting handler which will convert them into di= rect - method calls on the target POJO, CustomerProcessorImpl = in - this case, using reflection. - - The TransporterServer has a start() = and - stop() method exposed to control when to start and stop= the - running of the remoting server. The start() method is - called automatically within the createTransporterServer() - method, so is ready to receive requests upon the return of this meth= od. - The stop() method, however, needs to be called explicit= ly - when no longer wish to receive remote calls on the target POJO. - - Next up is the client side. This is represented by the - Client class. - - public class Client -{ - private String locatorURI =3D "socket://localhost:5400"; - - public void makeClientCall() throws Exception - { - Customer customer =3D createCustomer(); - - CustomerProcessor customerProcessor =3D (Cus= tomerProcessor) TransporterClient.createTransporterClient(locatorURI, Custo= merProcessor.class); - - System.out.println("Customer to be processed: " + customer); - Customer processedCustomer =3D customerProce= ssor.processCustomer(customer); - System.out.println("Customer is now: " + processedCustomer); - - TransporterClient.destroyTransporterClient(c= ustomerProcessor); - } - - private Customer createCustomer() - { - Customer cust =3D new Customer(); - cust.setFirstName("Bob"); - cust.setLastName("Smith"); - Address addr =3D 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 =3D new Client(); - try - { - client.makeClientCall(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } -} - - The Client class is also pretty simple. It create= s a - new Customer object instance, creates the remote proxy = to - the CustomerProcessor, and then calls on the - CustomerProcessor to process its new Customer - instance. - - To get the remote proxy for the CustomerProcessor, - all that is required is to call the TransporterClient's - method createTransporterClient() method and pass the - locator uri and the type of the remote proxy (and explicitly cast the - return to that type). This will create a dynamic proxy for the speci= fied - type, CustomerProcessor in this case, which is backed b= y a - remoting client which in turn makes the calls to the remote POJO's - remoting server. Once the call to createTransportClient() - has returned, the remoting client has already made its connection to= the - remoting server and is ready to make calls (will throw an exception = if - it could not connect to the specified remoting server). - - When finished making calls on the remote POJO proxy, will need= to - explicitly destroy the client by calling - destroyTransporterClient() and pass the remote proxy - instance. This allows the remoting client to disconnect from the POJ= O's - remoting server and clean up any network resources previously - used. - - To run this example, can run the Server and then the Client. Or - can go to the examples directory and run the ant target - 'run-transporter-basic-server' and then in another window run the ant - target 'run-transporter-basic-client'. For example: - - ant run-transporter-basic-server - - and then: - - ant run-transporter-basic-client - - The output from the Client console should be similar to: - - Customer to be processed: -Customer: -customer id: -1 -first name: Bob -last name: Smith -street: 101 Oak Street -city: Atlanata -state: GA -zip: 30249 - -Customer is now: -Customer: -customer id: 204 -first name: Bob -last name: Smith -street: 101 Oak Street -city: Atlanata -state: GA -zip: 30249 - - - - and the output from the Server class should be similar to: - - processed customer with new id of 204 - - The output shows that the Customer instance creat= ed - on the client was sent to the server where it was processed (by sett= ing - the customer id to 204) and returned to the client (and printed out - showing that the customer id was set to 204). -
- -
- Transporter sample - JBoss serialization - - The transporter serialization example (found in - org.jboss.remoting.samples.transporter.serialization package) is very - similar to the previous basic example, except in this one, the domain - objects being sent over the wire will NOT be Serializable. This is - accomplished via the use of JBoss Serialization. This can be useful = when - don't know which domain objects you may be using in remote calls or = if - adding ability for remote calls on legacy code. - - To start, there are a few more domain objects: Order, - OrderProcessor, and OrderProcessorImpl. Th= ese - will use some of the domain objects from the previous example as wel= l, - such as Customer. - - public class Order -{ - private int orderId =3D -1; - private boolean isProcessed =3D false; - private Customer customer =3D null; - private List items =3D null; - - - public int getOrderId() - { - return orderId; - } - - public void setOrderId(int orderId) - { - this.orderId =3D orderId; - } - - public boolean isProcessed() - { - return isProcessed; - } - - public void setProcessed(boolean processed) - { - isProcessed =3D processed; - } - - public Customer getCustomer() - { - return customer; - } - - public void setCustomer(Customer customer) - { - this.customer =3D customer; - } - - public List getItems() - { - return items; - } - - public void setItems(List items) - { - this.items =3D items; - } - - public String toString() - { - StringBuffer buffer =3D new StringBuffer(); - buffer.append("\nOrder:\n"); - buffer.append("\nIs processed: " + isProcessed); - buffer.append("\nOrder id: " + orderId); - buffer.append(customer.toString()); - - buffer.append("\nItems ordered:"); - Iterator itr =3D items.iterator(); - while(itr.hasNext()) - { - buffer.append("\n" + itr.next().toString()); - } - - return buffer.toString(); - } -} - - public class OrderProcessorI= mpl implements OrderProcessor -{ - private CustomerProcessor customerProcessor =3D null; - - public OrderProcessorImpl() - { - customerProcessor =3D new CustomerProcessorImpl(); - } - - public Order processOrder(Order order) - { - System.out.println("Incoming order to process from customer.\n" + or= der.getCustomer()); - - // has this customer been processed? - if(order.getCustomer().getCustomerId() < 0) - { - order.setCustomer(customerProcessor.processCustomer(order.getCust= omer())); - } - - List items =3D order.getItems(); - System.out.println("Items ordered:"); - Iterator itr =3D items.iterator(); - while(itr.hasNext()) - { - System.out.println(itr.next()); - } - - order.setOrderId(new Random().nextInt(1000)); - order.setProcessed(true); - - System.out.println("Order processed. Order id now: " + order.getOrd= erId()); - return order; - } -} - - public interface OrderProcessor -{ - public Order processOrder(Order order); -} - - The OrderProcessorImpl will take orders, via the - processOrder() method, check that the customer for the - order has been processed, and if not have the customer processor pro= cess - the new customer. Then will place the order, which means will just s= et - the order id and processed attribute to true. - - The most important point to this example is that the - Order class does NOT implement - java.io.Serializable. - - Now onto the Server class. This is just like the - previous Server class in the basic example with one main - difference: the locatorURI value. - - public class Server -{ - private String locatorURI =3D "socket://localhost:5400/?serializationtype=3Djboss"; - private TransporterServer server =3D null; - - public void start() throws Exception - { - server =3D TransporterServer.createTransporterServer(locatorURI, new= OrderProcessorImpl()); - } - - public void stop() - { - if(server !=3D null) - { - server.stop(); - } - } - - public static void main(String[] args) - { - Server server =3D new Server(); - try - { - server.start(); - - Thread.currentThread().sleep(60000); - - } - catch(Exception e) - { - e.printStackTrace(); - } - finally - { - server.stop(); - } - } -} - - The addition of serializationtype=3Djboss t= ells - the remoting framework to use JBoss Serialization in place of the - standard java serialization. - - On the client side, there is the Client class, ju= st - as in the previous basic example. - - public class Client -{ - private String locatorURI =3D "socket://localhost:5400/?serializationtype=3Djboss"; - - public void makeClientCall() throws Exception - { - Order order =3D createOrder(); - - OrderProcessor orderProcessor =3D (OrderProcessor) TransporterClient= .createTransporterClient(locatorURI, OrderProcessor.class); - - System.out.println("Order to be processed: " + order); - Order changedOrder =3D orderProcessor.processOrder(order); - System.out.println("Order now processed " + changedOrder); - - TransporterClient.destroyTransporterClient(orderProcessor); - - } - - private Order createOrder() - { - Order order =3D new Order(); - Customer customer =3D createCustomer(); - order.setCustomer(customer); - - List items =3D new ArrayList(); - items.add("Xbox 360"); - items.add("Wireless controller"); - items.add("Ghost Recon 3"); - - order.setItems(items); - - return order; - } - - private Customer createCustomer() - { - Customer cust =3D new Customer(); - cust.setFirstName("Bob"); - cust.setLastName("Smith"); - Address addr =3D 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 =3D new Client(); - try - { - client.makeClientCall(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } -} - - Again, the biggest difference to note is that have added - serializationtype=3Djboss to the locator uri. - - Note: Running this example requires JDK 1.5. - - To run this example, can run the Server and then the Client. Or - can go to the examples directory and run the ant target 'ant - run-transporter-serialization-server' and then in another window run= the - ant target 'ant run-transporter-serialization-client'. For - example: - - ant run-transporter-serialization-server - - and then: - - ant run-transporter-serialization-client - - When the server and client are run the output for the - Client class is: - - Order to be processed: -Order: - -Is processed: false -Order id: -1 -Customer: -customer id: -1 -first name: Bob -last name: Smith -street: 101 Oak Street -city: Atlanata -state: GA -zip: 30249 - -Items ordered: -Xbox 360 -Wireless controller -Ghost Recon 3 -Order now processed -Order: - -Is processed: true -Order id: 221 -Customer: -customer id: 861 -first name: Bob -last name: Smith -street: 101 Oak Street -city: Atlanata -state: GA -zip: 30249 - -Items ordered: -Xbox 360 -Wireless controller -Ghost Recon 3 - - - The client output shows the printout of the newly created order - before calling the OrderProcessor and then the processed - order afterwards. Noticed that the processed order has its customer'= s id - set, its order id set and the processed attribute is set to true. - - And the output from the Server is: - - Incoming order to process from customer. - -Customer: -customer id: -1 -first name: Bob -last name: Smith -street: 101 Oak Street -city: Atlanata -state: GA -zip: 30249 - -processed customer with new id of 861 -Items ordered: -Xbox 360 -Wireless controller -Ghost Recon 3 -Order processed. Order id now: 221 - - - The server output shows the printout of the customer before be= ing - processed and then the order while being processed. -
- -
- Transporter sample - clustered - - In the previous examples, there has been one and only one targ= et - 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 =3D "socket://localhost:5400"; - private TransporterServer server =3D null; - - public void start() throws Exception - { - server =3D TransporterServer.createTransport= erServer(getLocatorURI(), new CustomerProcessorImpl(), - CustomerProcessor= .class.getName(), true); - } - - protected String getLocatorURI() - { - return locatorURI; - } - - public void stop() - { - if(server !=3D null) - { - server.stop(); - } - } - - public static void main(String[] args) - { - SocketServer server =3D 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) a= nd - that want clustering turned on (via the last true - parameter). - - The interface type of the target POJO is needed because this w= ill - be used as the subsystem within the remoting server for the target P= OJO. - 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 Remoti= ng - for automatic discovery when in clustered mode. The actual detecti= on - of remote servers that come online can take up to a few seconds on= ce - 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. T= he - RMIServer class extends the SocketServer c= lass - and uses a different locator uri to specify rmi a= s the - transport protocol and a different port - (5500). - - public class RMIServer extends SocketServer -{ - private String localLocatorURI =3D "rmi://local= host:5500"; - - protected String getLocatorURI() - { - return localLocatorURI; - } - - public static void main(String[] args) - { - SocketServer server =3D 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 =3D "http://loca= lhost:5600"; - - protected String getLocatorURI() - { - return localLocatorURI; - } - - public static void main(String[] args) - { - SocketServer server =3D 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 clas= s. - This class is very similar to the one from the basic example. The ma= in - 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 c= an - 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 =3D SocketServer.loca= torURI; - - private CustomerProcessor customerProcessor =3D null; - - public void makeClientCall() throws Exception - { - Customer customer =3D createCustomer(); - - System.out.println("Customer to be processed: " + customer); - Customer processedCustomer =3D customerProce= ssor.processCustomer(customer); - System.out.println("Customer is now: " + processedCustomer); - - //TransporterClient.destroyTransporterClient(customerProcessor); - } - - public void getCustomerProcessor() throws Exception - { - customerProcessor =3D (CustomerProcessor) Tr= ansporterClient.createTransporterClient(locatorURI, CustomerProcessor.class= , true); - } - - private Customer createCustomer() - { - Customer cust =3D new Customer(); - cust.setFirstName("Bob"); - cust.setLastName("Smith"); - Address addr =3D 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 =3D 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 ri= ght - 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 ca= n 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 log= ged - 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 serv= er - 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.useHttpURLConnecti= on(HTTPClientInvoker.java:147) - at org.jboss.remoting.transport.http.HTTPClientInvoker.transport(HTTPClie= ntInvoker.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(TransporterCli= ent.java:219) - at $Proxy0.processCustomer(Unknown Source) - at org.jboss.remoting.samples.transporter3.client.Client.makeClientCall(C= lient.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.j= ava:39) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccess= orImpl.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.<init>(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(HttpURLCo= nnection.java:792) - at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnec= tion.java:744) - at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.= java:669) - at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLCon= nection.java:836) - at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnecti= on(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 fai= ling - 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 serv= ers - 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(HttpURLCon= nection.java:836) - at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnecti= on(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 runn= ing - in other processes. - -
- -
- Transporters sample - multiple - - The multiple transporter example (found in - org.jboss.remoting.samples.transporter.multiple package) shows how c= an - 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 focu= s 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 =3D "socket://localhost:5400"; - private TransporterServer server =3D null; - - public void start() throws Exception - { - server =3D TransporterServer.createTransporterServer(locatorURI, new= CustomerProcessorImpl(), CustomerProcessor.class.getName()); - server.addHandler(new AccountProcessorImpl(), AccountProcessor.class= .getName()); - } - - public void stop() - { - if(server !=3D null) - { - server.stop(); - } - } - - public static void main(String[] args) - { - Server server =3D new Server(); - try - { - server.start(); - - Thread.currentThread().sleep(60000); - - } - catch(Exception e) - { - e.printStackTrace(); - } - finally - { - server.stop(); - } - } -} - - The TransporterServer is created with the CustomerProcessorImp= l as - the inital target pojo. Now that have a live TransporterServer, can = add - other pojos as targets. This is done using the addHandler() method w= here - 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 =3D "socket://localhost:5400"; - - public void makeClientCall() throws Exception - { - Customer customer =3D createCustomer(); - - CustomerProcessor customerProcessor =3D (CustomerProcessor) Transpor= terClient.createTransporterClient(locatorURI, CustomerProcessor.class); - - System.out.println("Customer to be processed: " + customer); - Customer processedCustomer =3D customerProcessor.processCustomer(cus= tomer); - System.out.println("Customer is now: " + processedCustomer); - - AccountProcessor accountProcessor =3D (AccountProcessor) Transporter= Client.createTransporterClient(locatorURI, AccountProcessor.class); - - System.out.println("Asking for a new account to be created for custo= mer."); - Account account =3D accountProcessor.createAccount(processedCustomer= ); - System.out.println("New account: " + account); - - TransporterClient.destroyTransporterClient(customerProcessor); - TransporterClient.destroyTransporterClient(accountProcessor); - - } - - private Customer createCustomer() - { - Customer cust =3D new Customer(); - cust.setFirstName("Bob"); - cust.setLastName("Smith"); - Address addr =3D 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= =3D 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. T= hese - 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 - -
- -
- Transporters sample - proxy - - The proxy transporter example (found in - org.jboss.remoting.samples.transporter.proxy package) shows how can = have - a TransporterClient sent over the network and called upon. In this - example, will have a target pojo, CustomerProcessorImpl which itself - creates a TransporterClient to another target pojo, Customer, and re= turn - it as response to a method invocation. - - To start, will look at the initial target pojo, - CustomerProcessorImpl. - - public class CustomerProcessorImpl implements Custom= erProcessor -{ - private String locatorURI =3D "socket://localhost:5401"; - - /** - * Takes the customer passed, and if not null and customer id - * is less than 0, will create a new random id and set it. - * The customer object returned will be the modified customer - * object passed. - * - * @param customer - * @return - */ - public ICustomer processCustomer(Customer customer) - { - if (customer !=3D null && customer.getCustomerId() < 0) - { - customer.setCustomerId(new Random().nextInt(1000)); - } - - ICustomer customerProxy =3D null; - try - { - TransporterServer server =3D TransporterServer.createTransporterS= erver(locatorURI, customer, ICustomer.class.getName()); - customerProxy =3D (ICustomer) TransporterClient.createTransporter= Client(locatorURI, ICustomer.class); - } - catch (Exception e) - { - e.printStackTrace(); - } - - System.out.println("processed customer with new id of " + customerPr= oxy.getCustomerId()); - return customerProxy; - } - -} - - Notice that the processCustomer() method will take a Customer - object and set customer id on it. Then it will create a - TransporterServer for that customer instance and also create a - TransporterClient for the same instance and return that - TransporterClient proxy as the return to the processCustomer() - method. - - Next will look at the Customer class. It is a basic data objec= t in - that is really just stores the customer data. - - public class Customer implements Serializable, ICust= omer -{ - private String firstName =3D null; - private String lastName =3D null; - private Address addr =3D null; - private int customerId =3D -1; - - public String getFirstName() - { - return firstName; - } - - public void setFirstName(String firstName) - { - this.firstName =3D firstName; - } - - public String getLastName() - { - return lastName; - } - - public void setLastName(String lastName) - { - this.lastName =3D lastName; - } - - public Address getAddr() - { - return addr; - } - - public void setAddr(Address addr) - { - this.addr =3D addr; - } - - public int getCustomerId() - { - return customerId; - } - - public void setCustomerId(int customerId) - { - this.customerId =3D customerId; - } - - public String toString() - { - System.out.println("Customer.toString() being called."); - StringBuffer buffer =3D new StringBuffer(); - buffer.append("\nCustomer:\n"); - buffer.append("customer id: " + customerId + "\n"); - buffer.append("first name: " + firstName + "\n"); - buffer.append("last name: " + lastName + "\n"); - buffer.append("street: " + addr.getStreet() + "\n"); - buffer.append("city: " + addr.getCity() + "\n"); - buffer.append("state: " + addr.getState() + "\n"); - buffer.append("zip: " + addr.getZip() + "\n"); - - return buffer.toString(); - } - - -} - - - Notice the toString() method and how it prints out to the stan= dard - out when being called. This will be important when the sample is run - later. - - Now if look at the Server class, will see is a standard setup = like - have seen in previous samples. - - public class Server -{ - private String locatorURI =3D "socket://localhost:5400"; - private TransporterServer server =3D null; - - public void start() throws Exception - { - server =3D TransporterServer.createTransporterServer(locatorURI, new= CustomerProcessorImpl(), CustomerProcessor.class.getName()); - } - - public void stop() - { - if (server !=3D null) - { - server.stop(); - } - } - - public static void main(String[] args) - { - Server server =3D new Server(); - try - { - server.start(); - - Thread.currentThread().sleep(60000); - - } - catch (Exception e) - { - e.printStackTrace(); - } - finally - { - server.stop(); - } - } -} - - It is creating a TransporterServer for the CustomerProcessImpl - upon being started and will wait 60 seconds for invocations. - - Next is the Client class. - - public class Client -{ - private String locatorURI =3D "socket://localhost:5400"; - - public void makeClientCall() throws Exception - { - Customer customer =3D createCustomer(); - - CustomerProcessor customerProcessor =3D (CustomerProcessor) Transpor= terClient.createTransporterClient(locatorURI, CustomerProcessor.class); - - System.out.println("Customer to be processed: " + customer); - ICustomer processedCustomer =3D customerProcessor.processCustomer(cu= stomer); - // processedCustomer returned is actually a proxy to the Customer in= stnace - // that lives on the server. So when print it out below, will actua= lly - // be calling back to the server to get the string (vi toString() ca= ll). - // Notice the output of 'Customer.toString() being called.' on the s= erver side. - System.out.println("Customer is now: " + processedCustomer); - - TransporterClient.destroyTransporterClient(customerProcessor); - - - } - - private Customer createCustomer() - { - Customer cust =3D new Customer(); - cust.setFirstName("Bob"); - cust.setLastName("Smith"); - Address addr =3D 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) - { - Client client =3D new Client(); - try - { - client.makeClientCall(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - -} - - The client class looks similar to the other example seen in th= at - it creates a TransporterClient for the CustomerProcessor and calls o= n it - to process the customer. Will then call on the ICustomer instance - returned from the processCustomer() method call and call toString() = on - it (in the system out call). - - To run this example, run the Server class and then the Client - class. This can be done via ant targets 'run-transporter-proxy-serve= r' - and then 'run-transporter-proxy-client'. For example: - - ant run-transporter-proxy-server - - ant then: - - ant run-transporter-proxy-client - - The output for the client should look similar to: - - Customer.toString() being called. -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: 418 -first name: Bob -last name: Smith -street: 101 Oak Street -city: Atlanta -state: GA -zip: 30249 - - - The first line - is the print out from calling the Customer's toString() method that = was - created to be passed to the CustomerProcessor's processCustomer() - method. Then the contents of the Customer object before being proces= sed. - Then have the print out of the customer after has been processed. No= tice - that when the ICustomer object instance is printed out the second ti= me, - do not see the 'Customer.toString() being called'. This is because t= hat - code is no longer being executed in the client vm, but instead is a - remote call to the customer instance living on the server (remember,= the - processCustomer() method returned a TransporterClient proxy to the - customer living on the server side). - - Now, if look at output from the server will look similar - to: - - processed customer with new id of 418 -Customer.toString() being called. - - Notice that the 'Customer.toString() being called.' printed ou= t at - the end. This is the result of the client's call to print out the - contents of the customer object returned from the processCustomer() - method, which actually lives within the server vm. - - This example has shown how can pass around TransporterClient - proxies to target pojos. However, when doing this, is important to - understand where the code is actually being executed as there are - consequences to being remote verse local, which need to be - understood. -
- -
- Transporter sample -complex - - The complex transporter example (found in - org.jboss.remoting.samples.transporter.complex package) is based off= a - test case a user, Milt Grinberg, provided (thanks Milt). The example= is - similar to the previous examples, except in this case involves match= ing - Doctors and Patients using the ProviderInterface and provides a more - complex sample in which to demonstrate how to use transporters. - - This example requires JDK 1.5 to run, since is using JBoss - Serialization (and non-serialized data objects). To run this example, - run the Server class and then the Client class. This can be done via= ant - targets 'run-transporter-complex-server' and then - 'run-transporter-complex-client' as well. For example: - - ant run-transporter-complex-server - - and then: - - ant run-transporter-complex-client - - The output for the client should look similar to: - - *** Have a new patient that needs a doctor. The pat= ient is: - -Patient: - Name: Bill Gates - Ailment - Type: financial, Description: Money coming out the wazoo. - -*** Looking for doctor that can help our patient... - -*** Found doctor for our patient. Doctor found is: -Doctor: - Name: Andy Jones - Specialty: financial - Patients: - -Patient: - Name: Larry Ellison - Ailment - Type: null, Description: null - Doctor - Name: Andy Jones - -Patient: - Name: Steve Jobs - Ailment - Type: null, Description: null - Doctor - Name: Andy Jones - -Patient: - Name: Bill Gates - Ailment - Type: financial, Description: Money coming out the wazoo. - -*** Set doctor as patient's doctor. Patient info is now: - -Patient: - Name: Bill Gates - Ailment - Type: financial, Description: Money coming out the wazoo. - Doctor - Name: Andy Jones - -*** Have a new patient that we need to find a doctor for (remember, the pr= evious one retired and there are no others) -*** Could not find doctor for patient. This is an expected exception when= there are not doctors available. -org.jboss.remoting.samples.transporter.complex.NoDoctorAvailableException:= No doctor available for ailment 'financial' - at org.jboss.remoting.RemoteClientInvoker.invoke(RemoteClientInvoker.java= :183) - at org.jboss.remoting.Client.invoke(Client.java:325) - at org.jboss.remoting.Client.invoke(Client.java:288) - at org.jboss.remoting.Client.invoke(Client.java:273) - at org.jboss.remoting.transporter.TransporterClient.invoke(TransporterCli= ent.java:237) - at $Proxy0.findDoctor(Unknown Source) - at org.jboss.remoting.samples.transporter.complex.client.Client.makeClien= tCall(Client.java:72) - at org.jboss.remoting.samples.transporter.complex.client.Client.main(Clie= nt.java:90) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.j= ava:39) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccess= orImpl.java:25) - at java.lang.reflect.Method.invoke(Method.java:585) - at com.intellij.rt.execution.application.AppMain.main(AppMain.java:86) - - - From the output see the creation of a new patient, Bill Gates,= and - the attempt to find a doctor that specializes in his ailment. For Mr. - Gates, we were able to find a doctor, Andy Jones, and can see that he - has been added to the list of Dr. Jones' patients. Then we have Dr. - Jones retire. Then we create a new patient and try to find an availa= ble - doctor for the same ailment. Since Dr. Jones has retired, and there = are - no other doctors that specialize in that particular ailment, an - exception is thrown. This is as expected. -
-
- -
- Multiplex invokers - - This section illustrates the construction of multiplex invoker - groups described in the section . The - directory - -
- examples/org/jboss/remoting/samples/multiplex/invoker -
- - contains a server class, - MultiplexInvokerServer, which is suitable for u= se - with any of the client classes described below. It may be run in an ID= E or - from the command line using ant target run-multiplex-server - from the build.xml file found in the examples - directory. The server will stay alive, processing invocation requests = as - they are presented, until it has sent two push callbacks to however ma= ny - listeners are registered, at which time it will shut itself down. - - The sample clients are as follows. Each sample client - <client> may be run in an IDE or by using t= he - ant target run-<client> (e.g., - run-Client2Server1). - - - - Client2Server1: A - MultiplexClientInvoker starts according to - client rule 2, after which a - MultiplexServerInvoker is started according= to - server rule 1. Note that the Client and - Connector are passed matching - clientMultiplexId and - serverMultiplexId parameters, - respectively. - - - - Client2Server2: A - MultiplexClientInvoker starts according to - client rule 2, after which a - MultiplexServerInvoker is started according= to - server rule 2. Note that no clientMultiplexId= is - passed to the Client and no - serverMultiplexId parameter is passed to the - Connector in this example. - - - - Client3Server1: A - MultiplexClientInvoker is created, and, lac= king - binding information, finds itself governed by client rule 3. - Subsequently, a MultiplexServerInvoker is - started according to server rule 1, providing the binding informat= ion - which allows the MultiplexClientInvoker to - start. Note that the Client and - Connector are passed matching - clientMultiplexId and - serverMultiplexId parameters, - respectively. - - - - Server2Client1: A - MultiplexServerInvoker starts according to - server rule 2, after which a - MultiplexClientInvoker is started according= to - client rule 1. Note that the Connector and - Client are passed matching - serverMultiplexId and - clientMultiplexId parameters, - respectively. - - - - Server2Client2: A - MultiplexServerInvoker starts according to - server rule 2, after which a - MultiplexClientInvoker is started according= to - client rule 2. Note that no serverMultiplexId= is - passed to the Connector and no - clientMultiplexId parameter is passed to the - Client in this example. - - - - Server3Client1: A - MultiplexServerInvoker is created, and, lac= king - connect information, finds itself governed by server rule 3. - Subsequently, a MultiplexClientInvoker is - started according to client rule 1, providing the connect informat= ion - which allows the MultiplexServerInvoker to - start. Note that the Connector and - Client are passed matching - serverMultiplexId and - clientMultiplexId parameters, - respectively. - - - - For variety, the examples in which the client invoker starts fir= st - use the configuration Map to pass invoker group - parameters, and the examples in which the server invoker starts first = pass - parameters in the InvokerLocator. -
-
\ No newline at end of file + When boiled down, transporters take a plain old java object (POJ= O) + and expose a remote proxy to it via JBoss Remoting. Dynamic proxies and + reflection are used to make the typed method calls on that target POJO. + Since JBoss Remoting is used, can select from a number of different + network transports (i.e. rmi, http, socket, multiplex, etc.), including + support for SSL. Even clustering features can be included. See the + transporter samples in the next chapter for detailed examples of how to + set up use of a transporter. +
\ No newline at end of file --===============1445728459829918377==--