corba/src/share/classes/com/sun/corba/se/impl/presentation/rmi/IDLTypesUtil_save.sjava
changeset 19494 684292d0e03a
parent 19493 f2028bc02f0c
parent 19257 30a1d677a20c
child 19495 0a4337ec0592
equal deleted inserted replaced
19493:f2028bc02f0c 19494:684292d0e03a
     1 /*
       
     2  * Copyright (c) 2004, 2012, 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.lang.reflect.Method;
       
    29 import java.lang.reflect.Field;
       
    30 import java.util.Set;
       
    31 import java.util.HashSet;
       
    32 import java.util.Iterator;
       
    33 
       
    34 /**
       
    35  * Utility class for testing RMI/IDL Types as defined in
       
    36  * Section 1.2 of The Java Language to IDL Mapping.  Note that
       
    37  * these are static checks only.  Runtime checks, such as those
       
    38  * described in Section 1.2.3, #3, are not covered.
       
    39  */
       
    40 public class IDLTypesUtil {
       
    41 
       
    42     public static final String JAVA_GET_PROPERTY_PREFIX = "get";
       
    43     public static final String JAVA_SET_PROPERTY_PREFIX = "set";
       
    44     public static final String JAVA_IS_PROPERTY_PREFIX  = "is";
       
    45 
       
    46     public static final int VALID_TYPE   = 0;
       
    47     public static final int INVALID_TYPE = 1;
       
    48 
       
    49     /**
       
    50      * Validate a class to ensure it conforms to the rules for a
       
    51      * Java RMI/IIOP interface.
       
    52      *
       
    53      * @throws IDLTypeException if not a valid RMI/IIOP interface.
       
    54      */
       
    55     public void validateRemoteInterface(Class c) throws IDLTypeException
       
    56     {
       
    57         if( c == null ) {
       
    58             throw new IllegalArgumentException();
       
    59         } 
       
    60 
       
    61         if( !c.isInterface() ) {
       
    62             String msg = "Class " + c + " must be a java interface.";
       
    63             throw new IDLTypeException(msg);
       
    64         }
       
    65 
       
    66         if( !java.rmi.Remote.class.isAssignableFrom(c) ) {
       
    67             String msg = "Class " + c + " must extend java.rmi.Remote, " +
       
    68                 "either directly or indirectly.";
       
    69             throw new IDLTypeException(msg);
       
    70         }
       
    71 
       
    72         // Get all methods, including super-interface methods.
       
    73         Method[] methods = c.getMethods();
       
    74         
       
    75         for(int i = 0; i < methods.length; i++) {
       
    76             Method next = methods[i];
       
    77             validateExceptions(next);
       
    78         }
       
    79         
       
    80 	// Removed because of bug 4989053
       
    81         // validateDirectInterfaces(c);
       
    82         validateConstants(c);
       
    83 
       
    84         return;
       
    85     }
       
    86 
       
    87     public boolean isRemoteInterface(Class c)     
       
    88     {
       
    89         boolean remoteInterface = true;
       
    90         try {
       
    91             validateRemoteInterface(c);
       
    92         } catch(IDLTypeException ite) {
       
    93             remoteInterface = false;
       
    94         }
       
    95 
       
    96         return remoteInterface;
       
    97     }
       
    98 
       
    99     /**
       
   100      * Section 1.2.2 Primitive Types
       
   101      */ 
       
   102     public boolean isPrimitive(Class c) 
       
   103     {
       
   104         if( c == null ) {
       
   105             throw new IllegalArgumentException();
       
   106         } 
       
   107 
       
   108         return c.isPrimitive();
       
   109     }
       
   110 
       
   111     /**
       
   112      * Section 1.2.4
       
   113      */
       
   114     public boolean isValue(Class c) 
       
   115     {
       
   116         if( c == null ) {
       
   117             throw new IllegalArgumentException();
       
   118         } 
       
   119 
       
   120         return 
       
   121             (!c.isInterface() &&
       
   122              java.io.Serializable.class.isAssignableFrom(c) &&
       
   123              !java.rmi.Remote.class.isAssignableFrom(c));
       
   124     }
       
   125 
       
   126     /**
       
   127      * Section 1.2.5
       
   128      */
       
   129     public boolean isArray(Class c) 
       
   130     {
       
   131         boolean arrayType = false;
       
   132 
       
   133         if( c == null ) {
       
   134             throw new IllegalArgumentException();
       
   135         } 
       
   136 
       
   137         if( c.isArray() ) {
       
   138             Class componentType = c.getComponentType();
       
   139             arrayType =
       
   140                 (isPrimitive(componentType) || isRemoteInterface(componentType) ||
       
   141                  isEntity(componentType) || isException(componentType) || 
       
   142 		 isValue(componentType) || isObjectReference(componentType) );
       
   143         }
       
   144 
       
   145         return arrayType;
       
   146     }
       
   147 
       
   148     /**
       
   149      * Section 1.2.6
       
   150      */
       
   151     public boolean isException(Class c) 
       
   152     {
       
   153         if( c == null ) {
       
   154             throw new IllegalArgumentException();
       
   155         } 
       
   156 
       
   157         // Must be a checked exception, not including RemoteException or
       
   158         // its subclasses.
       
   159         return isCheckedException(c) && !isRemoteException(c) && isValue(c);
       
   160     }
       
   161 
       
   162     public boolean isRemoteException(Class c)
       
   163     {
       
   164         if( c == null ) {
       
   165             throw new IllegalArgumentException();
       
   166         } 
       
   167 
       
   168 	return java.rmi.RemoteException.class.isAssignableFrom(c) ;
       
   169     }
       
   170 
       
   171     public boolean isCheckedException(Class c) 
       
   172     {
       
   173         if( c == null ) {
       
   174             throw new IllegalArgumentException();
       
   175         } 
       
   176 
       
   177         return Throwable.class.isAssignableFrom(c) &&
       
   178             !RuntimeException.class.isAssignableFrom(c) &&
       
   179             !Error.class.isAssignableFrom(c) ;
       
   180     }
       
   181 
       
   182     /**
       
   183      * Section 1.2.7
       
   184      */ 
       
   185     public boolean isObjectReference(Class c) 
       
   186     {
       
   187         if( c == null ) {
       
   188             throw new IllegalArgumentException();
       
   189         } 
       
   190 
       
   191         return (c.isInterface() && 
       
   192                 org.omg.CORBA.Object.class.isAssignableFrom(c));
       
   193     }
       
   194 
       
   195     /**
       
   196      * Section 1.2.8
       
   197      */ 
       
   198     public boolean isEntity(Class c)
       
   199     {
       
   200         if( c == null ) {
       
   201             throw new IllegalArgumentException();
       
   202         } 
       
   203 
       
   204         Class superClass = c.getSuperclass();
       
   205         return (!c.isInterface() &&
       
   206                 (superClass != null) && 
       
   207                 (org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(c)));
       
   208     }
       
   209 
       
   210     public String javaPropertyPrefixToIDL( String javaPrefix )
       
   211     {
       
   212 	return "_" + javaPrefix + "_" ;
       
   213     }
       
   214 
       
   215     /**
       
   216      * Return the property type if given method is legal property accessor as defined in 
       
   217      * Section 1.3.4.3 of Java2IDL spec.  Result is one of: JAVA_GET_PROPERTY_PREFIX,
       
   218      * JAVA_SET_PROPERTY_PREFIX, JAVA_IS_PROPERTY_PREFIX.
       
   219      */
       
   220     public String propertyAccessorMethodType(Method m, Class c) {
       
   221         
       
   222         String methodName = m.getName();
       
   223         Class returnType  = m.getReturnType();
       
   224         Class[] parameters = m.getParameterTypes();
       
   225         Class[] exceptionTypes = m.getExceptionTypes();
       
   226         String propertyType = null;
       
   227 
       
   228         if( methodName.startsWith(JAVA_GET_PROPERTY_PREFIX) ) {
       
   229 
       
   230             if((parameters.length == 0) && (returnType != Void.TYPE) &&
       
   231 		!hasCorrespondingReadProperty(m, c, JAVA_IS_PROPERTY_PREFIX) {
       
   232                 propertyType = JAVA_GET_PROPERTY_PREFIX;
       
   233             }
       
   234            
       
   235         } else if( methodName.startsWith(JAVA_SET_PROPERTY_PREFIX) ) {
       
   236             
       
   237             if((returnType == Void.TYPE) && (parameters.length == 1)) {
       
   238                 if (hasCorrespondingReadProperty(m, c, JAVA_GET_PROPERTY_PREFIX) ||
       
   239                     hasCorrespondingReadProperty(m, c, JAVA_IS_PROPERTY_PREFIX)) {
       
   240                     propertyType = JAVA_SET_PROPERTY_PREFIX;
       
   241                 }
       
   242             }
       
   243 
       
   244         } else if( methodName.startsWith(JAVA_IS_PROPERTY_PREFIX) ) {
       
   245             if((parameters.length == 0) && (returnType == Boolean.TYPE)) {
       
   246                 propertyType = JAVA_IS_PROPERTY_PREFIX;             
       
   247             }
       
   248         }
       
   249 
       
   250         // Some final checks that apply to all properties.  
       
   251         if( propertyType != null ) {
       
   252             if(!validPropertyExceptions(m) || 
       
   253                (methodName.length() <= propertyType.length())) {
       
   254                 propertyType = null;
       
   255             }                                       
       
   256         }
       
   257 
       
   258         return propertyType ;
       
   259     }
       
   260 
       
   261     private boolean hasCorrespondingReadProperty
       
   262         (Method writeProperty, Class c, String readPropertyPrefix) {
       
   263 
       
   264         String writePropertyMethodName = writeProperty.getName();
       
   265         Class[] writePropertyParameters = writeProperty.getParameterTypes();
       
   266         boolean foundReadProperty = false;
       
   267 
       
   268         try {            
       
   269             // Look for a valid corresponding Read property
       
   270             String readPropertyMethodName = 
       
   271                 writePropertyMethodName.replaceFirst
       
   272                     (JAVA_SET_PROPERTY_PREFIX, readPropertyPrefix);
       
   273             Method readPropertyMethod = c.getMethod(readPropertyMethodName, 
       
   274                                                     new Class[] {});
       
   275             foundReadProperty = 
       
   276                 ((propertyAccessorMethodType(readPropertyMethod, c) != null) &&
       
   277                  (readPropertyMethod.getReturnType() == 
       
   278                    writePropertyParameters[0]));
       
   279         } catch(Exception e) {
       
   280             // ignore. this means we didn't find a corresponding get property.
       
   281         }
       
   282 
       
   283         return foundReadProperty;
       
   284     }
       
   285 
       
   286     public String getAttributeNameForProperty(String propertyName) {
       
   287         String attributeName = null;
       
   288         String prefix = null;
       
   289 
       
   290         if( propertyName.startsWith(JAVA_GET_PROPERTY_PREFIX) ) {
       
   291             prefix = JAVA_GET_PROPERTY_PREFIX;           
       
   292         } else if( propertyName.startsWith(JAVA_SET_PROPERTY_PREFIX) ) {
       
   293             prefix = JAVA_SET_PROPERTY_PREFIX;
       
   294         } else if( propertyName.startsWith(JAVA_IS_PROPERTY_PREFIX) ) {
       
   295             prefix = JAVA_IS_PROPERTY_PREFIX;
       
   296         }
       
   297 
       
   298         if( (prefix != null) && (prefix.length() < propertyName.length()) ) {
       
   299             String remainder = propertyName.substring(prefix.length());
       
   300             if( (remainder.length() >= 2) && 
       
   301                 Character.isUpperCase(remainder.charAt(0)) &&
       
   302                 Character.isUpperCase(remainder.charAt(1)) ) {
       
   303                 // don't set the first letter to lower-case if the 
       
   304                 // first two are upper-case
       
   305                 attributeName = remainder;
       
   306             } else {
       
   307                 attributeName = Character.toLowerCase(remainder.charAt(0)) +
       
   308                     remainder.substring(1);
       
   309             }
       
   310         }
       
   311 
       
   312         return attributeName;
       
   313     }
       
   314 
       
   315     /**
       
   316      * Return IDL Type name for primitive types as defined in 
       
   317      * Section 1.3.3 of Java2IDL spec or null if not a primitive type.
       
   318      */ 
       
   319     public IDLType getPrimitiveIDLTypeMapping(Class c) {
       
   320                
       
   321         if( c == null ) {
       
   322             throw new IllegalArgumentException();
       
   323         } 
       
   324 
       
   325         if( c.isPrimitive() ) {            
       
   326             if( c == Void.TYPE ) {
       
   327 		return new IDLType( c, "void" ) ;
       
   328             } else if( c == Boolean.TYPE ) {
       
   329 		return new IDLType( c, "boolean" ) ;
       
   330             } else if( c == Character.TYPE ) {
       
   331 		return new IDLType( c, "wchar" ) ;
       
   332             } else if( c == Byte.TYPE ) {
       
   333 		return new IDLType( c, "octet" ) ;
       
   334             } else if( c == Short.TYPE ) {
       
   335 		return new IDLType( c, "short" ) ;
       
   336             } else if( c == Integer.TYPE ) {
       
   337 		return new IDLType( c, "long" ) ;
       
   338             } else if( c == Long.TYPE ) {
       
   339 		return new IDLType( c, "long_long" ) ;
       
   340             } else if( c == Float.TYPE ) {
       
   341 		return new IDLType( c, "float" ) ;
       
   342             } else if( c == Double.TYPE ) {
       
   343 		return new IDLType( c, "double" ) ;
       
   344             }
       
   345         }
       
   346         
       
   347         return null;
       
   348     }
       
   349 
       
   350     /**
       
   351      * Return IDL Type name for special case type mappings as defined in
       
   352      * Table 1-1 of Java2IDL spec or null if given class is not a special
       
   353      * type.
       
   354      */
       
   355     public IDLType getSpecialCaseIDLTypeMapping(Class c) {
       
   356 
       
   357         if( c == null ) {
       
   358             throw new IllegalArgumentException();
       
   359         } 
       
   360 
       
   361         if( c == java.lang.Object.class ) {
       
   362 	    return new IDLType( c, new String[] { "java", "lang" },
       
   363 		"Object" ) ;
       
   364         } else if( c == java.lang.String.class ) {
       
   365 	    return new IDLType( c, new String[] { "CORBA" },
       
   366 		"WStringValue" ) ;
       
   367         } else if( c == java.lang.Class.class ) {
       
   368 	    return new IDLType( c, new String[] { "javax", "rmi", "CORBA" },
       
   369 		"ClassDesc" ) ;
       
   370         } else if( c == java.io.Serializable.class ) {
       
   371 	    return new IDLType( c, new String[] { "java", "io" },
       
   372 		"Serializable" ) ;
       
   373         } else if( c == java.io.Externalizable.class ) {
       
   374 	    return new IDLType( c, new String[] { "java", "io" },
       
   375 		"Externalizable" ) ;
       
   376         } else if( c == java.rmi.Remote.class ) {
       
   377 	    return new IDLType( c, new String[] { "java", "rmi" },
       
   378 		"Remote" ) ;
       
   379         } else if( c == org.omg.CORBA.Object.class ) {
       
   380 	    return new IDLType( c, "Object" ) ;
       
   381         } else {
       
   382             return null;
       
   383         }
       
   384     }
       
   385 
       
   386     /**
       
   387      * Implements 1.2.3 #2 and #4
       
   388      */
       
   389     private void validateExceptions(Method method) throws IDLTypeException {
       
   390         
       
   391         Class[] exceptions = method.getExceptionTypes();
       
   392 
       
   393         boolean declaresRemoteExceptionOrSuperClass = false;
       
   394 
       
   395         // Section 1.2.3, #2
       
   396         for(int eIndex = 0; eIndex < exceptions.length; eIndex++) {
       
   397             Class exception = exceptions[eIndex];
       
   398             if( isRemoteExceptionOrSuperClass(exception) ) {
       
   399                 declaresRemoteExceptionOrSuperClass = true;
       
   400                 break;
       
   401             }
       
   402         }
       
   403 
       
   404         if( !declaresRemoteExceptionOrSuperClass ) {
       
   405             String msg = "Method '" + method + "' must throw at least one " +
       
   406                 "exception of type java.rmi.RemoteException or one of its " +
       
   407                 "super-classes";
       
   408             throw new IDLTypeException(msg);
       
   409         } 
       
   410 
       
   411         // Section 1.2.3, #4
       
   412 	// See also bug 4972402
       
   413 	// For all exceptions E in exceptions, 
       
   414 	// (isCheckedException(E) => (isValue(E) || RemoteException.isAssignableFrom( E ) )
       
   415         for(int eIndex = 0; eIndex < exceptions.length; eIndex++) {
       
   416             Class exception = exceptions[eIndex];
       
   417 
       
   418 	    if (isCheckedException(exception) && !isValue(exception) && 
       
   419 		!isRemoteException(exception)) 
       
   420 	    {
       
   421 		String msg = "Exception '" + exception + "' on method '" +
       
   422 		    method + "' is not a allowed RMI/IIOP exception type";
       
   423 		throw new IDLTypeException(msg);
       
   424             }
       
   425         }
       
   426 
       
   427         return;
       
   428     }
       
   429 
       
   430     /**
       
   431      * Returns true if the method's throw clause conforms to the exception 
       
   432      * restrictions for properties as defined in Section 1.3.4.3 of 
       
   433      * Java2IDL spec.  This means that for all exceptions E declared on the
       
   434      * method, E isChecked => RemoteException.isAssignableFrom( E ). 
       
   435      */
       
   436     private boolean validPropertyExceptions(Method method) 
       
   437     {
       
   438         Class[] exceptions = method.getExceptionTypes();
       
   439          
       
   440         for(int eIndex = 0; eIndex < exceptions.length; eIndex++) {
       
   441             Class exception = exceptions[eIndex];
       
   442 
       
   443 	    if (isCheckedException(exception) && !isRemoteException(exception)) 
       
   444 		return false ;
       
   445         }
       
   446 
       
   447         return true;
       
   448     }
       
   449 
       
   450     /**
       
   451      * Implements Section 1.2.3, #2.  
       
   452      */
       
   453     private boolean isRemoteExceptionOrSuperClass(Class c) {
       
   454         return 
       
   455             ((c == java.rmi.RemoteException.class) ||
       
   456              (c == java.io.IOException.class) ||
       
   457              (c == java.lang.Exception.class) ||
       
   458              (c == java.lang.Throwable.class));
       
   459     }
       
   460 
       
   461     /**
       
   462      * Implements Section 1.2.3, #5.
       
   463      */ 
       
   464     private void validateDirectInterfaces(Class c) throws IDLTypeException {
       
   465 
       
   466         Class[] directInterfaces = c.getInterfaces();
       
   467 
       
   468         if( directInterfaces.length < 2 ) {
       
   469             return;
       
   470         }
       
   471 
       
   472         Set allMethodNames = new HashSet();
       
   473         Set currentMethodNames = new HashSet();
       
   474 
       
   475         for(int i = 0; i < directInterfaces.length; i++) {
       
   476             Class next = directInterfaces[i];
       
   477             Method[] methods = next.getMethods();
       
   478 
       
   479             // Comparison is based on method names only.  First collect
       
   480             // all methods from current interface, eliminating duplicate
       
   481             // names.
       
   482             currentMethodNames.clear();
       
   483             for(int m = 0; m < methods.length; m++) {
       
   484                 currentMethodNames.add(methods[m].getName());
       
   485             }
       
   486 
       
   487             // Now check each method against list of all unique method
       
   488             // names processed so far.
       
   489             for(Iterator iter=currentMethodNames.iterator(); iter.hasNext();) {
       
   490                 String methodName = (String) iter.next();
       
   491                 if( allMethodNames.contains(methodName) ) {
       
   492                     String msg = "Class " + c + " inherits method " + 
       
   493                         methodName + " from multiple direct interfaces.";
       
   494                     throw new IDLTypeException(msg);
       
   495                 } else {
       
   496                     allMethodNames.add(methodName);
       
   497                 }
       
   498             }
       
   499         }
       
   500 
       
   501         return;
       
   502     }
       
   503 
       
   504     /**
       
   505      * Implements 1.2.3 #6
       
   506      */
       
   507     private void validateConstants(final Class c) 
       
   508         throws IDLTypeException {
       
   509 
       
   510         Field[] fields = null;
       
   511 
       
   512         try {
       
   513             fields = (Field[])
       
   514                 java.security.AccessController.doPrivileged
       
   515                 (new java.security.PrivilegedExceptionAction() {
       
   516                         public java.lang.Object run() throws Exception {
       
   517                             return c.getFields();
       
   518                         }
       
   519                     });
       
   520         } catch(java.security.PrivilegedActionException pae) {
       
   521             IDLTypeException ite = new IDLTypeException();
       
   522             ite.initCause(pae);
       
   523             throw ite;
       
   524         }
       
   525    
       
   526         for(int i = 0; i < fields.length; i++) {
       
   527             Field next = fields[i];
       
   528             Class fieldType = next.getType();
       
   529             if( (fieldType != java.lang.String.class) &&
       
   530                 !isPrimitive(fieldType) ) {
       
   531                 String msg = "Constant field '" + next.getName() + 
       
   532                     "' in class '" + next.getDeclaringClass().getName() + 
       
   533                     "' has invalid type' " + next.getType() + "'. Constants" +
       
   534                     " in RMI/IIOP interfaces can only have primitive" + 
       
   535                     " types and java.lang.String types.";
       
   536                 throw new IDLTypeException(msg);
       
   537             }
       
   538         }
       
   539 
       
   540 
       
   541         return;
       
   542     }
       
   543 
       
   544 }