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             return is.read_boolean() ;
 136         }
 137 
 138         public void write( OutputStream os, Object value )
 139         {
 140             Boolean val = (Boolean)value ;
 141             os.write_boolean( val.booleanValue() ) ;
 142         }
 143     } ;
 144 
 145     private static ReaderWriter byteRW = new ReaderWriterBase( "byte" )
 146     {
 147         public Object read( InputStream is )
 148         {
 149             byte value = is.read_octet() ;
 150             return new Byte( value ) ;
 151         }
 152 
 153         public void write( OutputStream os, Object value )
 154         {
 155             Byte val = (Byte)value ;
 156             os.write_octet( val.byteValue() ) ;
 157         }
 158     } ;
 159 
 160     private static ReaderWriter charRW = new ReaderWriterBase( "char" )
 161     {
 162         public Object read( InputStream is )
 163         {
 164             char value = is.read_wchar() ;
 165             return new Character( value ) ;
 166         }
 167 
 168         public void write( OutputStream os, Object value )
 169         {
 170             Character val = (Character)value ;
 171             os.write_wchar( val.charValue() ) ;
 172         }
 173     } ;
 174 
 175     private static ReaderWriter shortRW = new ReaderWriterBase( "short" )
 176     {
 177         public Object read( InputStream is )
 178         {
 179             short value = is.read_short() ;
 180             return new Short( value ) ;
 181         }
 182 
 183         public void write( OutputStream os, Object value )
 184         {
 185             Short val = (Short)value ;
 186             os.write_short( val.shortValue() ) ;
 187         }
 188     } ;
 189 
 190     private static ReaderWriter intRW = new ReaderWriterBase( "int" )
 191     {
 192         public Object read( InputStream is )
 193         {
 194             int value = is.read_long() ;
 195             return new Integer( value ) ;
 196         }
 197 
 198         public void write( OutputStream os, Object value )
 199         {
 200             Integer val = (Integer)value ;
 201             os.write_long( val.intValue() ) ;
 202         }
 203     } ;
 204 
 205     private static ReaderWriter longRW = new ReaderWriterBase( "long" )
 206     {
 207         public Object read( InputStream is )
 208         {
 209             long value = is.read_longlong() ;
 210             return new Long( value ) ;
 211         }
 212 
 213         public void write( OutputStream os, Object value )
 214         {
 215             Long val = (Long)value ;
 216             os.write_longlong( val.longValue() ) ;
 217         }
 218     } ;
 219 
 220     private static ReaderWriter floatRW = new ReaderWriterBase( "float" )
 221     {
 222         public Object read( InputStream is )
 223         {
 224             float value = is.read_float() ;
 225             return new Float( value ) ;
 226         }
 227 
 228         public void write( OutputStream os, Object value )
 229         {
 230             Float val = (Float)value ;
 231             os.write_float( val.floatValue() ) ;
 232         }
 233     } ;
 234 
 235     private static ReaderWriter doubleRW = new ReaderWriterBase( "double" )
 236     {
 237         public Object read( InputStream is )
 238         {
 239             double value = is.read_double() ;
 240             return new Double( value ) ;
 241         }
 242 
 243         public void write( OutputStream os, Object value )
 244         {
 245             Double val = (Double)value ;
 246             os.write_double( val.doubleValue() ) ;
 247         }
 248     } ;
 249 
 250     private static ReaderWriter corbaObjectRW = new ReaderWriterBase(
 251         "org.omg.CORBA.Object" )
 252     {
 253         public Object read( InputStream is )
 254         {
 255             return is.read_Object() ;
 256         }
 257 
 258         public void write( OutputStream os, Object value )
 259         {
 260             os.write_Object( (org.omg.CORBA.Object)value ) ;
 261         }
 262     } ;
 263 
 264     private static ReaderWriter anyRW = new ReaderWriterBase( "any" )
 265     {
 266         public Object read( InputStream is )
 267         {
 268             return Util.readAny(is) ;
 269         }
 270 
 271         public void write( OutputStream os, Object value )
 272         {
 273             Util.writeAny( os, value ) ;
 274         }
 275     } ;
 276 
 277     private static ReaderWriter abstractInterfaceRW = new ReaderWriterBase(
 278         "abstract_interface"  )
 279     {
 280         public Object read( InputStream is )
 281         {
 282             return is.read_abstract_interface() ;
 283         }
 284 
 285         public void write( OutputStream os, Object value )
 286         {
 287             Util.writeAbstractObject( os, value ) ;
 288         }
 289     } ;
 290 
 291 
 292     public static ReaderWriter makeReaderWriter( final Class cls )
 293     {
 294         if (cls.equals( boolean.class ))
 295             return booleanRW ;
 296         else if (cls.equals( byte.class ))
 297             return byteRW ;
 298         else if (cls.equals( char.class ))
 299             return charRW ;
 300         else if (cls.equals( short.class ))
 301             return shortRW ;
 302         else if (cls.equals( int.class ))
 303             return intRW ;
 304         else if (cls.equals( long.class ))
 305             return longRW ;
 306         else if (cls.equals( float.class ))
 307             return floatRW ;
 308         else if (cls.equals( double.class ))
 309             return doubleRW ;
 310         else if (java.rmi.Remote.class.isAssignableFrom( cls ))
 311             return new ReaderWriterBase( "remote(" + cls.getName() + ")" )
 312             {
 313                 public Object read( InputStream is )
 314                 {
 315                     return PortableRemoteObject.narrow( is.read_Object(),
 316                         cls ) ;
 317                 }
 318 
 319                 public void write( OutputStream os, Object value )
 320                 {
 321                     Util.writeRemoteObject( os, value ) ;
 322                 }
 323             } ;
 324         else if (cls.equals(org.omg.CORBA.Object.class))
 325             return corbaObjectRW ;
 326         else if (org.omg.CORBA.Object.class.isAssignableFrom( cls ))
 327             return new ReaderWriterBase( "org.omg.CORBA.Object(" +
 328                 cls.getName() + ")" )
 329             {
 330                 public Object read( InputStream is )
 331                 {
 332                     return is.read_Object(cls) ;
 333                 }
 334 
 335                 public void write( OutputStream os, Object value )
 336                 {
 337                     os.write_Object( (org.omg.CORBA.Object)value ) ;
 338                 }
 339             } ;
 340         else if (isAnyClass(cls))
 341             return anyRW ;
 342         else if (isAbstractInterface(cls))
 343             return abstractInterfaceRW ;
 344 
 345         // For anything else, just read it as a value type.
 346         return new ReaderWriterBase( "value(" + cls.getName() + ")" )
 347         {
 348             public Object read( InputStream is )
 349             {
 350                 return is.read_value(cls) ;
 351             }
 352 
 353             public void write( OutputStream os, Object value )
 354             {
 355                 os.write_value( (Serializable)value, cls ) ;
 356             }
 357         } ;
 358     }
 359 
 360     public DynamicMethodMarshallerImpl( Method method )
 361     {
 362         this.method = method ;
 363         ehandler = new ExceptionHandlerImpl( method.getExceptionTypes() ) ;
 364         needsArgumentCopy = false ;
 365 
 366         Class[] argTypes = method.getParameterTypes() ;
 367         hasArguments = argTypes.length > 0 ;
 368         if (hasArguments) {
 369             argRWs = new ReaderWriter[ argTypes.length ] ;
 370             for (int ctr=0; ctr<argTypes.length; ctr++ ) {
 371                 // This could be further optimized to avoid
 372                 // copying if argTypes contains at most one
 373                 // immutable object type.
 374                 if (!argTypes[ctr].isPrimitive())
 375                     needsArgumentCopy = true ;
 376                 argRWs[ctr] = makeReaderWriter( argTypes[ctr] ) ;
 377             }
 378         }
 379 
 380         Class resultType = method.getReturnType() ;
 381         needsResultCopy = false ;
 382         hasVoidResult = resultType.equals( void.class ) ;
 383         if (!hasVoidResult) {
 384             needsResultCopy = !resultType.isPrimitive() ;
 385             resultRW = makeReaderWriter( resultType ) ;
 386         }
 387     }
 388 
 389     public Method getMethod()
 390     {
 391         return method ;
 392     }
 393 
 394     public Object[] copyArguments( Object[] args,
 395         ORB orb ) throws RemoteException
 396     {
 397         if (needsArgumentCopy)
 398             return Util.copyObjects( args, orb ) ;
 399         else
 400             return args ;
 401     }
 402 
 403     public Object[] readArguments( InputStream is )
 404     {
 405         Object[] result = null ;
 406 
 407         if (hasArguments) {
 408             result = new Object[ argRWs.length ] ;
 409             for (int ctr=0; ctr<argRWs.length; ctr++ )
 410                 result[ctr] = argRWs[ctr].read( is ) ;
 411         }
 412 
 413         return result ;
 414     }
 415 
 416     public void writeArguments( OutputStream os, Object[] args )
 417     {
 418         if (hasArguments) {
 419             if (args.length != argRWs.length)
 420                 throw new IllegalArgumentException( "Expected " + argRWs.length +
 421                     " arguments, but got " + args.length + " arguments." ) ;
 422 
 423             for (int ctr=0; ctr<argRWs.length; ctr++ )
 424                 argRWs[ctr].write( os, args[ctr] ) ;
 425         }
 426     }
 427 
 428     public Object copyResult( Object result, ORB orb ) throws RemoteException
 429     {
 430         if (needsResultCopy)
 431             return Util.copyObject( result, orb ) ;
 432         else
 433             return result ;
 434     }
 435 
 436     public Object readResult( InputStream is )
 437     {
 438         if (hasVoidResult)
 439             return null ;
 440         else
 441             return resultRW.read( is ) ;
 442     }
 443 
 444     public void writeResult( OutputStream os, Object result )
 445     {
 446         if (!hasVoidResult)
 447             resultRW.write( os, result ) ;
 448     }
 449 
 450     public boolean isDeclaredException( Throwable thr )
 451     {
 452         return ehandler.isDeclaredException( thr.getClass() ) ;
 453     }
 454 
 455     public void writeException( OutputStream os, Exception ex )
 456     {
 457         ehandler.writeException( os, ex ) ;
 458     }
 459 
 460     public Exception readException( ApplicationException ae )
 461     {
 462         return ehandler.readException( ae ) ;
 463     }
 464 }