KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > remoting > RemoteClientInvoker


1 /***************************************
2  * *
3  * JBoss: The OpenSource J2EE WebOS *
4  * *
5  * Distributable under LGPL license. *
6  * See terms of license at gnu.org. *
7  * *
8  ***************************************/

9 package org.jboss.remoting;
10
11 import java.io.IOException JavaDoc;
12 import java.util.Map JavaDoc;
13 import org.jboss.remoting.loading.ClassByteClassLoader;
14 import org.jboss.remoting.marshal.InvalidMarshallingResource;
15 import org.jboss.remoting.marshal.MarshalFactory;
16 import org.jboss.remoting.marshal.Marshaller;
17 import org.jboss.remoting.marshal.UnMarshaller;
18 import org.jboss.remoting.transport.ClientInvoker;
19
20 /**
21  * RemoteClientInvoker is an abstract client part handler that implements the bulk of the heavy
22  * lifting to process a remote method and dispatch it to a remote ServerInvoker and handle the result. <P>
23  * <p/>
24  * Specialized Client/Server Invokers might add additional functionality as part of the invocation - such as
25  * delivering queued notifcations from a remote server by adding the notification objects during each invocation
26  * to the invocation result payload and then having the client re-dispatch the notifications locally upon
27  * receiving the return invocation result.
28  *
29  * @author <a HREF="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
30  * @author <a HREF="mailto:telrod@e2technologies.net">Tom Elrod</a>
31  * @version $Revision: 1.8 $
32  */

33 public abstract class RemoteClientInvoker extends AbstractInvoker implements ClientInvoker
34 {
35    protected boolean connected = false;
36    private Marshaller marshaller;
37    private UnMarshaller unmarshaller;
38    private String JavaDoc dataType;
39
40
41    public RemoteClientInvoker(InvokerLocator locator)
42    {
43       super(locator);
44    }
45
46    /**
47     * transport a request against a remote ServerInvoker
48     *
49     * @param invocationReq
50     * @return
51     * @throws Throwable
52     */

53    public Object JavaDoc invoke(InvocationRequest invocationReq)
54          throws Throwable JavaDoc
55    {
56       Object JavaDoc returnValue = null;
57       int invokeCount = 0;
58
59       if(log.isTraceEnabled())
60       {
61          log.trace((++invokeCount) + ") invoking =>" + invocationReq + " with parameter: " + invocationReq.getParameter());
62       }
63
64       Marshaller marshaller = getMarshaller();
65       UnMarshaller unmarshaller = getUnMarshaller();
66
67       if(marshaller == null)
68       {
69          // try by locator (in case marshaller class name specified)
70
marshaller = MarshalFactory.getMarshaller(getLocator(), getClassLoader());
71          if(marshaller == null)
72          {
73             // need to have a marshaller, so create a default one
74
marshaller = MarshalFactory.getMarshaller(getDataType());
75             if(marshaller == null)
76             {
77                // went as far as possible to find a marshaller, will have to give up
78
throw new InvalidMarshallingResource("Can not find a valid marshaller for data type: " + getDataType());
79             }
80          }
81       }
82
83       if(unmarshaller == null)
84       {
85          // try by locator (in case unmarshaller class name specified)
86
unmarshaller = MarshalFactory.getUnMarshaller(getLocator(), getClassLoader());
87          if(unmarshaller == null)
88          {
89             unmarshaller = MarshalFactory.getUnMarshaller(getDataType());
90             if(unmarshaller == null)
91             {
92                // went as far as possible to find a unmarshaller, will have to give up
93
throw new InvalidMarshallingResource("Can not find a valid unmarshaller for data type: " + getDataType());
94             }
95          }
96       }
97
98       try
99       {
100          // if raw, then send only param of invocation request
101
Object JavaDoc payload = null;
102          Map JavaDoc metadata = invocationReq.getRequestPayload();
103          if(metadata != null && metadata.get(Client.RAW) != null)
104          {
105             payload = invocationReq.getParameter();
106          }
107          else
108          {
109             payload = invocationReq;
110          }
111
112          returnValue = transport(invocationReq.getSessionId(), payload, metadata, marshaller, unmarshaller);
113
114          if(log.isTraceEnabled())
115          {
116             log.trace("received result=>" + returnValue);
117          }
118
119          // Now check if is remoting response and process
120
if(returnValue instanceof InvocationResponse)
121          {
122             InvocationResponse response = (InvocationResponse) returnValue;
123             returnValue = response.getResult();
124             if(log.isTraceEnabled())
125             {
126                log.trace("received result was an InvocationResponse so going to return response's return value of " + returnValue);
127                log.trace("response is exception = " + response.isException());
128             }
129             // if is a server side exception, throw it
130
if(response.isException())
131             {
132                throw (Throwable JavaDoc) returnValue;
133             }
134          }
135       }
136       catch(ClassNotFoundException JavaDoc cnf)
137       {
138          //TODO: -TME For now, just throw cnf, later will add dynamic classloading here.
139
throw cnf;
140       }
141       return returnValue;
142    }
143
144    /**
145     * this method is called prior to making the remote invocation to allow the subclass the ability
146     * to provide additional data or modify the invocation
147     *
148     * @param sessionId
149     * @param param
150     * @param sendPayload
151     * @param receivedPayload
152     */

153    protected void preProcess(String JavaDoc sessionId, Object JavaDoc param, Map JavaDoc sendPayload, Map JavaDoc receivedPayload)
154    {
155    }
156
157    /**
158     * this method is called prior to returning the result for the invocation to allow the subclass the ability
159     * to modify the result result
160     *
161     * @param sessionId
162     * @param param
163     * @param sendPayload
164     * @param receivedPayload
165     */

166    protected void postProcess(String JavaDoc sessionId, Object JavaDoc param, Map JavaDoc sendPayload,
167                               Map JavaDoc receivedPayload)
168    {
169
170    }
171
172    /**
173     * @param sessionId
174     * @param invocation
175     * @param marshaller
176     * @return
177     * @throws IOException
178     * @throws ConnectionFailedException
179     */

180    protected abstract Object JavaDoc transport(String JavaDoc sessionId, Object JavaDoc invocation, Map JavaDoc metadata, Marshaller marshaller, UnMarshaller unmarshaller)
181          throws IOException JavaDoc, ConnectionFailedException, ClassNotFoundException JavaDoc;
182
183    /**
184     * subclasses must provide this method to return true if their remote connection is connected and
185     * false if disconnected. in some transports, such as SOAP, this method may always return true, since the
186     * remote connectivity is done on demand and not kept persistent like other transports (such as socket-based
187     * transport).
188     *
189     * @return boolean true if connected, false if not
190     */

191    public boolean isConnected()
192    {
193       return connected;
194    }
195
196
197    /**
198     * connect to the remote invoker
199     *
200     * @throws ConnectionFailedException
201     */

202    public synchronized void connect()
203          throws ConnectionFailedException
204    {
205       if(!connected)
206       {
207          log.debug("connect called for: " + this);
208
209          handleConnect();
210          connected = true;
211       }
212    }
213
214    /**
215     * subclasses must implement this method to provide a hook to connect to the remote server, if this applies
216     * to the specific transport. However, in some transport implementations, this may not make must difference since
217     * the connection is not persistent among invocations, such as SOAP. In these cases, the method should
218     * silently return without any processing.
219     *
220     * @throws ConnectionFailedException
221     */

222    protected abstract void handleConnect()
223          throws ConnectionFailedException;
224
225    /**
226     * subclasses must implement this method to provide a hook to disconnect from the remote server, if this applies
227     * to the specific transport. However, in some transport implementations, this may not make must difference since
228     * the connection is not persistent among invocations, such as SOAP. In these cases, the method should
229     * silently return without any processing.
230     */

231    protected abstract void handleDisconnect();
232
233    /**
234     * disconnect from the remote invokere
235     */

236    public synchronized void disconnect()
237    {
238       if(connected)
239       {
240          log.debug("disconnect called for: " + this);
241
242          connected = false;
243          handleDisconnect();
244          ClassLoader JavaDoc classLoader = getClassLoader();
245          if(classLoader != null && classLoader instanceof ClassByteClassLoader)
246          {
247             ((ClassByteClassLoader) classbyteloader).destroy();
248          }
249       }
250       /**
251        * Need to remove myself from registry so will not keep
252        * reference to me since I am of no use now. Will have to create
253        * a new one.
254        */

255       InvokerRegistry.destroyClientInvoker(getLocator());
256    }
257
258    public void setMarshaller(Marshaller marshaller)
259    {
260       this.marshaller = marshaller;
261    }
262
263    public Marshaller getMarshaller()
264    {
265       return this.marshaller;
266    }
267
268    public void setUnMarshaller(UnMarshaller unmarshaller)
269    {
270       this.unmarshaller = unmarshaller;
271    }
272
273    public UnMarshaller getUnMarshaller()
274    {
275       return this.unmarshaller;
276    }
277
278    /**
279     * Will get the data type for the marshaller factory so know which marshaller to
280     * get to marshal the data. Will first check the locator uri for a 'datatype'
281     * parameter and take that value if it exists. Otherwise, will use the
282     * default datatype for the client invoker, based on transport.
283     *
284     * @return
285     */

286    private String JavaDoc getDataType()
287    {
288       if(dataType == null)
289       {
290          dataType = getDataType(getLocator());
291          if(dataType == null)
292          {
293             dataType = getDefaultDataType();
294          }
295       }
296       return dataType;
297    }
298
299    private String JavaDoc getDataType(InvokerLocator locator)
300    {
301       String JavaDoc type = null;
302
303       if(locator != null)
304       {
305          Map JavaDoc params = locator.getParameters();
306          if(params != null)
307          {
308             type = (String JavaDoc) params.get(InvokerLocator.DATATYPE);
309             if(type == null)
310             {
311                type = (String JavaDoc) params.get(InvokerLocator.DATATYPE_CASED);
312             }
313          }
314       }
315       return type;
316    }
317
318    /**
319     * Each implementation of the remote client invoker should have
320     * a default data type that is uses in the case it is not specified
321     * in the invoker locator uri.
322     *
323     * @return
324     */

325    protected abstract String JavaDoc getDefaultDataType();
326
327
328    /**
329     * Called by the garbage collector on an object when garbage collection
330     * determines that there are no more references to the object.
331     * A subclass overrides the <code>finalize</code> method to dispose of
332     * system resources or to perform other cleanup.
333     * <p/>
334     * The general contract of <tt>finalize</tt> is that it is invoked
335     * if and when the Java<font size="-2"><sup>TM</sup></font> virtual
336     * machine has determined that there is no longer any
337     * means by which this object can be accessed by any thread that has
338     * not yet died, except as a result of an action taken by the
339     * finalization of some other object or class which is ready to be
340     * finalized. The <tt>finalize</tt> method may take any action, including
341     * making this object available again to other threads; the usual purpose
342     * of <tt>finalize</tt>, however, is to perform cleanup actions before
343     * the object is irrevocably discarded. For example, the finalize method
344     * for an object that represents an input/output connection might perform
345     * explicit I/O transactions to break the connection before the object is
346     * permanently discarded.
347     * <p/>
348     * The <tt>finalize</tt> method of class <tt>Object</tt> performs no
349     * special action; it simply returns normally. Subclasses of
350     * <tt>Object</tt> may override this definition.
351     * <p/>
352     * The Java programming language does not guarantee which thread will
353     * transport the <tt>finalize</tt> method for any given object. It is
354     * guaranteed, however, that the thread that invokes finalize will not
355     * be holding any user-visible synchronization locks when finalize is
356     * invoked. If an uncaught exception is thrown by the finalize method,
357     * the exception is ignored and finalization of that object terminates.
358     * <p/>
359     * After the <tt>finalize</tt> method has been invoked for an object, no
360     * further action is taken until the Java virtual machine has again
361     * determined that there is no longer any means by which this object can
362     * be accessed by any thread that has not yet died, including possible
363     * actions by other objects or classes which are ready to be finalized,
364     * at which point the object may be discarded.
365     * <p/>
366     * The <tt>finalize</tt> method is never invoked more than once by a Java
367     * virtual machine for any given object.
368     * <p/>
369     * Any exception thrown by the <code>finalize</code> method causes
370     * the finalization of this object to be halted, but is otherwise
371     * ignored.
372     *
373     * @throws Throwable the <code>Exception</code> raised by this method
374     */

375    protected void finalize() throws Throwable JavaDoc
376    {
377       disconnect();
378       super.finalize();
379    }
380 }
381
Popular Tags