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 
  26 package com.sun.corba.se.impl.presentation.rmi ;
  27 
  28 import java.io.Serializable ;
  29 import java.io.Externalizable ;
  30 
  31 import javax.rmi.PortableRemoteObject ;
  32 import javax.rmi.CORBA.Util ;
  33 
  34 import org.omg.CORBA.portable.IDLEntity ;
  35 
  36 import org.omg.CORBA_2_3.portable.InputStream ;
  37 import org.omg.CORBA_2_3.portable.OutputStream ;
  38 import org.omg.CORBA.portable.ApplicationException ;
  39 
  40 import java.lang.reflect.Method ;
  41 
  42 import java.rmi.RemoteException ;
  43 
  44 import com.sun.corba.se.spi.orb.ORB ;
  45 
  46 import com.sun.corba.se.spi.presentation.rmi.DynamicMethodMarshaller ;
  47 
  48 public 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 }