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 jdk.jshell; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.ByteArrayOutputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.lang.reflect.InvocationTargetException; 34 import java.lang.reflect.Method; 35 import java.net.URI; 36 import java.nio.file.FileSystems; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.util.Collection; 40 import java.util.Iterator; 41 import java.util.Map; 42 import java.util.NoSuchElementException; 43 import java.util.Set; 44 import java.util.TreeMap; 45 46 import javax.tools.JavaFileObject.Kind; 47 import static javax.tools.StandardLocation.CLASS_PATH; 48 import javax.tools.FileObject; 49 import javax.tools.JavaFileManager; 50 import javax.tools.JavaFileObject; 51 import javax.tools.SimpleJavaFileObject; 52 import javax.tools.StandardJavaFileManager; 53 import javax.tools.StandardLocation; 54 55 56 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_FMGR; 57 58 /** 59 * File manager for the compiler API. Reads from memory (Strings) and writes 60 * class files to memory (cached OutputMemoryJavaFileObject). 61 * 62 * @author Robert Field 63 */ 64 class MemoryFileManager implements JavaFileManager { 65 66 private final StandardJavaFileManager stdFileManager; 67 68 private final Map<String, OutputMemoryJavaFileObject> classObjects = new TreeMap<>(); 69 70 private ClassFileCreationListener classListener = null; 71 72 private final JShell proc; 73 74 // Upcoming Jigsaw 75 private Method inferModuleNameMethod = null; 76 private Method listLocationsForModulesMethod = null; 77 78 Iterable<? extends Path> getLocationAsPaths(Location loc) { 79 return this.stdFileManager.getLocationAsPaths(loc); 80 } 81 82 static abstract class MemoryJavaFileObject extends SimpleJavaFileObject { 83 84 public MemoryJavaFileObject(String name, JavaFileObject.Kind kind) { 85 super(URI.create("string:///" + name.replace('.', '/') 86 + kind.extension), kind); 87 } 88 } 89 90 class SourceMemoryJavaFileObject extends MemoryJavaFileObject { 91 private final String src; 92 private final Object origin; 93 94 SourceMemoryJavaFileObject(Object origin, String className, String code) { 95 super(className, JavaFileObject.Kind.SOURCE); 96 this.origin = origin; 97 this.src = code; 167 public MemoryFileManager(StandardJavaFileManager standardManager, JShell proc) { 168 this.stdFileManager = standardManager; 169 this.proc = proc; 170 } 171 172 private Collection<OutputMemoryJavaFileObject> generatedClasses() { 173 return classObjects.values(); 174 } 175 176 // For debugging dumps 177 public void dumpClasses() { 178 for (OutputMemoryJavaFileObject co : generatedClasses()) { 179 co.dump(); 180 } 181 } 182 183 public JavaFileObject createSourceFileObject(Object origin, String name, String code) { 184 return new SourceMemoryJavaFileObject(origin, name, code); 185 } 186 187 // Make compatible with Jigsaw 188 public String inferModuleName(Location location) { 189 try { 190 if (inferModuleNameMethod == null) { 191 inferModuleNameMethod = JavaFileManager.class.getDeclaredMethod("inferModuleName", Location.class); 192 } 193 @SuppressWarnings("unchecked") 194 String result = (String) inferModuleNameMethod.invoke(stdFileManager, location); 195 return result; 196 } catch (NoSuchMethodException | SecurityException ex) { 197 throw new InternalError("Cannot lookup JavaFileManager method", ex); 198 } catch (IllegalAccessException | 199 IllegalArgumentException | 200 InvocationTargetException ex) { 201 throw new InternalError("Cannot invoke JavaFileManager method", ex); 202 } 203 } 204 205 // Make compatible with Jigsaw 206 public Iterable<Set<Location>> listLocationsForModules(Location location) throws IOException { 207 try { 208 if (listLocationsForModulesMethod == null) { 209 listLocationsForModulesMethod = JavaFileManager.class.getDeclaredMethod("listLocationsForModules", Location.class); 210 } 211 @SuppressWarnings("unchecked") 212 Iterable<Set<Location>> result = (Iterable<Set<Location>>) listLocationsForModulesMethod.invoke(stdFileManager, location); 213 return result; 214 } catch (NoSuchMethodException | SecurityException ex) { 215 throw new InternalError("Cannot lookup JavaFileManager method", ex); 216 } catch (IllegalAccessException | 217 IllegalArgumentException | 218 InvocationTargetException ex) { 219 throw new InternalError("Cannot invoke JavaFileManager method", ex); 220 } 221 } 222 223 224 /** 225 * Returns a class loader for loading plug-ins from the given location. For 226 * example, to load annotation processors, a compiler will request a class 227 * loader for the {@link 228 * StandardLocation#ANNOTATION_PROCESSOR_PATH 229 * ANNOTATION_PROCESSOR_PATH} location. 230 * 231 * @param location a location 232 * @return a class loader for the given location; or {@code null} 233 * if loading plug-ins from the given location is disabled or if 234 * the location is not known 235 * @throws SecurityException if a class loader can not be created 236 * in the current security context 237 * @throws IllegalStateException if {@link #close} has been called 238 * and this file manager cannot be reopened 239 */ 240 @Override 241 public ClassLoader getClassLoader(JavaFileManager.Location location) { 242 proc.debug(DBG_FMGR, "getClassLoader: location\n", location); 243 return stdFileManager.getClassLoader(location); 563 * manager and the file manager does not support unknown 564 * locations, or if {@code relativeName} is not valid 565 * @throws IOException if an I/O error occurred, or if {@link 566 * #close} has been called and this file manager cannot be 567 * reopened 568 * @throws IllegalStateException if {@link #close} has been called 569 * and this file manager cannot be reopened 570 */ 571 @Override 572 public FileObject getFileForOutput(JavaFileManager.Location location, 573 String packageName, 574 String relativeName, 575 FileObject sibling) 576 throws IOException { 577 throw new UnsupportedOperationException("getFileForOutput: location: " + location + 578 ", packageName: " + packageName + 579 ", relativeName: " + relativeName + 580 ", sibling: " + sibling); 581 } 582 583 /** 584 * Flushes any resources opened for output by this file manager 585 * directly or indirectly. Flushing a closed file manager has no 586 * effect. 587 * 588 * @throws IOException if an I/O error occurred 589 * @see #close 590 */ 591 @Override 592 public void flush() throws IOException { 593 // Nothing to flush 594 } 595 596 /** 597 * Releases any resources opened by this file manager directly or 598 * indirectly. This might render this file manager useless and 599 * the effect of subsequent calls to methods on this object or any 600 * objects obtained through this object is undefined unless 601 * explicitly allowed. However, closing a file manager which has 602 * already been closed has no effect. | 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 jdk.jshell; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.ByteArrayOutputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.net.URI; 34 import java.nio.file.FileSystems; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.util.Collection; 38 import java.util.Iterator; 39 import java.util.Map; 40 import java.util.NoSuchElementException; 41 import java.util.Set; 42 import java.util.TreeMap; 43 44 import javax.tools.JavaFileObject.Kind; 45 import static javax.tools.StandardLocation.CLASS_PATH; 46 import javax.tools.FileObject; 47 import javax.tools.JavaFileManager; 48 import javax.tools.JavaFileObject; 49 import javax.tools.SimpleJavaFileObject; 50 import javax.tools.StandardJavaFileManager; 51 import javax.tools.StandardLocation; 52 53 54 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_FMGR; 55 56 /** 57 * File manager for the compiler API. Reads from memory (Strings) and writes 58 * class files to memory (cached OutputMemoryJavaFileObject). 59 * 60 * @author Robert Field 61 */ 62 class MemoryFileManager implements JavaFileManager { 63 64 private final StandardJavaFileManager stdFileManager; 65 66 private final Map<String, OutputMemoryJavaFileObject> classObjects = new TreeMap<>(); 67 68 private ClassFileCreationListener classListener = null; 69 70 private final JShell proc; 71 72 Iterable<? extends Path> getLocationAsPaths(Location loc) { 73 return this.stdFileManager.getLocationAsPaths(loc); 74 } 75 76 static abstract class MemoryJavaFileObject extends SimpleJavaFileObject { 77 78 public MemoryJavaFileObject(String name, JavaFileObject.Kind kind) { 79 super(URI.create("string:///" + name.replace('.', '/') 80 + kind.extension), kind); 81 } 82 } 83 84 class SourceMemoryJavaFileObject extends MemoryJavaFileObject { 85 private final String src; 86 private final Object origin; 87 88 SourceMemoryJavaFileObject(Object origin, String className, String code) { 89 super(className, JavaFileObject.Kind.SOURCE); 90 this.origin = origin; 91 this.src = code; 161 public MemoryFileManager(StandardJavaFileManager standardManager, JShell proc) { 162 this.stdFileManager = standardManager; 163 this.proc = proc; 164 } 165 166 private Collection<OutputMemoryJavaFileObject> generatedClasses() { 167 return classObjects.values(); 168 } 169 170 // For debugging dumps 171 public void dumpClasses() { 172 for (OutputMemoryJavaFileObject co : generatedClasses()) { 173 co.dump(); 174 } 175 } 176 177 public JavaFileObject createSourceFileObject(Object origin, String name, String code) { 178 return new SourceMemoryJavaFileObject(origin, name, code); 179 } 180 181 /** 182 * Returns a class loader for loading plug-ins from the given location. For 183 * example, to load annotation processors, a compiler will request a class 184 * loader for the {@link 185 * StandardLocation#ANNOTATION_PROCESSOR_PATH 186 * ANNOTATION_PROCESSOR_PATH} location. 187 * 188 * @param location a location 189 * @return a class loader for the given location; or {@code null} 190 * if loading plug-ins from the given location is disabled or if 191 * the location is not known 192 * @throws SecurityException if a class loader can not be created 193 * in the current security context 194 * @throws IllegalStateException if {@link #close} has been called 195 * and this file manager cannot be reopened 196 */ 197 @Override 198 public ClassLoader getClassLoader(JavaFileManager.Location location) { 199 proc.debug(DBG_FMGR, "getClassLoader: location\n", location); 200 return stdFileManager.getClassLoader(location); 520 * manager and the file manager does not support unknown 521 * locations, or if {@code relativeName} is not valid 522 * @throws IOException if an I/O error occurred, or if {@link 523 * #close} has been called and this file manager cannot be 524 * reopened 525 * @throws IllegalStateException if {@link #close} has been called 526 * and this file manager cannot be reopened 527 */ 528 @Override 529 public FileObject getFileForOutput(JavaFileManager.Location location, 530 String packageName, 531 String relativeName, 532 FileObject sibling) 533 throws IOException { 534 throw new UnsupportedOperationException("getFileForOutput: location: " + location + 535 ", packageName: " + packageName + 536 ", relativeName: " + relativeName + 537 ", sibling: " + sibling); 538 } 539 540 @Override 541 public Location getLocationForModule(Location location, String moduleName) throws IOException { 542 return stdFileManager.getLocationForModule(location, moduleName); 543 } 544 545 @Override 546 public Location getLocationForModule(Location location, JavaFileObject fo, String pkgName) throws IOException { 547 return stdFileManager.getLocationForModule(location, fo, pkgName); 548 } 549 550 @Override 551 public String inferModuleName(Location location) throws IOException { 552 return stdFileManager.inferModuleName(location); 553 } 554 555 @Override 556 public Iterable<Set<Location>> listLocationsForModules(Location location) throws IOException { 557 return stdFileManager.listLocationsForModules(location); 558 } 559 560 /** 561 * Flushes any resources opened for output by this file manager 562 * directly or indirectly. Flushing a closed file manager has no 563 * effect. 564 * 565 * @throws IOException if an I/O error occurred 566 * @see #close 567 */ 568 @Override 569 public void flush() throws IOException { 570 // Nothing to flush 571 } 572 573 /** 574 * Releases any resources opened by this file manager directly or 575 * indirectly. This might render this file manager useless and 576 * the effect of subsequent calls to methods on this object or any 577 * objects obtained through this object is undefined unless 578 * explicitly allowed. However, closing a file manager which has 579 * already been closed has no effect. |