DynamicMethodMarshallerImpl.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.corba.se.impl.presentation.rmi ;
27
28import java.io.Serializable ;
29import java.io.Externalizable ;
30
31import javax.rmi.PortableRemoteObject ;
32import javax.rmi.CORBA.Util ;
33
34import org.omg.CORBA.portable.IDLEntity ;
35
36import org.omg.CORBA_2_3.portable.InputStream ;
37import org.omg.CORBA_2_3.portable.OutputStream ;
38import org.omg.CORBA.portable.ApplicationException ;
39
40import java.lang.reflect.Method ;
41
42import java.rmi.RemoteException ;
43
44import com.sun.corba.se.spi.orb.ORB ;
45
46import com.sun.corba.se.spi.presentation.rmi.DynamicMethodMarshaller ;
47
48public class DynamicMethodMarshallerImpl implements DynamicMethodMarshaller
49{
50    Method method ;
51    ExceptionHandler ehandler ;
52    boolean hasArguments = true ;
53    boolean hasVoidResult = true ;
54    boolean needsArgumentCopy ;         // true if copyObjects call needs for args
55    boolean needsResultCopy ;           // true if copyObject call needs for result
56    ReaderWriter[] argRWs = null ;
57    ReaderWriter resultRW = null ;
58
59    private static boolean isAnyClass( Class cls )
60    {
61        return cls.equals( Object.class ) || cls.equals( Serializable.class ) ||
62            cls.equals( Externalizable.class ) ;
63    }
64
65    // Assume that cls is not Remote, !isAnyClass(cls), and
66    // !org.omg.CORBA.Object.class.isAssignableFrom( cls ).
67    // Then return whether cls is an RMI-IIOP abstract interface.
68    private static boolean isAbstractInterface( Class cls )
69    {
70        // Either cls is an interface that extends IDLEntity, or else
71        // cls does not extend java.rmi.Remote and all of its methods
72        // throw RemoteException.
73        if (IDLEntity.class.isAssignableFrom( cls ))
74            return cls.isInterface() ;
75        else
76            return cls.isInterface() && allMethodsThrowRemoteException( cls ) ;
77    }
78
79    private static boolean allMethodsThrowRemoteException( Class cls )
80    {
81        Method[] methods = cls.getMethods() ;
82
83        // Check that all methods (other than those declared in java.lang.Object)
84        // throw an exception that is a subclass of RemoteException.
85        for (int ctr=0; ctr<methods.length; ctr++) {
86            Method method = methods[ctr] ;
87            if (method.getDeclaringClass() != Object.class)
88                if (!throwsRemote( method ))
89                    return false ;
90        }
91
92        return true ;
93    }
94
95    private static boolean throwsRemote( Method method )
96    {
97        Class[] exceptionTypes = method.getExceptionTypes() ;
98
99        // Check that some exceptionType is a subclass of RemoteException
100        for (int ctr=0; ctr<exceptionTypes.length; ctr++) {
101            Class exceptionType = exceptionTypes[ctr] ;
102            if (java.rmi.RemoteException.class.isAssignableFrom( exceptionType ))
103                return true ;
104        }
105
106        return false ;
107    }
108
109    public interface ReaderWriter
110    {
111        Object read( InputStream is ) ;
112
113        void write( OutputStream os, Object value ) ;
114    }
115
116    abstract static class ReaderWriterBase implements ReaderWriter
117    {
118        String name ;
119
120        public ReaderWriterBase( String name )
121        {
122            this.name = name ;
123        }
124
125        public String toString()
126        {
127            return "ReaderWriter[" + name + "]" ;
128        }
129    }
130
131    private static ReaderWriter booleanRW = new ReaderWriterBase( "boolean" )
132    {
133        public Object read( InputStream is )
134        {
135            boolean value = is.read_boolean() ;
136            return new Boolean( value ) ;
137        }
138
139        public void write( OutputStream os, Object value )
140        {
141            Boolean val = (Boolean)value ;
142            os.write_boolean( val.booleanValue() ) ;
143        }
144    } ;
145
146    private static ReaderWriter byteRW = new ReaderWriterBase( "byte" )
147    {
148        public Object read( InputStream is )
149        {
150            byte value = is.read_octet() ;
151            return new Byte( value ) ;
152        }
153
154        public void write( OutputStream os, Object value )
155        {
156            Byte val = (Byte)value ;
157            os.write_octet( val.byteValue() ) ;
158        }
159    } ;
160
161    private static ReaderWriter charRW = new ReaderWriterBase( "char" )
162    {
163        public Object read( InputStream is )
164        {
165            char value = is.read_wchar() ;
166            return new Character( value ) ;
167        }
168
169        public void write( OutputStream os, Object value )
170        {
171            Character val = (Character)value ;
172            os.write_wchar( val.charValue() ) ;
173        }
174    } ;
175
176    private static ReaderWriter shortRW = new ReaderWriterBase( "short" )
177    {
178        public Object read( InputStream is )
179        {
180            short value = is.read_short() ;
181            return new Short( value ) ;
182        }
183
184        public void write( OutputStream os, Object value )
185        {
186            Short val = (Short)value ;
187            os.write_short( val.shortValue() ) ;
188        }
189    } ;
190
191    private static ReaderWriter intRW = new ReaderWriterBase( "int" )
192    {
193        public Object read( InputStream is )
194        {
195            int value = is.read_long() ;
196            return new Integer( value ) ;
197        }
198
199        public void write( OutputStream os, Object value )
200        {
201            Integer val = (Integer)value ;
202            os.write_long( val.intValue() ) ;
203        }
204    } ;
205
206    private static ReaderWriter longRW = new ReaderWriterBase( "long" )
207    {
208        public Object read( InputStream is )
209        {
210            long value = is.read_longlong() ;
211            return new Long( value ) ;
212        }
213
214        public void write( OutputStream os, Object value )
215        {
216            Long val = (Long)value ;
217            os.write_longlong( val.longValue() ) ;
218        }
219    } ;
220
221    private static ReaderWriter floatRW = new ReaderWriterBase( "float" )
222    {
223        public Object read( InputStream is )
224        {
225            float value = is.read_float() ;
226            return new Float( value ) ;
227        }
228
229        public void write( OutputStream os, Object value )
230        {
231            Float val = (Float)value ;
232            os.write_float( val.floatValue() ) ;
233        }
234    } ;
235
236    private static ReaderWriter doubleRW = new ReaderWriterBase( "double" )
237    {
238        public Object read( InputStream is )
239        {
240            double value = is.read_double() ;
241            return new Double( value ) ;
242        }
243
244        public void write( OutputStream os, Object value )
245        {
246            Double val = (Double)value ;
247            os.write_double( val.doubleValue() ) ;
248        }
249    } ;
250
251    private static ReaderWriter corbaObjectRW = new ReaderWriterBase(
252        "org.omg.CORBA.Object" )
253    {
254        public Object read( InputStream is )
255        {
256            return is.read_Object() ;
257        }
258
259        public void write( OutputStream os, Object value )
260        {
261            os.write_Object( (org.omg.CORBA.Object)value ) ;
262        }
263    } ;
264
265    private static ReaderWriter anyRW = new ReaderWriterBase( "any" )
266    {
267        public Object read( InputStream is )
268        {
269            return Util.readAny(is) ;
270        }
271
272        public void write( OutputStream os, Object value )
273        {
274            Util.writeAny( os, value ) ;
275        }
276    } ;
277
278    private static ReaderWriter abstractInterfaceRW = new ReaderWriterBase(
279        "abstract_interface"  )
280    {
281        public Object read( InputStream is )
282        {
283            return is.read_abstract_interface() ;
284        }
285
286        public void write( OutputStream os, Object value )
287        {
288            Util.writeAbstractObject( os, value ) ;
289        }
290    } ;
291
292
293    public static ReaderWriter makeReaderWriter( final Class cls )
294    {
295        if (cls.equals( boolean.class ))
296            return booleanRW ;
297        else if (cls.equals( byte.class ))
298            return byteRW ;
299        else if (cls.equals( char.class ))
300            return charRW ;
301        else if (cls.equals( short.class ))
302            return shortRW ;
303        else if (cls.equals( int.class ))
304            return intRW ;
305        else if (cls.equals( long.class ))
306            return longRW ;
307        else if (cls.equals( float.class ))
308            return floatRW ;
309        else if (cls.equals( double.class ))
310            return doubleRW ;
311        else if (java.rmi.Remote.class.isAssignableFrom( cls ))
312            return new ReaderWriterBase( "remote(" + cls.getName() + ")" )
313            {
314                public Object read( InputStream is )
315                {
316                    return PortableRemoteObject.narrow( is.read_Object(),
317                        cls ) ;
318                }
319
320                public void write( OutputStream os, Object value )
321                {
322                    Util.writeRemoteObject( os, value ) ;
323                }
324            } ;
325        else if (cls.equals(org.omg.CORBA.Object.class))
326            return corbaObjectRW ;
327        else if (org.omg.CORBA.Object.class.isAssignableFrom( cls ))
328            return new ReaderWriterBase( "org.omg.CORBA.Object(" +
329                cls.getName() + ")" )
330            {
331                public Object read( InputStream is )
332                {
333                    return is.read_Object(cls) ;
334                }
335
336                public void write( OutputStream os, Object value )
337                {
338                    os.write_Object( (org.omg.CORBA.Object)value ) ;
339                }
340            } ;
341        else if (isAnyClass(cls))
342            return anyRW ;
343        else if (isAbstractInterface(cls))
344            return abstractInterfaceRW ;
345
346        // For anything else, just read it as a value type.
347        return new ReaderWriterBase( "value(" + cls.getName() + ")" )
348        {
349            public Object read( InputStream is )
350            {
351                return is.read_value(cls) ;
352            }
353
354            public void write( OutputStream os, Object value )
355            {
356                os.write_value( (Serializable)value, cls ) ;
357            }
358        } ;
359    }
360
361    public DynamicMethodMarshallerImpl( Method method )
362    {
363        this.method = method ;
364        ehandler = new ExceptionHandlerImpl( method.getExceptionTypes() ) ;
365        needsArgumentCopy = false ;
366
367        Class[] argTypes = method.getParameterTypes() ;
368        hasArguments = argTypes.length > 0 ;
369        if (hasArguments) {
370            argRWs = new ReaderWriter[ argTypes.length ] ;
371            for (int ctr=0; ctr<argTypes.length; ctr++ ) {
372                // This could be further optimized to avoid
373                // copying if argTypes contains at most one
374                // immutable object type.
375                if (!argTypes[ctr].isPrimitive())
376                    needsArgumentCopy = true ;
377                argRWs[ctr] = makeReaderWriter( argTypes[ctr] ) ;
378            }
379        }
380
381        Class resultType = method.getReturnType() ;
382        needsResultCopy = false ;
383        hasVoidResult = resultType.equals( void.class ) ;
384        if (!hasVoidResult) {
385            needsResultCopy = !resultType.isPrimitive() ;
386            resultRW = makeReaderWriter( resultType ) ;
387        }
388    }
389
390    public Method getMethod()
391    {
392        return method ;
393    }
394
395    public Object[] copyArguments( Object[] args,
396        ORB orb ) throws RemoteException
397    {
398        if (needsArgumentCopy)
399            return Util.copyObjects( args, orb ) ;
400        else
401            return args ;
402    }
403
404    public Object[] readArguments( InputStream is )
405    {
406        Object[] result = null ;
407
408        if (hasArguments) {
409            result = new Object[ argRWs.length ] ;
410            for (int ctr=0; ctr<argRWs.length; ctr++ )
411                result[ctr] = argRWs[ctr].read( is ) ;
412        }
413
414        return result ;
415    }
416
417    public void writeArguments( OutputStream os, Object[] args )
418    {
419        if (hasArguments) {
420            if (args.length != argRWs.length)
421                throw new IllegalArgumentException( "Expected " + argRWs.length +
422                    " arguments, but got " + args.length + " arguments." ) ;
423
424            for (int ctr=0; ctr<argRWs.length; ctr++ )
425                argRWs[ctr].write( os, args[ctr] ) ;
426        }
427    }
428
429    public Object copyResult( Object result, ORB orb ) throws RemoteException
430    {
431        if (needsResultCopy)
432            return Util.copyObject( result, orb ) ;
433        else
434            return result ;
435    }
436
437    public Object readResult( InputStream is )
438    {
439        if (hasVoidResult)
440            return null ;
441        else
442            return resultRW.read( is ) ;
443    }
444
445    public void writeResult( OutputStream os, Object result )
446    {
447        if (!hasVoidResult)
448            resultRW.write( os, result ) ;
449    }
450
451    public boolean isDeclaredException( Throwable thr )
452    {
453        return ehandler.isDeclaredException( thr.getClass() ) ;
454    }
455
456    public void writeException( OutputStream os, Exception ex )
457    {
458        ehandler.writeException( os, ex ) ;
459    }
460
461    public Exception readException( ApplicationException ae )
462    {
463        return ehandler.readException( ae ) ;
464    }
465}
466