src/share/classes/sun/rmi/rmic/iiop/Generator.java

Wed, 27 Apr 2016 01:21:28 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:21:28 +0800
changeset 0
7ef37b2cdcad
child 748
6845b95cba6b
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/corba/
changeset: 765:f46df0af2ca8
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 /*
aoqi@0 27 * Licensed Materials - Property of IBM
aoqi@0 28 * RMI-IIOP v1.0
aoqi@0 29 * Copyright IBM Corp. 1998 1999 All Rights Reserved
aoqi@0 30 *
aoqi@0 31 */
aoqi@0 32
aoqi@0 33
aoqi@0 34 package sun.rmi.rmic.iiop;
aoqi@0 35
aoqi@0 36 import java.io.File;
aoqi@0 37 import java.io.FileOutputStream;
aoqi@0 38 import java.io.OutputStreamWriter;
aoqi@0 39 import java.io.IOException;
aoqi@0 40 import sun.tools.java.Identifier;
aoqi@0 41 import sun.tools.java.ClassPath;
aoqi@0 42 import sun.tools.java.ClassFile;
aoqi@0 43 import sun.tools.java.ClassNotFound;
aoqi@0 44 import sun.tools.java.ClassDefinition;
aoqi@0 45 import sun.tools.java.ClassDeclaration;
aoqi@0 46 import sun.rmi.rmic.IndentingWriter;
aoqi@0 47 import sun.rmi.rmic.Main;
aoqi@0 48 import sun.rmi.rmic.iiop.Util;
aoqi@0 49 import java.util.HashSet;
aoqi@0 50
aoqi@0 51 /**
aoqi@0 52 * Generator provides a small framework from which IIOP-specific
aoqi@0 53 * generators can inherit. Common logic is implemented here which uses
aoqi@0 54 * both abstract methods as well as concrete methods which subclasses may
aoqi@0 55 * want to override. The following methods must be present in any subclass:
aoqi@0 56 * <pre>
aoqi@0 57 * Default constructor
aoqi@0 58 * CompoundType getTopType(BatchEnvironment env, ClassDefinition cdef);
aoqi@0 59 * int parseArgs(String argv[], int currentIndex);
aoqi@0 60 * boolean requireNewInstance();
aoqi@0 61 * OutputType[] getOutputTypesFor(CompoundType topType,
aoqi@0 62 * HashSet alreadyChecked);
aoqi@0 63 * String getFileNameExtensionFor(OutputType outputType);
aoqi@0 64 * void writeOutputFor ( OutputType outputType,
aoqi@0 65 * HashSet alreadyChecked,
aoqi@0 66 * IndentingWriter writer) throws IOException;
aoqi@0 67 * </pre>
aoqi@0 68 * @author Bryan Atsatt
aoqi@0 69 */
aoqi@0 70 public abstract class Generator implements sun.rmi.rmic.Generator,
aoqi@0 71 sun.rmi.rmic.iiop.Constants {
aoqi@0 72
aoqi@0 73 protected boolean alwaysGenerate = false;
aoqi@0 74 protected BatchEnvironment env = null;
aoqi@0 75 protected ContextStack contextStack = null;
aoqi@0 76 private boolean trace = false;
aoqi@0 77 protected boolean idl = false;
aoqi@0 78
aoqi@0 79 /**
aoqi@0 80 * Examine and consume command line arguments.
aoqi@0 81 * @param argv The command line arguments. Ignore null
aoqi@0 82 * and unknown arguments. Set each consumed argument to null.
aoqi@0 83 * @param error Report any errors using the main.error() methods.
aoqi@0 84 * @return true if no errors, false otherwise.
aoqi@0 85 */
aoqi@0 86 public boolean parseArgs(String argv[], Main main) {
aoqi@0 87 for (int i = 0; i < argv.length; i++) {
aoqi@0 88 if (argv[i] != null) {
aoqi@0 89 if (argv[i].equalsIgnoreCase("-always") ||
aoqi@0 90 argv[i].equalsIgnoreCase("-alwaysGenerate")) {
aoqi@0 91 alwaysGenerate = true;
aoqi@0 92 argv[i] = null;
aoqi@0 93 } else if (argv[i].equalsIgnoreCase("-xtrace")) {
aoqi@0 94 trace = true;
aoqi@0 95 argv[i] = null;
aoqi@0 96 }
aoqi@0 97 }
aoqi@0 98 }
aoqi@0 99 return true;
aoqi@0 100 }
aoqi@0 101
aoqi@0 102 /**
aoqi@0 103 * Return true if non-conforming types should be parsed.
aoqi@0 104 * @param stack The context stack.
aoqi@0 105 */
aoqi@0 106 protected abstract boolean parseNonConforming(ContextStack stack);
aoqi@0 107
aoqi@0 108 /**
aoqi@0 109 * Create and return a top-level type.
aoqi@0 110 * @param cdef The top-level class definition.
aoqi@0 111 * @param stack The context stack.
aoqi@0 112 * @return The compound type or null if is non-conforming.
aoqi@0 113 */
aoqi@0 114 protected abstract CompoundType getTopType(ClassDefinition cdef, ContextStack stack);
aoqi@0 115
aoqi@0 116 /**
aoqi@0 117 * Return an array containing all the file names and types that need to be
aoqi@0 118 * generated for the given top-level type. The file names must NOT have an
aoqi@0 119 * extension (e.g. ".java").
aoqi@0 120 * @param topType The type returned by getTopType().
aoqi@0 121 * @param alreadyChecked A set of Types which have already been checked.
aoqi@0 122 * Intended to be passed to Type.collectMatching(filter,alreadyChecked).
aoqi@0 123 */
aoqi@0 124 protected abstract OutputType[] getOutputTypesFor(CompoundType topType,
aoqi@0 125 HashSet alreadyChecked);
aoqi@0 126
aoqi@0 127 /**
aoqi@0 128 * Return the file name extension for the given file name (e.g. ".java").
aoqi@0 129 * All files generated with the ".java" extension will be compiled. To
aoqi@0 130 * change this behavior for ".java" files, override the compileJavaSourceFile
aoqi@0 131 * method to return false.
aoqi@0 132 * @param outputType One of the items returned by getOutputTypesFor(...)
aoqi@0 133 */
aoqi@0 134 protected abstract String getFileNameExtensionFor(OutputType outputType);
aoqi@0 135
aoqi@0 136 /**
aoqi@0 137 * Write the output for the given OutputFileName into the output stream.
aoqi@0 138 * @param name One of the items returned by getOutputTypesFor(...)
aoqi@0 139 * @param alreadyChecked A set of Types which have already been checked.
aoqi@0 140 * Intended to be passed to Type.collectMatching(filter,alreadyChecked).
aoqi@0 141 * @param writer The output stream.
aoqi@0 142 */
aoqi@0 143 protected abstract void writeOutputFor(OutputType outputType,
aoqi@0 144 HashSet alreadyChecked,
aoqi@0 145 IndentingWriter writer) throws IOException;
aoqi@0 146
aoqi@0 147 /**
aoqi@0 148 * Return true if a new instance should be created for each
aoqi@0 149 * class on the command line. Subclasses which return true
aoqi@0 150 * should override newInstance() to return an appropriately
aoqi@0 151 * constructed instance.
aoqi@0 152 */
aoqi@0 153 protected abstract boolean requireNewInstance();
aoqi@0 154
aoqi@0 155 /**
aoqi@0 156 * Return true if the specified file needs generation.
aoqi@0 157 */
aoqi@0 158 public boolean requiresGeneration (File target, Type theType) {
aoqi@0 159
aoqi@0 160 boolean result = alwaysGenerate;
aoqi@0 161
aoqi@0 162 if (!result) {
aoqi@0 163
aoqi@0 164 // Get a ClassFile instance for base source or class
aoqi@0 165 // file. We use ClassFile so that if the base is in
aoqi@0 166 // a zip file, we can still get at it's mod time...
aoqi@0 167
aoqi@0 168 ClassFile baseFile;
aoqi@0 169 ClassPath path = env.getClassPath();
aoqi@0 170 String className = theType.getQualifiedName().replace('.',File.separatorChar);
aoqi@0 171
aoqi@0 172 // First try the source file...
aoqi@0 173
aoqi@0 174 baseFile = path.getFile(className + ".source");
aoqi@0 175
aoqi@0 176 if (baseFile == null) {
aoqi@0 177
aoqi@0 178 // Then try class file...
aoqi@0 179
aoqi@0 180 baseFile = path.getFile(className + ".class");
aoqi@0 181 }
aoqi@0 182
aoqi@0 183 // Do we have a baseFile?
aoqi@0 184
aoqi@0 185 if (baseFile != null) {
aoqi@0 186
aoqi@0 187 // Yes, grab baseFile's mod time...
aoqi@0 188
aoqi@0 189 long baseFileMod = baseFile.lastModified();
aoqi@0 190
aoqi@0 191 // Get a File instance for the target. If it is a source
aoqi@0 192 // file, create a class file instead since the source file
aoqi@0 193 // will frequently be deleted...
aoqi@0 194
aoqi@0 195 String targetName = IDLNames.replace(target.getName(),".java",".class");
aoqi@0 196 String parentPath = target.getParent();
aoqi@0 197 File targetFile = new File(parentPath,targetName);
aoqi@0 198
aoqi@0 199 // Does the target file exist?
aoqi@0 200
aoqi@0 201 if (targetFile.exists()) {
aoqi@0 202
aoqi@0 203 // Yes, so grab it's mod time...
aoqi@0 204
aoqi@0 205 long targetFileMod = targetFile.lastModified();
aoqi@0 206
aoqi@0 207 // Set result...
aoqi@0 208
aoqi@0 209 result = targetFileMod < baseFileMod;
aoqi@0 210
aoqi@0 211 } else {
aoqi@0 212
aoqi@0 213 // No, so we must generate...
aoqi@0 214
aoqi@0 215 result = true;
aoqi@0 216 }
aoqi@0 217 } else {
aoqi@0 218
aoqi@0 219 // No, so we must generate...
aoqi@0 220
aoqi@0 221 result = true;
aoqi@0 222 }
aoqi@0 223 }
aoqi@0 224
aoqi@0 225 return result;
aoqi@0 226 }
aoqi@0 227
aoqi@0 228 /**
aoqi@0 229 * Create and return a new instance of self. Subclasses
aoqi@0 230 * which need to do something other than default construction
aoqi@0 231 * must override this method.
aoqi@0 232 */
aoqi@0 233 protected Generator newInstance() {
aoqi@0 234 Generator result = null;
aoqi@0 235 try {
aoqi@0 236 result = (Generator) getClass().newInstance();
aoqi@0 237 }
aoqi@0 238 catch (Exception e){} // Should ALWAYS work!
aoqi@0 239
aoqi@0 240 return result;
aoqi@0 241 }
aoqi@0 242
aoqi@0 243 /**
aoqi@0 244 * Default constructor for subclasses to use.
aoqi@0 245 */
aoqi@0 246 protected Generator() {
aoqi@0 247 }
aoqi@0 248
aoqi@0 249 /**
aoqi@0 250 * Generate output. Any source files created which need compilation should
aoqi@0 251 * be added to the compiler environment using the addGeneratedFile(File)
aoqi@0 252 * method.
aoqi@0 253 *
aoqi@0 254 * @param env The compiler environment
aoqi@0 255 * @param cdef The definition for the implementation class or interface from
aoqi@0 256 * which to generate output
aoqi@0 257 * @param destDir The directory for the root of the package hierarchy
aoqi@0 258 * for generated files. May be null.
aoqi@0 259 */
aoqi@0 260 public void generate(sun.rmi.rmic.BatchEnvironment env, ClassDefinition cdef, File destDir) {
aoqi@0 261
aoqi@0 262 this.env = (BatchEnvironment) env;
aoqi@0 263 contextStack = new ContextStack(this.env);
aoqi@0 264 contextStack.setTrace(trace);
aoqi@0 265
aoqi@0 266 // Make sure the environment knows whether or not to parse
aoqi@0 267 // non-conforming types. This will clear out any previously
aoqi@0 268 // parsed types if necessary...
aoqi@0 269
aoqi@0 270 this.env.setParseNonConforming(parseNonConforming(contextStack));
aoqi@0 271
aoqi@0 272 // Get our top level type...
aoqi@0 273
aoqi@0 274 CompoundType topType = getTopType(cdef,contextStack);
aoqi@0 275 if (topType != null) {
aoqi@0 276
aoqi@0 277 Generator generator = this;
aoqi@0 278
aoqi@0 279 // Do we need to make a new instance?
aoqi@0 280
aoqi@0 281 if (requireNewInstance()) {
aoqi@0 282
aoqi@0 283 // Yes, so make one. 'this' instance is the one instantiated by Main
aoqi@0 284 // and which knows any needed command line args...
aoqi@0 285
aoqi@0 286 generator = newInstance();
aoqi@0 287 }
aoqi@0 288
aoqi@0 289 // Now generate all output files...
aoqi@0 290
aoqi@0 291 generator.generateOutputFiles(topType, this.env, destDir);
aoqi@0 292 }
aoqi@0 293 }
aoqi@0 294
aoqi@0 295 /**
aoqi@0 296 * Create and return a new instance of self. Subclasses
aoqi@0 297 * which need to do something other than default construction
aoqi@0 298 * must override this method.
aoqi@0 299 */
aoqi@0 300 protected void generateOutputFiles (CompoundType topType,
aoqi@0 301 BatchEnvironment env,
aoqi@0 302 File destDir) {
aoqi@0 303
aoqi@0 304 // Grab the 'alreadyChecked' HashSet from the environment...
aoqi@0 305
aoqi@0 306 HashSet alreadyChecked = env.alreadyChecked;
aoqi@0 307
aoqi@0 308 // Ask subclass for a list of output types...
aoqi@0 309
aoqi@0 310 OutputType[] types = getOutputTypesFor(topType,alreadyChecked);
aoqi@0 311
aoqi@0 312 // Process each file...
aoqi@0 313
aoqi@0 314 for (int i = 0; i < types.length; i++) {
aoqi@0 315 OutputType current = types[i];
aoqi@0 316 String className = current.getName();
aoqi@0 317 File file = getFileFor(current,destDir);
aoqi@0 318 boolean sourceFile = false;
aoqi@0 319
aoqi@0 320 // Do we need to generate this file?
aoqi@0 321
aoqi@0 322 if (requiresGeneration(file,current.getType())) {
aoqi@0 323
aoqi@0 324 // Yes. If java source file, add to environment so will be compiled...
aoqi@0 325
aoqi@0 326 if (file.getName().endsWith(".java")) {
aoqi@0 327 sourceFile = compileJavaSourceFile(current);
aoqi@0 328
aoqi@0 329 // Are we supposeded to compile this one?
aoqi@0 330
aoqi@0 331 if (sourceFile) {
aoqi@0 332 env.addGeneratedFile(file);
aoqi@0 333 }
aoqi@0 334 }
aoqi@0 335
aoqi@0 336 // Now create an output stream and ask subclass to fill it up...
aoqi@0 337
aoqi@0 338 try {
aoqi@0 339 IndentingWriter out = new IndentingWriter(
aoqi@0 340 new OutputStreamWriter(new FileOutputStream(file)),INDENT_STEP,TAB_SIZE);
aoqi@0 341
aoqi@0 342 long startTime = 0;
aoqi@0 343 if (env.verbose()) {
aoqi@0 344 startTime = System.currentTimeMillis();
aoqi@0 345 }
aoqi@0 346
aoqi@0 347 writeOutputFor(types[i],alreadyChecked,out);
aoqi@0 348 out.close();
aoqi@0 349
aoqi@0 350 if (env.verbose()) {
aoqi@0 351 long duration = System.currentTimeMillis() - startTime;
aoqi@0 352 env.output(Main.getText("rmic.generated", file.getPath(), Long.toString(duration)));
aoqi@0 353 }
aoqi@0 354 if (sourceFile) {
aoqi@0 355 env.parseFile(new ClassFile(file));
aoqi@0 356 }
aoqi@0 357 } catch (IOException e) {
aoqi@0 358 env.error(0, "cant.write", file.toString());
aoqi@0 359 return;
aoqi@0 360 }
aoqi@0 361 } else {
aoqi@0 362
aoqi@0 363 // No, say so if we need to...
aoqi@0 364
aoqi@0 365 if (env.verbose()) {
aoqi@0 366 env.output(Main.getText("rmic.previously.generated", file.getPath()));
aoqi@0 367 }
aoqi@0 368 }
aoqi@0 369 }
aoqi@0 370 }
aoqi@0 371
aoqi@0 372 /**
aoqi@0 373 * Return the File object that should be used as the output file
aoqi@0 374 * for the given OutputType.
aoqi@0 375 * @param outputType The type to create a file for.
aoqi@0 376 * @param destinationDir The directory to use as the root of the
aoqi@0 377 * package heirarchy. May be null, in which case the current
aoqi@0 378 * classpath is searched to find the directory in which to create
aoqi@0 379 * the output file. If that search fails (most likely because the
aoqi@0 380 * package directory lives in a zip or jar file rather than the
aoqi@0 381 * file system), the current user directory is used.
aoqi@0 382 */
aoqi@0 383 protected File getFileFor(OutputType outputType, File destinationDir) {
aoqi@0 384 // Calling this method does some crucial initialization
aoqi@0 385 // in a subclass implementation. Don't skip it.
aoqi@0 386 Identifier id = getOutputId(outputType);
aoqi@0 387 File packageDir = null;
aoqi@0 388 if(idl){
aoqi@0 389 packageDir = Util.getOutputDirectoryForIDL(id,destinationDir,env);
aoqi@0 390 } else {
aoqi@0 391 packageDir = Util.getOutputDirectoryForStub(id,destinationDir,env);
aoqi@0 392 }
aoqi@0 393 String classFileName = outputType.getName() + getFileNameExtensionFor(outputType);
aoqi@0 394 return new File(packageDir, classFileName);
aoqi@0 395 }
aoqi@0 396
aoqi@0 397 /**
aoqi@0 398 * Return an identifier to use for output.
aoqi@0 399 * @param outputType the type for which output is to be generated.
aoqi@0 400 * @return the new identifier. This implementation returns the input parameter.
aoqi@0 401 */
aoqi@0 402 protected Identifier getOutputId (OutputType outputType) {
aoqi@0 403 return outputType.getType().getIdentifier();
aoqi@0 404 }
aoqi@0 405
aoqi@0 406 /**
aoqi@0 407 * Return true if the given file should be compiled.
aoqi@0 408 * @param outputType One of the items returned by getOutputTypesFor(...) for
aoqi@0 409 * which getFileNameExtensionFor(OutputType) returned ".java".
aoqi@0 410 */
aoqi@0 411 protected boolean compileJavaSourceFile (OutputType outputType) {
aoqi@0 412 return true;
aoqi@0 413 }
aoqi@0 414
aoqi@0 415 //_____________________________________________________________________
aoqi@0 416 // OutputType is a simple wrapper for a name and a Type
aoqi@0 417 //_____________________________________________________________________
aoqi@0 418
aoqi@0 419 public class OutputType {
aoqi@0 420 private String name;
aoqi@0 421 private Type type;
aoqi@0 422
aoqi@0 423 public OutputType (String name, Type type) {
aoqi@0 424 this.name = name;
aoqi@0 425 this.type = type;
aoqi@0 426 }
aoqi@0 427
aoqi@0 428 public String getName() {
aoqi@0 429 return name;
aoqi@0 430 }
aoqi@0 431
aoqi@0 432 public Type getType() {
aoqi@0 433 return type;
aoqi@0 434 }
aoqi@0 435 }
aoqi@0 436 }

mercurial