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==--