1 /* 2 * Copyright (c) 2003, 2005, 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 sun.rmi.rmic.newrmic.jrmp; 27 28 import com.sun.javadoc.ClassDoc; 29 import java.io.File; 30 import java.io.FileOutputStream; 31 import java.io.IOException; 32 import java.io.OutputStreamWriter; 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.HashSet; 36 import java.util.Map; 37 import java.util.Set; 38 import sun.rmi.rmic.newrmic.BatchEnvironment; 39 import sun.rmi.rmic.newrmic.Generator; 40 import sun.rmi.rmic.newrmic.IndentingWriter; 41 import sun.rmi.rmic.newrmic.Main; 42 import sun.rmi.rmic.newrmic.Resources; 43 44 import static sun.rmi.rmic.newrmic.jrmp.Constants.*; 45 46 /** 47 * JRMP rmic back end; generates source code for JRMP stub and 48 * skeleton classes. 49 * 50 * WARNING: The contents of this source file are not part of any 51 * supported API. Code that depends on them does so at its own risk: 52 * they are subject to change or removal without notice. 53 * 54 * @author Peter Jones 55 **/ 56 public class JrmpGenerator implements Generator { 57 58 private static final Map<String,StubVersion> versionOptions = 59 new HashMap<String,StubVersion>(); 60 static { 61 versionOptions.put("-v1.1", StubVersion.V1_1); 62 versionOptions.put("-vcompat", StubVersion.VCOMPAT); 63 versionOptions.put("-v1.2", StubVersion.V1_2); 64 } 65 66 private static final Set<String> bootstrapClassNames = 67 new HashSet<String>(); 68 static { 69 bootstrapClassNames.add("java.lang.Exception"); 70 bootstrapClassNames.add("java.rmi.Remote"); 71 bootstrapClassNames.add("java.rmi.RemoteException"); 72 bootstrapClassNames.add("java.lang.RuntimeException"); 73 }; 74 75 /** version of the JRMP stub protocol to generate code for */ 76 private StubVersion version = StubVersion.V1_2; // default is -v1.2 77 78 /** 79 * Creates a new JrmpGenerator. 80 **/ 81 public JrmpGenerator() { } 82 83 /** 84 * The JRMP generator recognizes command line options for 85 * selecting the JRMP stub protocol version to generate classes 86 * for. Only one such option is allowed. 87 **/ 88 public boolean parseArgs(String[] args, Main main) { 89 String explicitVersion = null; 90 for (int i = 0; i < args.length; i++) { 91 String arg = args[i]; 92 if (versionOptions.containsKey(arg)) { 93 if (explicitVersion != null && !explicitVersion.equals(arg)) { 94 main.error("rmic.cannot.use.both", explicitVersion, arg); 95 return false; 96 } 97 explicitVersion = arg; 98 version = versionOptions.get(arg); 99 args[i] = null; 100 } 101 } 102 return true; 103 } 104 105 /** 106 * The JRMP generator does not require an environment class more 107 * specific than BatchEnvironment. 108 **/ 109 public Class<? extends BatchEnvironment> envClass() { 110 return BatchEnvironment.class; 111 } 112 113 public Set<String> bootstrapClassNames() { 114 return Collections.unmodifiableSet(bootstrapClassNames); 115 } 116 117 /** 118 * Generates the source file(s) for the JRMP stub class and 119 * (optionally) skeleton class for the specified remote 120 * implementation class. 121 **/ 122 public void generate(BatchEnvironment env, 123 ClassDoc inputClass, 124 File destDir) 125 { 126 RemoteClass remoteClass = RemoteClass.forClass(env, inputClass); 127 if (remoteClass == null) { 128 return; // an error must have occurred 129 } 130 131 StubSkeletonWriter writer = 132 new StubSkeletonWriter(env, remoteClass, version); 133 134 File stubFile = sourceFileForClass(writer.stubClassName(), destDir); 135 try { 136 IndentingWriter out = new IndentingWriter( 137 new OutputStreamWriter(new FileOutputStream(stubFile))); 138 writer.writeStub(out); 139 out.close(); 140 if (env.verbose()) { 141 env.output(Resources.getText("rmic.wrote", 142 stubFile.getPath())); 143 } 144 env.addGeneratedFile(stubFile); 145 } catch (IOException e) { 146 env.error("rmic.cant.write", stubFile.toString()); 147 return; 148 } 149 150 File skeletonFile = 151 sourceFileForClass(writer.skeletonClassName(), destDir); 152 if (version == StubVersion.V1_1 || 153 version == StubVersion.VCOMPAT) 154 { 155 try { 156 IndentingWriter out = new IndentingWriter( 157 new OutputStreamWriter( 158 new FileOutputStream(skeletonFile))); 159 writer.writeSkeleton(out); 160 out.close(); 161 if (env.verbose()) { 162 env.output(Resources.getText("rmic.wrote", 163 skeletonFile.getPath())); 164 } 165 env.addGeneratedFile(skeletonFile); 166 } catch (IOException e) { 167 env.error("rmic.cant.write", skeletonFile.toString()); 168 return; 169 } 170 } else { 171 /* 172 * If skeleton files are not being generated for this run, 173 * delete old skeleton source or class files for this 174 * remote implementation class that were (presumably) left 175 * over from previous runs, to avoid user confusion from 176 * extraneous or inconsistent generated files. 177 */ 178 File skeletonClassFile = 179 classFileForClass(writer.skeletonClassName(), destDir); 180 181 skeletonFile.delete(); // ignore failures (no big deal) 182 skeletonClassFile.delete(); 183 } 184 } 185 186 187 /** 188 * Returns the File object to be used as the source file for a 189 * class with the specified binary name, with the specified 190 * destination directory as the top of the package hierarchy. 191 **/ 192 private File sourceFileForClass(String binaryName, File destDir) { 193 return fileForClass(binaryName, destDir, ".java"); 194 } 195 196 /** 197 * Returns the File object to be used as the class file for a 198 * class with the specified binary name, with the supplied 199 * destination directory as the top of the package hierarchy. 200 **/ 201 private File classFileForClass(String binaryName, File destDir) { 202 return fileForClass(binaryName, destDir, ".class"); 203 } 204 205 private File fileForClass(String binaryName, File destDir, String ext) { 206 int i = binaryName.lastIndexOf('.'); 207 String classFileName = binaryName.substring(i + 1) + ext; 208 if (i != -1) { 209 String packageName = binaryName.substring(0, i); 210 String packagePath = packageName.replace('.', File.separatorChar); 211 File packageDir = new File(destDir, packagePath); 212 /* 213 * Make sure that the directory for this package exists. 214 * We assume that the caller has verified that the top- 215 * level destination directory exists, so we need not 216 * worry about creating it unintentionally. 217 */ 218 if (!packageDir.exists()) { 219 packageDir.mkdirs(); 220 } 221 return new File(packageDir, classFileName); 222 } else { 223 return new File(destDir, classFileName); 224 } 225 } 226 }