1 18 package org.apache.beehive.netui.compiler.xdoclet.tools; 19 20 import java.io.StreamTokenizer ; 21 import java.io.Reader ; 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.io.FileNotFoundException ; 25 import java.io.FileReader ; 26 import java.io.FileWriter ; 27 import java.io.PrintWriter ; 28 import java.util.ArrayList ; 29 30 public class AnnotationsToXDoclet 31 { 32 private static final String [] QUALIFIED_ANNOTATIONS = 33 { 34 "@org.apache.beehive.netui.pageflow.annotations.", 35 "@org.apache.beehive.controls.api.bean." 36 }; 37 38 private static void usage() 39 { 40 System.err.println( "usage: " + AnnotationsToXDoclet.class.getName() + " input-file output-file" ); 41 System.err.println( " -or-" ); 42 System.err.println( "usage: " + AnnotationsToXDoclet.class.getName() 43 + " -input-dir <root of input dir> -output-dir <root of output dir> -extensions <comma-separated list>" ); 44 } 45 46 public static void main( String [] args ) 47 throws IOException , FileNotFoundException 48 { 49 if ( args.length == 6 ) 51 { 52 if ( ! args[0].equals( "-input-dir" ) || ! args[2].equals( "-output-dir" ) || ! args[4].equals( "-extensions" ) ) 53 { 54 usage(); 55 System.exit( 1 ); 56 } 57 58 File inputDir = new File ( args[1] ); 59 if ( ! inputDir.exists() ) 60 { 61 System.err.println( inputDir + " is not a directory" ); 62 System.exit( 2 ); 63 } 64 65 File outputDir = new File ( args[3] ); 66 if ( ! outputDir.exists() ) 67 { 68 System.err.println( outputDir + " is not a directory" ); 69 System.exit( 2 ); 70 } 71 72 String [] extensions = args[5].split( "," ); 73 new AnnotationsToXDoclet().translateRecursive( inputDir, outputDir, extensions ); 74 return; 75 } 76 77 if ( args.length != 2 ) 79 { 80 usage(); 81 System.exit( 1 ); 82 } 83 84 File input = new File ( args[0] ); 85 File output = new File ( args[1] ); 86 87 if ( input.equals( output ) ) 88 { 89 System.err.println( "input file " + input + " must be different from output file" ); 90 System.exit( 2 ); 91 } 92 93 if ( ! input.canRead() ) 94 { 95 System.err.println( "cannot read " + input ); 96 System.exit( 2 ); 97 } 98 99 if ( output.exists() && ! output.canWrite() ) 100 { 101 System.err.println( "cannot write to " + output ); 102 System.exit( 2 ); 103 } 104 105 new AnnotationsToXDoclet().translate( input, output ); 106 } 107 108 public void translateRecursive( File inputDir, File outputDir, String [] extensions ) 109 throws IOException , FileNotFoundException 110 { 111 File [] children = inputDir.listFiles(); 112 113 outputDir.mkdirs(); 114 115 for ( int i = 0; i < children.length; i++ ) 116 { 117 File child = children[i]; 118 119 if ( child.isFile() ) 120 { 121 for ( int j = 0; j < extensions.length; j++ ) 122 { 123 String extension = extensions[j]; 124 if ( child.getName().endsWith( extension ) ) 125 { 126 translate( child, new File ( outputDir, child.getName() ) ); 127 } 128 } 129 } 130 else if ( child.isDirectory() ) 131 { 132 File childOutputDir = new File ( outputDir, child.getName() ); 133 translateRecursive( child, childOutputDir, extensions ); 134 } 135 } 136 } 137 138 public void translate( File input, File output ) 139 throws IOException , FileNotFoundException 140 { 141 System.err.println( input + " -> " + output ); 142 output.getParentFile().mkdirs(); 143 FileReader in = new FileReader ( input ); 144 PrintWriter out = null; 145 146 try 147 { 148 out = new PrintWriter ( new FileWriter ( output ) ); 149 StreamTokenizer tok = getJavaTokenizer( in ); 150 boolean addedSpace = false; 151 StringBuffer indentBuffer = new StringBuffer (); 152 String indent = ""; 153 154 while ( tok.nextToken() != StreamTokenizer.TT_EOF ) 155 { 156 boolean wasSpace = false; 157 boolean wasChar = false; 158 159 switch ( tok.ttype ) 160 { 161 case StreamTokenizer.TT_WORD: 162 if ( indentBuffer != null ) 163 { 164 indent = indentBuffer.toString(); 165 indentBuffer = null; 166 } 167 String str = tok.sval; 168 if ( str.startsWith( "@Jpf.ViewProperties" ) ) 169 { 170 ignoreUntil( tok, ")" ); 171 } 172 else if ( str.startsWith( "@Jpf." ) || str.startsWith( "@Control" ) 173 || str.startsWith( "@org.apache.beehive" ) ) 174 { 175 out.println( "/**" ); 176 ArrayList tags = new ArrayList (); 177 translateAnnotation( tok, out, str, indent, tags ); 178 for ( int i = 0; i < tags.size(); ++i ) 179 { 180 out.print( indent ); 181 out.print( " * " ); 182 out.println( ( String ) tags.get( i ) ); 183 } 184 out.print( indent ); 185 out.print( " */" ); 186 } 187 else if ( str.equals( "import" ) ) 188 { 189 filterImport( tok, out ); 190 } 191 else 192 { 193 out.print( str ); 194 if ( str.length() == 1 ) 195 { 196 char c = str.charAt( 0 ); 197 if ( c == '\'' || c == '"' ) wasChar = true; 198 } 199 } 200 break; 201 202 case StreamTokenizer.TT_NUMBER: 203 assert false : tok.nval; break; 205 206 default: 207 char c = ( char ) tok.ttype; 208 wasChar = true; 209 if ( ! addedSpace || c != ' ' ) out.print( c ); 210 wasSpace = Character.isWhitespace( c ); 211 if ( ! wasSpace && indentBuffer != null ) 212 { 213 indent = indentBuffer.toString(); 214 indentBuffer = null; 215 } 216 if ( indentBuffer != null ) indentBuffer.append( c ); 217 if ( c == '\n' ) indentBuffer = new StringBuffer (); 218 } 219 220 if ( ! wasChar ) 221 { 222 out.print( ' ' ); 223 addedSpace = true; 224 } 225 else 226 { 227 addedSpace = false; 228 } 229 } 230 } 231 finally 232 { 233 in.close(); 234 if ( out != null ) out.close(); 235 } 236 } 237 238 private void ignoreUntil( StreamTokenizer tok, String str ) 239 throws IOException 240 { 241 while ( ! getToken( tok ).equals( str ) ) 242 { 243 } 244 } 245 246 private void filterImport( StreamTokenizer tok, PrintWriter out ) 247 throws IOException 248 { 249 String importName = getToken( tok ); 250 if ( ! importName.startsWith( "org.apache.beehive.netui.pageflow.annotations" ) 251 && ! importName.startsWith( "org.apache.beehive.controls.api.bean.Control" ) ) 252 { 253 out.print( "import " ); 254 out.print( importName ); 255 } 256 else 257 { 258 expectToken( tok, ";" ); 259 } 260 } 261 262 private void translateAnnotation( StreamTokenizer tok, PrintWriter out, String firstToken, String indent, 263 ArrayList tags ) 264 throws IOException 265 { 266 for ( int i = 0; i < QUALIFIED_ANNOTATIONS.length; i++ ) 267 { 268 String qualifiedAnnotation = QUALIFIED_ANNOTATIONS[i]; 269 if ( firstToken.startsWith( qualifiedAnnotation ) ) 270 { 271 firstToken = '@' + firstToken.substring( qualifiedAnnotation.length() ); 272 } 273 } 274 275 String nextToken = getToken( tok ); 276 277 if ( ! nextToken.equals( "(" ) ) 278 { 279 tok.pushBack(); 280 tags.add( firstToken ); 281 return; 282 } 283 else 284 { 285 StringBuffer tag = new StringBuffer ( firstToken ); 286 int thisTagPos = tags.size(); 287 tags.add( "" ); 288 289 while ( ! ( nextToken = getToken( tok ) ).equals( ")" ) ) 290 { 291 if ( nextToken.equals( "," ) ) nextToken = getToken( tok ); 292 String attrName = nextToken; 293 expectToken( tok, "=" ); 294 String value = getToken( tok ); 295 int pos; 296 297 if ( value.charAt( 0 ) == '@' ) 298 { 299 if ( attrName.equals( "validationErrorForward" ) ) 300 { 301 value = "@Jpf.ValidationErrorForward"; 306 } 307 308 translateAnnotation( tok, out, value, indent, tags ); 309 value = null; 310 } 311 else if ( value.equals( "{" ) ) 312 { 313 StringBuffer stringArray = null; 314 315 while ( ! ( nextToken = getToken( tok ) ).equals( "}" ) ) 316 { 317 if ( nextToken.equals( "," ) ) nextToken = getToken( tok ); 318 319 if ( nextToken.charAt( 0 ) == '@' ) 320 { 321 translateAnnotation( tok, out, nextToken, indent, tags ); 322 } 323 else 324 { 325 assert nextToken.length() > 1 && nextToken.charAt( 0 ) == '"' 327 && nextToken.charAt( nextToken.length() - 1 ) == '"' : nextToken; 328 if ( stringArray == null ) 329 { 330 stringArray = new StringBuffer ( "\"" ); 331 } 332 else 333 { 334 stringArray.append( ',' ); 335 } 336 stringArray.append( nextToken.substring( 1, nextToken.length() - 1 ) ); 337 } 338 } 339 340 value = stringArray != null ? stringArray.append( '"' ).toString() : null; 341 } 342 else if ( value.equals( "true" ) || value.equals( "false" ) ) 343 { 344 value = '"' + value + '"'; 345 } 346 else if ( value.endsWith( ".class" ) ) 347 { 348 value = '"' + value.substring( 0, value.length() - 6 ) + '"'; 349 } 350 else if ( ( pos = value.indexOf( "Jpf.NavigateTo." ) ) != -1 ) 351 { 352 value = '"' + value.substring( pos + 15 ) + '"'; 353 } 354 else if ( ( pos = value.indexOf( "Jpf.ValidatorVersion." ) ) != -1 ) 355 { 356 value = '"' + value.substring( pos + 21 ) + '"'; 357 } 358 else if ( isNumber( value ) ) 359 { 360 value = '"' + value + '"'; 361 } 362 else 363 { 364 assert value.charAt( 0 ) == '"' && value.charAt( value.length() - 1 ) == '"' : value; 365 if ( value.charAt( 0 ) != '"' ) value = '"' + value; 366 if ( value.charAt( value.length() - 1 ) != '"' ) value += '"'; 367 } 368 369 if ( value != null ) 370 { 371 tag.append( ' ' ).append( attrName ).append( '=' ).append( value ); 372 } 373 } 374 375 tags.set( thisTagPos, tag.toString() ); 376 } 377 } 378 379 private static boolean isNumber( String str ) 380 { 381 char firstChar = str.charAt( 0 ); 382 if ( firstChar != '-' && ! Character.isDigit( firstChar ) && firstChar != '.' ) return false; 383 384 for ( int i = 1; i < str.length(); ++i ) 385 { 386 char c = str.charAt( i ); 387 if ( ! Character.isDigit( c ) && c != '.' ) return false; 388 } 389 390 return true; 391 } 392 393 private String expectToken( StreamTokenizer tok, String expected ) 394 throws IOException 395 { 396 String token = getToken( tok ); 397 assert token.equals( expected ) : "expected \"" + expected + "\", got \"" + token + "\" (line " + tok.lineno() + ')'; 398 return token; 399 } 400 401 private String getToken( StreamTokenizer tok ) 402 throws IOException 403 { 404 return getToken( tok, false, "" ); 405 } 406 407 private String getToken( StreamTokenizer tok, boolean includeSpace, String prepend ) 408 throws IOException 409 { 410 tok.nextToken(); 411 assert tok.ttype != StreamTokenizer.TT_EOF : "unexpected eof"; 412 String retVal; 413 414 switch ( tok.ttype ) 415 { 416 case StreamTokenizer.TT_WORD: 417 retVal = prepend + tok.sval; 418 break; 419 420 case StreamTokenizer.TT_NUMBER: 421 assert false : tok.nval; retVal = new Double ( tok.nval ).toString(); 423 break; 424 425 default: 426 char c = ( char ) tok.ttype; 427 if ( Character.isWhitespace( c ) && ! includeSpace ) return getToken( tok ); 428 retVal = prepend + Character.toString( c ); 429 } 430 431 return count( retVal, '"' ) % 2 != 0 ? getToken( tok, true, retVal ) : retVal; 433 } 434 435 private static int count( String s, char c ) 436 { 437 int count = 0; 438 char lastChar = '\0'; 439 440 for ( int i = 0; i < s.length(); ++i ) 441 { 442 if ( lastChar != '\\' && s.charAt( i ) == c ) ++count; 443 lastChar = c; 444 } 445 446 return count; 447 } 448 449 private static StreamTokenizer getJavaTokenizer( Reader reader ) 450 { 451 StreamTokenizer tok = new StreamTokenizer ( reader ); 452 tok.resetSyntax(); 453 tok.eolIsSignificant( true ); 454 tok.lowerCaseMode( false ); 455 tok.wordChars( 'A', 'Z' ); 456 tok.wordChars( 'a', 'z' ); 457 tok.wordChars( '_', '_' ); 458 tok.wordChars( '@', '@' ); 459 tok.wordChars( '[', '[' ); 460 tok.wordChars( ']', ']' ); 461 tok.wordChars( '.', '.' ); 462 tok.wordChars( '"', '"' ); 463 tok.wordChars( '\'', '\'' ); 464 tok.wordChars( '-', '-' ); 465 tok.wordChars( '0', '9' ); 466 tok.wordChars( ':', ':' ); 467 tok.wordChars( '$', '$' ); 468 tok.wordChars( '/', '/' ); 469 tok.wordChars( '*', '*' ); 470 tok.wordChars( '\\', '\\' ); 471 tok.wordChars( '?', '?' ); 472 return tok; 473 } 474 } 475 | Popular Tags |