001 /* 002 Copyright (C) 2001-2003 Renaud Pawlak. 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.util; 019 020 import java.io.*; 021 import java.util.*; 022 import java.lang.reflect.*; 023 024 /** 025 * This class generates the <code>jac.lib</code> delegators 026 * source-files from the <code>jac.prop</code> file found in the 027 * current directory (exclude all other options). 028 * 029 * @author Renaud Pawlak */ 030 031 public class WrapLib { 032 033 public static String listAsString(List l) { 034 String s="["; 035 for(int i=0;i<l.size();i++) { 036 s=s+l.get(i); 037 if(i+1<l.size()) s=s+","; 038 } 039 return s; 040 } 041 042 /** 043 * The entry point of the wraplib program. 044 * 045 * @param args none arguments are expected (parametrization is done 046 * by the <code>jac.prop</code> file in the current directory -- 047 * user should define the jac.toWrap property as a list of classes 048 * to wrap */ 049 050 public static void main(String[] args) throws Throwable { 051 String propFileName = "jac.prop"; 052 String toAdaptProp = "jac.toWrap"; 053 Properties props; 054 Vector classesToAdapt = new Vector(); 055 /** Try to load a jac.prop file from the current directory */ 056 try { 057 058 FileInputStream fis = new FileInputStream( propFileName ); 059 060 props = new Properties(); 061 props.load( fis ); 062 String prop = props.getProperty(toAdaptProp); 063 064 if ( prop == null ) { 065 System.out.println( "-- ERROR: no property jac.toAdapt found in property file "+propFileName ); 066 System.exit(-1); 067 068 } else { 069 070 StringTokenizer st = new StringTokenizer( prop ); 071 while ( st.hasMoreElements() ) 072 classesToAdapt.add( st.nextElement() ); 073 } 074 075 076 for ( int i = 0; i < classesToAdapt.size(); i++ ) { 077 createDelegator( Class.forName( (String) classesToAdapt.get(i) )); 078 } 079 080 } 081 catch( FileNotFoundException e ) { 082 System.out.println( "-- ERROR: property file "+propFileName+" not found" ); 083 System.exit(-1); 084 } 085 catch( Exception e ) { e.printStackTrace(); } 086 } 087 088 /** 089 * Creates a class that present the same interface that the 090 * original class but that delegates all the work to an instance of 091 * the original class. 092 * 093 * <p>This feature is implemented to be able to easily wrap 094 * libraries that would have been hardly wrappable on the "as is" 095 * classes, for instance the jdk classes (see the -g option of Jac). 096 * 097 * <p>As a result, this method creates a Java source file in the 098 * src/org/objectweb/jac/lib directory of the JAC distribution. This file should 099 * then be compiled as a regular file. 100 * 101 * @param c the original class */ 102 103 protected static void createDelegator( Class c ) { 104 try { 105 System.out.println("-- Generating delegator version of " + c + "."); 106 File f = new File( 107 "src/org/objectweb/jac/lib/" + c.getName().replace('.','/') + ".java" ); 108 if ( f.exists() ) 109 f.delete(); 110 f.getParentFile().mkdirs(); 111 f.createNewFile(); 112 String shortName = c.getName().substring( c.getName().lastIndexOf('.') + 1 ); 113 FileWriter fw = new FileWriter( f ); 114 fw.write( "/**\n" + 115 " * This class delegates to " + c.getName() + "\n" + 116 " * This file was automatically generated by JAC (-g option)\n" + 117 " * DO NOT MODIFY\n" + 118 " * Author: Renaud Pawlak (pawlak@cnam.fr)\n" + 119 " */\n" ); 120 fw.write( "\npackage jac.lib." + c.getPackage().getName() + ";\n" ); 121 fw.write( "\npublic class " + shortName + ((c.getInterfaces().length == 0)? "" : " implements " + 122 arrayToString( createArray( c.getInterfaces() ) )) ); 123 fw.write( " {\n" ); 124 fw.write( "\n private " + c.getName() + " delegate = new " + c.getName() + "();\n" ); 125 fw.write( "\n public Object clone() {\n Object result=null;\n try { result=super.clone(); } catch(Exception e) {};\n (("+ shortName +")result).delegate=("+c.getName()+")delegate.clone();\n return result;\n }\n"); 126 fw.write( "\n public boolean equals(Object o1) {\n return (delegate==null?super.equals(o1):delegate.equals(o1));\n }\n"); 127 //fw.write( "\n public String toString() {\n return delegate.toString();\n }\n"); 128 Method[] ms = c.getMethods(); 129 for ( int i = 0; i < ms.length; i++ ) { 130 int mod = ms[i].getModifiers(); 131 if( Modifier.isPrivate(mod) || Modifier.isAbstract(mod) || 132 Modifier.isInterface(mod) || Modifier.isProtected(mod) || 133 Modifier.isStatic(mod) ) continue; 134 if( ms[i].getName().equals("clone") ) continue; 135 //if( ms[i].getName().equals("hashCode") ) continue; 136 if( ms[i].getDeclaringClass() == Object.class || 137 ms[i].getDeclaringClass().isInterface() ) continue; 138 139 try { 140 Object.class.getMethod( ms[i].getName(), ms[i].getParameterTypes() ); 141 continue; 142 } catch ( Exception e ) {} 143 144 fw.write( "\n " + getMethodPrototype( ms[i] ) + " {\n" ); 145 if ( ms[i].getReturnType().getName().equals( "void" ) ) { 146 // fw.write( " if ( delegate == null ) return;\n" ); 147 fw.write( " delegate." + ms[i].getName() + "(" + 148 arrayToString( createParameterNames( ms[i].getParameterTypes() ) ) + ");\n" ); 149 } else { 150 // fw.write( " if ( delegate == null ) return " + 151 // getDefaultValueFor( ms[i].getReturnType() ) + ";\n" ); 152 fw.write( " return delegate." + ms[i].getName() + "(" + 153 arrayToString( createParameterNames( ms[i].getParameterTypes() ) ) + ");\n" ); 154 } 155 fw.write( " }\n" ); 156 } 157 fw.write( "}\n" ); 158 fw.close(); 159 } catch ( Exception e ) { 160 e.printStackTrace(); 161 } 162 } 163 164 /** 165 * Return the default string value that should return a method with 166 * a <code>c</code> return type. 167 * 168 * <p>By default: 169 * 170 * <ul><pre> 171 * - c == boolean => "false" 172 * - c == char => "''" 173 * - c == byte => "0" 174 * - c == all other primitive types => "-1" 175 * - c is an object => "null" 176 * </pre></ul> 177 * 178 * @param c the type 179 * @return the default string value for this type */ 180 181 private static String getDefaultValueFor( Class c ) { 182 if ( c.isPrimitive() ) { 183 if (c == Boolean.TYPE ) 184 return "false"; 185 if (c == Character.TYPE ) 186 return "''"; 187 if ( c == Byte.TYPE ) 188 return "0"; 189 if (c == Short.TYPE || c == Integer.TYPE || 190 c == Long.TYPE || c == Float.TYPE || c == Double.TYPE ) 191 return "-1"; 192 } 193 return "null"; 194 } 195 196 /** 197 * Return a Java-syntax-compiliant string representation of the 198 * given method. 199 * 200 * @param m the method 201 * @return the string representation 202 */ 203 204 private static String getMethodPrototype( Method m ) { 205 return "public " + createStringFor( m.getReturnType() ) + " " + m.getName() + 206 " ( " + arrayToString( createTypedParameterNames( m.getParameterTypes() ) ) + 207 " ) " + arrayToString( createArray( m.getExceptionTypes() ) ); 208 } 209 210 /** 211 * Return a comma-separated string for a string array. 212 * 213 * <p>For instance: 214 * 215 * <ul><pre> 216 * - {"a", "b", "c"} => "a, b, c" 217 * - {"a"} => "a" 218 * - {} => "" 219 * </pre></ul> 220 * 221 * @param array the given array 222 * @return its string representation 223 */ 224 225 private static String arrayToString( String[] array ) { 226 if ( array.length == 0 ) return ""; 227 String ls = java.util.Arrays.asList(array).toString(); 228 return ls.substring( 1, ls.length() - 1 ); 229 } 230 231 /** 232 * Create an array of Java-syntax-compiliant string from an array of types. 233 * 234 * <p>For instance: 235 * 236 * <ul><pre> 237 * - {class int, class java.lang.object} => {"int", "java.lang.Object"} 238 * - {class [java.lang.object} => {"java.lang.Object[]"} 239 * </pre></ul> 240 * 241 * @param array the types 242 * @return the corresponding strings 243 * 244 * @see #createStringFor(Class) 245 */ 246 247 private static String[] createArray( Class[] array ) { 248 String[] res = new String[array.length]; 249 for ( int i = 0; i < array.length; i ++ ) { 250 res[i] = createStringFor( array[i] ); 251 } 252 return res; 253 } 254 255 /** 256 * Create a Java-syntax-compiliant string from a type. 257 * 258 * <p>For instance: 259 * 260 * <ul><pre> 261 * - class java.lang.object => "java.lang.Object" 262 * - class [java.lang.object => "java.lang.Object[]" 263 * </pre></ul> 264 * 265 * @param c the type 266 * @return the corresponding string 267 */ 268 269 private static String createStringFor ( Class c ) { 270 if ( c.isArray() ) { 271 return c.getComponentType().getName() + "[]"; 272 } else { 273 return c.getName(); 274 } 275 } 276 277 /** 278 * Create a Java-syntax-compiliant string for a method that would 279 * take a set of parameters defined in <code>array</code>. 280 * 281 * <p>The parameter names are generated to "p[0-array.length]". For 282 * instance: 283 * 284 * <ul><pre> 285 * - {class int, class byte} => {"int p0", "byte p1"} 286 * </pre></ul> 287 * 288 * @param array the types 289 * @param the resulting strings 290 * 291 * @see #createParametersName( array ) */ 292 293 private static String[] createTypedParameterNames ( Class[] array ) { 294 String[] res = new String[array.length]; 295 for ( int i = 0; i < array.length; i ++ ) { 296 res[i] = createStringFor( array[i] ) + " p" + i; 297 } 298 return res; 299 } 300 301 /** 302 * Create untyped paramameter names that correspond to the names 303 * that would have been given by the 304 * <code>createTypedParameterNames</code>. 305 * 306 * <p>For instance, an array of 2 types always returns: 307 * 308 * <ul><pre> 309 * {"p0, "p1"} 310 * </pre></ul> 311 * 312 * @param array the types 313 * @param the resulting strings 314 * 315 * @see #createTypedParametersName( array ) */ 316 317 private static String[] createParameterNames ( Class[] array ) { 318 String[] res = new String[array.length]; 319 for ( int i = 0; i < array.length; i ++ ) { 320 res[i] = "p" + i; 321 } 322 return res; 323 } 324 325 } 326