KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > iiop > rmi > marshal > strategy > StubStrategy


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.iiop.rmi.marshal.strategy;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.rmi.UnexpectedException JavaDoc;
30 import javax.rmi.PortableRemoteObject JavaDoc;
31
32 import org.omg.CORBA.UserException JavaDoc;
33 import org.omg.CORBA.portable.IDLEntity JavaDoc;
34 import org.omg.CORBA_2_3.portable.InputStream JavaDoc;
35 import org.omg.CORBA_2_3.portable.OutputStream JavaDoc;
36
37 import org.jboss.iiop.rmi.marshal.CDRStream;
38 import org.jboss.iiop.rmi.marshal.CDRStreamReader;
39 import org.jboss.iiop.rmi.marshal.CDRStreamWriter;
40
41 /**
42  * An <code>StubStrategy</code> for a given method knows how to marshal
43  * the sequence of method parameters into a CDR output stream, how to unmarshal
44  * from a CDR input stream the return value of the method, and how to unmarshal
45  * from a CDR input stream an application exception thrown by the method.
46  *
47  * @author <a HREF="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
48  * @version $Revision: 37459 $
49  */

50 public class StubStrategy
51 {
52    // Fields ------------------------------------------------------------------
53

54    /**
55     * Each <code>CDRStreamWriter</code> in the array marshals a method
56     * parameter.
57     */

58    private CDRStreamWriter[] paramWriters;
59
60    /**
61     * List of exception classes.
62     */

63    private List JavaDoc exceptionList;
64
65    /**
66     * Maps exception repository ids into ExceptionReader instances.
67     */

68    private Map JavaDoc exceptionMap;
69
70    /**
71     * A <code>CDRStreamReader</code> that unmarshals the return value of the
72     * method.
73     */

74    private CDRStreamReader retvalReader;
75
76    /**
77     * If this <code>StubStrategy</code> is for a method that returns a
78     * remote interface, this field contains the remote interface's
79     * <code>Class</code>. Otherwise it contains null.
80     */

81    private Class JavaDoc retvalRemoteInterface;
82    // Static ------------------------------------------------------------------
83

84    /**
85     * Returns an <code>StubStrategy</code> for a method, given descriptions
86     * of the method parameters, exceptions, and return value. Parameter and
87     * return value descriptions are "marshaller abbreviated names".
88     *
89     * @param paramTypes a string array with marshaller abbreviated names for
90     * the method parameters
91     * @param excepIds a string array with the CORBA repository ids of the
92     * exceptions thrown by the method
93     * @param excepTypes a string array with the Java class names of the
94     * exceptions thrown by the method
95     * @param retvalType marshaller abbreaviated name for the return value of
96     * the method
97     * @param cl a <code>ClassLoader</code> to load value classes
98     * (if null, the current thread's context class loader
99     * will be used)
100     * @return an <code>StubStrategy</code> for the operation with the
101     * parameters, exceptions, and return value specified.
102     * @see org.jboss.iiop.marshal.CDRStream#abbrevFor(Class clz)
103     */

104    public static StubStrategy forMethod(String JavaDoc[] paramTypes,
105                                         String JavaDoc[] excepIds,
106                                         String JavaDoc[] excepTypes,
107                                         String JavaDoc retvalType,
108                                         ClassLoader JavaDoc cl)
109    {
110       // This "factory method" exists just because I have found it easier
111
// to invoke a static method (rather than invoking operator new)
112
// from a stub class dynamically assembled by an instance of
113
// org.jboss.proxy.ProxyAssembler.
114

115       return new StubStrategy(paramTypes, excepIds,
116                               excepTypes, retvalType, cl);
117    }
118
119
120    // Constructor -------------------------------------------------------------
121

122    /**
123     * Constructs an <code>StubStrategy</code> for a method, given
124     * descriptions of the method parameters, exceptions, and return value.
125     * Parameter and return value descriptions are "marshaller abbreviated
126     * names".
127     *
128     * @param paramTypes a string array with marshaller abbreviated names for
129     * the method parameters
130     * @param excepIds a string array with the CORBA repository ids of the
131     * exceptions thrown by the method
132     * @param excepTypes a string array with the Java class names of the
133     * exceptions thrown by the method
134     * @param retvalType marshaller abbreaviated name for the return value of
135     * the method
136     * @param cl a <code>ClassLoader</code> to load value classes
137     * (if null, the current thread's context class loader
138     * will be used)
139     * @see org.jboss.iiop.marshal.CDRStream#abbrevFor(Class clz)
140     */

141    private StubStrategy(String JavaDoc[] paramTypes, String JavaDoc[] excepIds,
142                         String JavaDoc[] excepTypes, String JavaDoc retvalType,
143                         ClassLoader JavaDoc cl)
144    {
145       if (cl == null) {
146          cl = Thread.currentThread().getContextClassLoader();
147       }
148       
149       // Initialize paramWriters
150
int len = paramTypes.length;
151       paramWriters = new CDRStreamWriter[len];
152       for (int i = 0; i < len; i++) {
153             paramWriters[i] = CDRStream.writerFor(paramTypes[i], cl);
154       }
155
156       // Initialize exception list and exception map
157
exceptionList = new ArrayList JavaDoc();
158       exceptionMap = new HashMap JavaDoc();
159       len = excepIds.length;
160       for (int i = 0; i < len; i++) {
161          try {
162             Class JavaDoc clz = cl.loadClass(excepTypes[i]);
163             exceptionList.add(clz);
164             ExceptionReader exceptionReader =
165                new ExceptionReader(clz, excepIds[i]);
166             exceptionMap.put(exceptionReader.getReposId(), exceptionReader);
167          }
168          catch (ClassNotFoundException JavaDoc e) {
169             throw new RuntimeException JavaDoc("Error loading class "
170                                        + excepTypes[i] + ": " + e);
171          }
172       }
173
174       // Initialize retvalReader
175
retvalReader = CDRStream.readerFor(retvalType, cl);
176
177       // Initialize retvalRemoteInterface
178
if (retvalType.charAt(0) == 'R') {
179          try {
180             retvalRemoteInterface = cl.loadClass(retvalType.substring(1));
181          }
182          catch (ClassNotFoundException JavaDoc e) {
183             throw new RuntimeException JavaDoc("Error loading class "
184                                        + retvalType.substring(1) + ": " + e);
185          }
186       }
187    }
188
189    // Public -----------------------------------------------------------------
190

191    /**
192     * Marshals the sequence of method parameters into an output stream.
193     *
194     * @param out a CDR output stream
195     * @param params an object array with the parameters.
196     */

197    public void writeParams(OutputStream JavaDoc out, Object JavaDoc[] params)
198    {
199       int len = params.length;
200       
201       if (len != paramWriters.length) {
202           throw new RuntimeException JavaDoc("Cannot marshal parameters: "
203                                      + "unexpected number of parameters");
204       }
205       for (int i = 0; i < len; i++ ) {
206          paramWriters[i].write(out, params[i]);
207       }
208    }
209    
210    /**
211     * Returns true if this <code>StubStrategy</code>'s method is non void.
212     */

213    public boolean isNonVoid()
214    {
215       return (retvalReader != null);
216    }
217
218    /**
219     * Unmarshals from an input stream the return value of the method.
220     *
221     * @param in a CDR input stream
222     * @return a value unmarshaled from the stream.
223     */

224    public Object JavaDoc readRetval(InputStream JavaDoc in)
225    {
226       return retvalReader.read(in);
227    }
228
229    /**
230     * Unmarshals from an input stream an exception thrown by the method.
231     *
232     * @param id the repository id of the exception to unmarshal
233     * @param in a CDR input stream
234     * @return an exception unmarshaled from the stream.
235     */

236    public Exception JavaDoc readException(String JavaDoc id, InputStream JavaDoc in)
237    {
238       ExceptionReader exceptionReader = (ExceptionReader)exceptionMap.get(id);
239       if (exceptionReader == null) {
240          return new UnexpectedException JavaDoc(id);
241       }
242       else {
243          return exceptionReader.read(in);
244       }
245    }
246
247    /**
248     * Checks if a given <code>Throwable</code> instance corresponds to an
249     * exception declared by this <code>StubStrategy</code>'s method.
250     *
251     * @param t an exception class
252     * @return true if <code>t</code> is an instance of any of the
253     * exceptions declared by this <code>StubStrategy</code>'s
254     * method, false otherwise.
255     */

256    public boolean isDeclaredException(Throwable JavaDoc t)
257    {
258       Iterator JavaDoc iterator = exceptionList.iterator();
259       while (iterator.hasNext()) {
260          if (((Class JavaDoc)iterator.next()).isInstance(t)) {
261             return true;
262          }
263       }
264       return false;
265    }
266    
267    /**
268     * Converts the return value of a local invocation into the expected type.
269     * A conversion is needed if the return value is a remote interface
270     * (in this case <code>PortableRemoteObject.narrow()</code> must be called).
271     *
272     * @param obj the return value to be converted
273     * @return the converted value.
274     */

275    public Object JavaDoc convertLocalRetval(Object JavaDoc obj)
276    {
277       if (retvalRemoteInterface == null)
278          return obj;
279       else
280          return PortableRemoteObject.narrow(obj, retvalRemoteInterface);
281    }
282    
283    // Static inner class (private) --------------------------------------------
284

285    /**
286     * An <code>ExceptionReader</code> knows how to read exceptions of a given
287     * class from a CDR input stream.
288     */

289    private static class ExceptionReader
290    {
291       /**
292        * The exception class.
293        */

294       private Class JavaDoc clz;
295   
296       /**
297        * The CORBA repository id of the exception class.
298        */

299       private String JavaDoc reposId;
300       
301       /*
302        * If the exception class corresponds to an IDL-defined exception, this
303        * field contains the read method of the associated helper class.
304        * A null value indicates that the exception class does not correspond
305        * to an IDL-defined exception.
306        */

307       private java.lang.reflect.Method JavaDoc readMethod = null;
308
309       /**
310        * Constructs an <code>ExceptionReader</code> for a given exception
311        * class.
312        */

313       ExceptionReader(Class JavaDoc clz, String JavaDoc reposId)
314       {
315          this.clz = clz;
316          if (IDLEntity JavaDoc.class.isAssignableFrom(clz)
317              && UserException JavaDoc.class.isAssignableFrom(clz)) {
318
319             // This ExceptionReader corresponds to an IDL-defined exception
320
String JavaDoc helperClassName = clz.getName() + "Helper";
321             try {
322                Class JavaDoc helperClass =
323                   clz.getClassLoader().loadClass(helperClassName);
324                Class JavaDoc[] paramTypes =
325                   { org.omg.CORBA.portable.InputStream JavaDoc.class };
326                readMethod = helperClass.getMethod("read", paramTypes);
327
328                // Ignore the reposId parameter and use the id
329
// returned by the IDL-generated helper class
330
java.lang.reflect.Method JavaDoc idMethod =
331                   helperClass.getMethod("id", null);
332                this.reposId = (String JavaDoc)idMethod.invoke(null, null);
333             }
334             catch (ClassNotFoundException JavaDoc e) {
335                throw new RuntimeException JavaDoc("Error loading class "
336                                           + helperClassName + ": " + e);
337             }
338             catch (NoSuchMethodException JavaDoc e) {
339                 throw new RuntimeException JavaDoc("No read/id method in helper class "
340                                            + helperClassName + ": " + e);
341             }
342             catch (IllegalAccessException JavaDoc e) {
343                throw new RuntimeException JavaDoc("Internal error: " + e);
344             }
345             catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
346                throw new RuntimeException JavaDoc("Exception in call to "
347                                           + helperClassName + ": "
348                                           + e.getTargetException());
349             }
350          }
351          else {
352             // This ExceptionReader does not correspond to an IDL-defined
353
// exception: store the reposId parameter
354
this.reposId = reposId;
355          }
356       }
357
358       public String JavaDoc getReposId()
359       {
360          return reposId;
361       }
362       
363       /**
364        * Reads an exception from a CDR input stream.
365        */

366       public Exception JavaDoc read(InputStream JavaDoc in)
367       {
368          if (readMethod != null) {
369             try {
370                return (Exception JavaDoc)readMethod.invoke(null, new Object JavaDoc[] { in });
371             }
372             catch (IllegalAccessException JavaDoc e) {
373                throw new RuntimeException JavaDoc("Internal error: " + e);
374             }
375             catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
376                throw new RuntimeException JavaDoc("Exception unmarshaling IDLEntity: "
377                                           + e.getTargetException());
378             }
379          }
380          else {
381             in.read_string(); // read and discard the repository id
382
return (Exception JavaDoc)in.read_value(clz);
383          }
384       }
385
386    } // end of inner class ExceptionReader
387

388 }
389
Popular Tags