langtools/src/jdk.jshell/share/classes/jdk/jshell/MemoryFileManager.java
changeset 33362 65ec6de1d6b4
child 33715 74b1bed86932
equal deleted inserted replaced
33361:1c96344ecd49 33362:65ec6de1d6b4
       
     1 /*
       
     2  * Copyright (c) 2014, 2015, 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 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 import javax.tools.JavaFileObject.Kind;
       
    46 import static javax.tools.StandardLocation.CLASS_PATH;
       
    47 import javax.tools.FileObject;
       
    48 import javax.tools.JavaFileManager;
       
    49 import javax.tools.JavaFileObject;
       
    50 import javax.tools.SimpleJavaFileObject;
       
    51 import javax.tools.StandardJavaFileManager;
       
    52 
       
    53 import com.sun.tools.javac.util.DefinedBy;
       
    54 import com.sun.tools.javac.util.DefinedBy.Api;
       
    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 ClassLoader loader = new REPLClassLoader();
       
    73 
       
    74     private final JShell proc;
       
    75 
       
    76     // Upcoming Jigsaw
       
    77     private Method inferModuleNameMethod = null;
       
    78     private Method listModuleLocationsMethod = null;
       
    79 
       
    80     static abstract class MemoryJavaFileObject extends SimpleJavaFileObject {
       
    81 
       
    82         public MemoryJavaFileObject(String name, JavaFileObject.Kind kind) {
       
    83             super(URI.create("string:///" + name.replace('.', '/')
       
    84                     + kind.extension), kind);
       
    85         }
       
    86     }
       
    87 
       
    88     class SourceMemoryJavaFileObject extends MemoryJavaFileObject {
       
    89         private final String src;
       
    90         private final Object origin;
       
    91 
       
    92         SourceMemoryJavaFileObject(Object origin, String className, String code) {
       
    93             super(className, JavaFileObject.Kind.SOURCE);
       
    94             this.origin = origin;
       
    95             this.src = code;
       
    96         }
       
    97 
       
    98         public Object getOrigin() {
       
    99             return origin;
       
   100         }
       
   101 
       
   102         @Override @DefinedBy(Api.COMPILER)
       
   103         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       
   104             return src;
       
   105         }
       
   106     }
       
   107 
       
   108     static class OutputMemoryJavaFileObject extends MemoryJavaFileObject {
       
   109 
       
   110         /**
       
   111          * Byte code created by the compiler will be stored in this
       
   112          * ByteArrayOutputStream.
       
   113          */
       
   114         private ByteArrayOutputStream bos = new ByteArrayOutputStream();
       
   115         private byte[] bytes = null;
       
   116 
       
   117         private final String className;
       
   118 
       
   119         public OutputMemoryJavaFileObject(String name, JavaFileObject.Kind kind) {
       
   120             super(name, kind);
       
   121             this.className = name;
       
   122         }
       
   123 
       
   124         public byte[] getBytes() {
       
   125             if (bytes == null) {
       
   126                 bytes = bos.toByteArray();
       
   127                 bos = null;
       
   128             }
       
   129             return bytes;
       
   130         }
       
   131 
       
   132         public void dump() {
       
   133             try {
       
   134                 Path dumpDir = FileSystems.getDefault().getPath("dump");
       
   135                 if (Files.notExists(dumpDir)) {
       
   136                     Files.createDirectory(dumpDir);
       
   137                 }
       
   138                 Path file = FileSystems.getDefault().getPath("dump", getName() + ".class");
       
   139                 Files.write(file, getBytes());
       
   140             } catch (IOException ex) {
       
   141                 throw new RuntimeException(ex);
       
   142             }
       
   143         }
       
   144 
       
   145         @Override @DefinedBy(Api.COMPILER)
       
   146         public String getName() {
       
   147             return className;
       
   148         }
       
   149 
       
   150         /**
       
   151          * Will provide the compiler with an output stream that leads to our
       
   152          * byte array.
       
   153          */
       
   154         @Override @DefinedBy(Api.COMPILER)
       
   155         public OutputStream openOutputStream() throws IOException {
       
   156             return bos;
       
   157         }
       
   158 
       
   159         @Override @DefinedBy(Api.COMPILER)
       
   160         public InputStream openInputStream() throws IOException {
       
   161             return new ByteArrayInputStream(getBytes());
       
   162         }
       
   163     }
       
   164 
       
   165     // For restoring process-local execution support
       
   166     class REPLClassLoader extends ClassLoader {
       
   167 
       
   168         @Override
       
   169         protected Class<?> findClass(String name) throws ClassNotFoundException {
       
   170             OutputMemoryJavaFileObject fo = classObjects.get(name);
       
   171             proc.debug(DBG_FMGR, "findClass %s = %s\n", name, fo);
       
   172             if (fo == null) {
       
   173                 throw new ClassNotFoundException("Not ours");
       
   174             }
       
   175             byte[] b = fo.getBytes();
       
   176             return super.defineClass(name, b, 0, b.length, null);
       
   177         }
       
   178     }
       
   179 
       
   180     public MemoryFileManager(StandardJavaFileManager standardManager, JShell proc) {
       
   181         this.stdFileManager = standardManager;
       
   182         this.proc = proc;
       
   183     }
       
   184 
       
   185     private Collection<OutputMemoryJavaFileObject> generatedClasses() {
       
   186         return classObjects.values();
       
   187     }
       
   188 
       
   189     // For debugging dumps
       
   190     public void dumpClasses() {
       
   191         for (OutputMemoryJavaFileObject co : generatedClasses()) {
       
   192             co.dump();
       
   193         }
       
   194     }
       
   195 
       
   196     // For restoring process-local execution support
       
   197     public Class<?> findGeneratedClass(String genClassFullName) throws ClassNotFoundException {
       
   198         for (OutputMemoryJavaFileObject co : generatedClasses()) {
       
   199             if (co.className.equals(genClassFullName)) {
       
   200                 Class<?> klass = loadClass(co.className);
       
   201                 proc.debug(DBG_FMGR, "Loaded %s\n", klass);
       
   202                 return klass;
       
   203             }
       
   204         }
       
   205         return null;
       
   206     }
       
   207 
       
   208     // For restoring process-local execution support
       
   209     public byte[] findGeneratedBytes(String genClassFullName) throws ClassNotFoundException {
       
   210         for (OutputMemoryJavaFileObject co : generatedClasses()) {
       
   211             if (co.className.equals(genClassFullName)) {
       
   212                 return co.getBytes();
       
   213             }
       
   214         }
       
   215         return null;
       
   216     }
       
   217 
       
   218     // For restoring process-local execution support
       
   219     public Class<?> loadClass(String name) throws ClassNotFoundException {
       
   220         return getClassLoader(null).loadClass(name);
       
   221     }
       
   222 
       
   223     public JavaFileObject createSourceFileObject(Object origin, String name, String code) {
       
   224         return new SourceMemoryJavaFileObject(origin, name, code);
       
   225     }
       
   226 
       
   227     // Make compatible with Jigsaw
       
   228     public String inferModuleName(Location location) {
       
   229         try {
       
   230             if (inferModuleNameMethod == null) {
       
   231                 inferModuleNameMethod = JavaFileManager.class.getDeclaredMethod("inferModuleName", Location.class);
       
   232             }
       
   233             @SuppressWarnings("unchecked")
       
   234             String result = (String) inferModuleNameMethod.invoke(stdFileManager, location);
       
   235             return result;
       
   236         } catch (NoSuchMethodException | SecurityException ex) {
       
   237             throw new InternalError("Cannot lookup JavaFileManager method", ex);
       
   238         } catch (IllegalAccessException |
       
   239                 IllegalArgumentException |
       
   240                 InvocationTargetException ex) {
       
   241             throw new InternalError("Cannot invoke JavaFileManager method", ex);
       
   242         }
       
   243     }
       
   244 
       
   245     // Make compatible with Jigsaw
       
   246     public Iterable<Set<Location>> listModuleLocations(Location location) throws IOException {
       
   247         try {
       
   248             if (listModuleLocationsMethod == null) {
       
   249                 listModuleLocationsMethod = JavaFileManager.class.getDeclaredMethod("listModuleLocations", Location.class);
       
   250             }
       
   251             @SuppressWarnings("unchecked")
       
   252             Iterable<Set<Location>> result = (Iterable<Set<Location>>) listModuleLocationsMethod.invoke(stdFileManager, location);
       
   253             return result;
       
   254         } catch (NoSuchMethodException | SecurityException ex) {
       
   255             throw new InternalError("Cannot lookup JavaFileManager method", ex);
       
   256         } catch (IllegalAccessException |
       
   257                 IllegalArgumentException |
       
   258                 InvocationTargetException ex) {
       
   259             throw new InternalError("Cannot invoke JavaFileManager method", ex);
       
   260         }
       
   261     }
       
   262 
       
   263 
       
   264     /**
       
   265      * Returns a class loader for loading plug-ins from the given location. For
       
   266      * example, to load annotation processors, a compiler will request a class
       
   267      * loader for the {@link
       
   268      * StandardLocation#ANNOTATION_PROCESSOR_PATH
       
   269      * ANNOTATION_PROCESSOR_PATH} location.
       
   270      *
       
   271      * @param location a location
       
   272      * @return a class loader for the given location; or {@code null}
       
   273      * if loading plug-ins from the given location is disabled or if
       
   274      * the location is not known
       
   275      * @throws SecurityException if a class loader can not be created
       
   276      * in the current security context
       
   277      * @throws IllegalStateException if {@link #close} has been called
       
   278      * and this file manager cannot be reopened
       
   279      */
       
   280     @Override @DefinedBy(Api.COMPILER)
       
   281     public ClassLoader getClassLoader(JavaFileManager.Location location) {
       
   282         proc.debug(DBG_FMGR, "getClassLoader: location\n", location);
       
   283         return loader;
       
   284     }
       
   285 
       
   286     /**
       
   287      * Lists all file objects matching the given criteria in the given
       
   288      * location.  List file objects in "subpackages" if recurse is
       
   289      * true.
       
   290      *
       
   291      * <p>Note: even if the given location is unknown to this file
       
   292      * manager, it may not return {@code null}.  Also, an unknown
       
   293      * location may not cause an exception.
       
   294      *
       
   295      * @param location     a location
       
   296      * @param packageName  a package name
       
   297      * @param kinds        return objects only of these kinds
       
   298      * @param recurse      if true include "subpackages"
       
   299      * @return an Iterable of file objects matching the given criteria
       
   300      * @throws IOException if an I/O error occurred, or if {@link
       
   301      * #close} has been called and this file manager cannot be
       
   302      * reopened
       
   303      * @throws IllegalStateException if {@link #close} has been called
       
   304      * and this file manager cannot be reopened
       
   305      */
       
   306     @Override @DefinedBy(Api.COMPILER)
       
   307     public Iterable<JavaFileObject> list(JavaFileManager.Location location,
       
   308             String packageName,
       
   309             Set<JavaFileObject.Kind> kinds,
       
   310             boolean recurse)
       
   311             throws IOException {
       
   312         Iterable<JavaFileObject> stdList = stdFileManager.list(location, packageName, kinds, recurse);
       
   313         if (location==CLASS_PATH && packageName.equals("REPL")) {
       
   314             // if the desired list is for our JShell package, lazily iterate over
       
   315             // first the standard list then any generated classes.
       
   316             return () -> new Iterator<JavaFileObject>() {
       
   317                 boolean stdDone = false;
       
   318                 Iterator<? extends JavaFileObject> it;
       
   319 
       
   320                 @Override
       
   321                 public boolean hasNext() {
       
   322                     if (it == null) {
       
   323                         it = stdList.iterator();
       
   324                     }
       
   325                     if (it.hasNext()) {
       
   326                         return true;
       
   327                     }
       
   328                     if (stdDone) {
       
   329                         return false;
       
   330                     } else {
       
   331                         stdDone = true;
       
   332                         it = generatedClasses().iterator();
       
   333                         return it.hasNext();
       
   334                     }
       
   335                 }
       
   336 
       
   337                 @Override
       
   338                 public JavaFileObject next() {
       
   339                     if (!hasNext()) {
       
   340                         throw new NoSuchElementException();
       
   341                     }
       
   342                     return it.next();
       
   343                 }
       
   344 
       
   345             };
       
   346         } else {
       
   347             return stdList;
       
   348         }
       
   349     }
       
   350 
       
   351     /**
       
   352      * Infers a binary name of a file object based on a location.  The
       
   353      * binary name returned might not be a valid binary name according to
       
   354      * <cite>The Java&trade {        throw new UnsupportedOperationException("Not supported yet.");  } Language Specification</cite>.
       
   355      *
       
   356      * @param location a location
       
   357      * @param file a file object
       
   358      * @return a binary name or {@code null} the file object is not
       
   359      * found in the given location
       
   360      * @throws IllegalStateException if {@link #close} has been called
       
   361      * and this file manager cannot be reopened
       
   362      */
       
   363     @Override @DefinedBy(Api.COMPILER)
       
   364     public String inferBinaryName(JavaFileManager.Location location, JavaFileObject file) {
       
   365         if (file instanceof OutputMemoryJavaFileObject) {
       
   366             OutputMemoryJavaFileObject ofo = (OutputMemoryJavaFileObject) file;
       
   367             proc.debug(DBG_FMGR, "inferBinaryName %s => %s\n", file, ofo.getName());
       
   368             return ofo.getName();
       
   369         } else {
       
   370             return stdFileManager.inferBinaryName(location, file);
       
   371         }
       
   372     }
       
   373 
       
   374     /**
       
   375      * Compares two file objects and return true if they represent the
       
   376      * same underlying object.
       
   377      *
       
   378      * @param a a file object
       
   379      * @param b a file object
       
   380      * @return true if the given file objects represent the same
       
   381      * underlying object
       
   382      *
       
   383      * @throws IllegalArgumentException if either of the arguments
       
   384      * were created with another file manager and this file manager
       
   385      * does not support foreign file objects
       
   386      */
       
   387     @Override @DefinedBy(Api.COMPILER)
       
   388     public boolean isSameFile(FileObject a, FileObject b) {
       
   389         return stdFileManager.isSameFile(b, b);
       
   390     }
       
   391 
       
   392     /**
       
   393      * Determines if the given option is supported and if so, the
       
   394      * number of arguments the option takes.
       
   395      *
       
   396      * @param option an option
       
   397      * @return the number of arguments the given option takes or -1 if
       
   398      * the option is not supported
       
   399      */
       
   400     @Override @DefinedBy(Api.COMPILER)
       
   401     public int isSupportedOption(String option) {
       
   402         proc.debug(DBG_FMGR, "isSupportedOption: %s\n", option);
       
   403         return stdFileManager.isSupportedOption(option);
       
   404     }
       
   405 
       
   406     /**
       
   407      * Handles one option.  If {@code current} is an option to this
       
   408      * file manager it will consume any arguments to that option from
       
   409      * {@code remaining} and return true, otherwise return false.
       
   410      *
       
   411      * @param current current option
       
   412      * @param remaining remaining options
       
   413      * @return true if this option was handled by this file manager,
       
   414      * false otherwise
       
   415      * @throws IllegalArgumentException if this option to this file
       
   416      * manager is used incorrectly
       
   417      * @throws IllegalStateException if {@link #close} has been called
       
   418      * and this file manager cannot be reopened
       
   419      */
       
   420     @Override @DefinedBy(Api.COMPILER)
       
   421     public boolean handleOption(String current, Iterator<String> remaining) {
       
   422         proc.debug(DBG_FMGR, "handleOption: current: %s\n", current +
       
   423                 ", remaining: " + remaining);
       
   424         return stdFileManager.handleOption(current, remaining);
       
   425     }
       
   426 
       
   427     /**
       
   428      * Determines if a location is known to this file manager.
       
   429      *
       
   430      * @param location a location
       
   431      * @return true if the location is known
       
   432      */
       
   433     @Override @DefinedBy(Api.COMPILER)
       
   434     public boolean hasLocation(JavaFileManager.Location location) {
       
   435         proc.debug(DBG_FMGR, "hasLocation: location: %s\n", location);
       
   436         return stdFileManager.hasLocation(location);
       
   437     }
       
   438 
       
   439     interface ClassFileCreationListener {
       
   440         void newClassFile(OutputMemoryJavaFileObject jfo, JavaFileManager.Location location,
       
   441                 String className, Kind kind, FileObject sibling);
       
   442     }
       
   443 
       
   444     void registerClassFileCreationListener(ClassFileCreationListener listen) {
       
   445         this.classListener = listen;
       
   446     }
       
   447 
       
   448     /**
       
   449      * Returns a {@linkplain JavaFileObject file object} for input
       
   450      * representing the specified class of the specified kind in the
       
   451      * given location.
       
   452      *
       
   453      * @param location a location
       
   454      * @param className the name of a class
       
   455      * @param kind the kind of file, must be one of {@link
       
   456      * JavaFileObject.Kind#SOURCE SOURCE} or {@link
       
   457      * JavaFileObject.Kind#CLASS CLASS}
       
   458      * @return a file object, might return {@code null} if the
       
   459      * file does not exist
       
   460      * @throws IllegalArgumentException if the location is not known
       
   461      * to this file manager and the file manager does not support
       
   462      * unknown locations, or if the kind is not valid
       
   463      * @throws IOException if an I/O error occurred, or if {@link
       
   464      * #close} has been called and this file manager cannot be
       
   465      * reopened
       
   466      * @throws IllegalStateException if {@link #close} has been called
       
   467      * and this file manager cannot be reopened
       
   468      */
       
   469     @Override @DefinedBy(Api.COMPILER)
       
   470     public JavaFileObject getJavaFileForInput(JavaFileManager.Location location,
       
   471             String className,
       
   472             JavaFileObject.Kind kind)
       
   473             throws IOException {
       
   474         return stdFileManager.getJavaFileForInput(location, className, kind);
       
   475     }
       
   476 
       
   477     /**
       
   478      * Returns a {@linkplain JavaFileObject file object} for output
       
   479      * representing the specified class of the specified kind in the
       
   480      * given location.
       
   481      *
       
   482      * <p>Optionally, this file manager might consider the sibling as
       
   483      * a hint for where to place the output.  The exact semantics of
       
   484      * this hint is unspecified.  The JDK compiler, javac, for
       
   485      * example, will place class files in the same directories as
       
   486      * originating source files unless a class file output directory
       
   487      * is provided.  To facilitate this behavior, javac might provide
       
   488      * the originating source file as sibling when calling this
       
   489      * method.
       
   490      *
       
   491      * @param location a location
       
   492      * @param className the name of a class
       
   493      * @param kind the kind of file, must be one of {@link
       
   494      * JavaFileObject.Kind#SOURCE SOURCE} or {@link
       
   495      * JavaFileObject.Kind#CLASS CLASS}
       
   496      * @param sibling a file object to be used as hint for placement;
       
   497      * might be {@code null}
       
   498      * @return a file object for output
       
   499      * @throws IllegalArgumentException if sibling is not known to
       
   500      * this file manager, or if the location is not known to this file
       
   501      * manager and the file manager does not support unknown
       
   502      * locations, or if the kind is not valid
       
   503      * @throws IOException if an I/O error occurred, or if {@link
       
   504      * #close} has been called and this file manager cannot be
       
   505      * reopened
       
   506      * @throws IllegalStateException {@link #close} has been called
       
   507      * and this file manager cannot be reopened
       
   508      */
       
   509     @Override @DefinedBy(Api.COMPILER)
       
   510     public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
       
   511             String className, Kind kind, FileObject sibling) throws IOException {
       
   512 
       
   513         OutputMemoryJavaFileObject fo;
       
   514         fo = new OutputMemoryJavaFileObject(className, kind);
       
   515         classObjects.put(className, fo);
       
   516         proc.debug(DBG_FMGR, "Set out file: %s = %s\n", className, fo);
       
   517         if (classListener != null) {
       
   518             classListener.newClassFile(fo, location, className, kind, sibling);
       
   519         }
       
   520         return fo;
       
   521     }
       
   522 
       
   523     /**
       
   524      * Returns a {@linkplain FileObject file object} for input
       
   525      * representing the specified <a href="JavaFileManager.html#relative_name">relative
       
   526      * name</a> in the specified package in the given location.
       
   527      *
       
   528      * <p>If the returned object represents a {@linkplain
       
   529      * JavaFileObject.Kind#SOURCE source} or {@linkplain
       
   530      * JavaFileObject.Kind#CLASS class} file, it must be an instance
       
   531      * of {@link JavaFileObject}.
       
   532      *
       
   533      * <p>Informally, the file object returned by this method is
       
   534      * located in the concatenation of the location, package name, and
       
   535      * relative name.  For example, to locate the properties file
       
   536      * "resources/compiler.properties" in the package
       
   537      * "com.sun.tools.javac" in the {@linkplain
       
   538      * StandardLocation#SOURCE_PATH SOURCE_PATH} location, this method
       
   539      * might be called like so:
       
   540      *
       
   541      * <pre>getFileForInput(SOURCE_PATH, "com.sun.tools.javac", "resources/compiler.properties");</pre>
       
   542      *
       
   543      * <p>If the call was executed on Windows, with SOURCE_PATH set to
       
   544      * <code>"C:\Documents&nbsp;and&nbsp;Settings\UncleBob\src\share\classes"</code>,
       
   545      * a valid result would be a file object representing the file
       
   546      * <code>"C:\Documents&nbsp;and&nbsp;Settings\UncleBob\src\share\classes\com\sun\tools\javac\resources\compiler.properties"</code>.
       
   547      *
       
   548      * @param location a location
       
   549      * @param packageName a package name
       
   550      * @param relativeName a relative name
       
   551      * @return a file object, might return {@code null} if the file
       
   552      * does not exist
       
   553      * @throws IllegalArgumentException if the location is not known
       
   554      * to this file manager and the file manager does not support
       
   555      * unknown locations, or if {@code relativeName} is not valid
       
   556      * @throws IOException if an I/O error occurred, or if {@link
       
   557      * #close} has been called and this file manager cannot be
       
   558      * reopened
       
   559      * @throws IllegalStateException if {@link #close} has been called
       
   560      * and this file manager cannot be reopened
       
   561      */
       
   562     @Override @DefinedBy(Api.COMPILER)
       
   563     public FileObject getFileForInput(JavaFileManager.Location location,
       
   564             String packageName,
       
   565             String relativeName)
       
   566             throws IOException {
       
   567         proc.debug(DBG_FMGR, "getFileForInput location=%s packageName=%s\n", location, packageName);
       
   568         return stdFileManager.getFileForInput(location, packageName, relativeName);
       
   569     }
       
   570 
       
   571     /**
       
   572      * Returns a {@linkplain FileObject file object} for output
       
   573      * representing the specified <a href="JavaFileManager.html#relative_name">relative
       
   574      * name</a> in the specified package in the given location.
       
   575      *
       
   576      * <p>Optionally, this file manager might consider the sibling as
       
   577      * a hint for where to place the output.  The exact semantics of
       
   578      * this hint is unspecified.  The JDK compiler, javac, for
       
   579      * example, will place class files in the same directories as
       
   580      * originating source files unless a class file output directory
       
   581      * is provided.  To facilitate this behavior, javac might provide
       
   582      * the originating source file as sibling when calling this
       
   583      * method.
       
   584      *
       
   585      * <p>If the returned object represents a {@linkplain
       
   586      * JavaFileObject.Kind#SOURCE source} or {@linkplain
       
   587      * JavaFileObject.Kind#CLASS class} file, it must be an instance
       
   588      * of {@link JavaFileObject}.
       
   589      *
       
   590      * <p>Informally, the file object returned by this method is
       
   591      * located in the concatenation of the location, package name, and
       
   592      * relative name or next to the sibling argument.  See {@link
       
   593      * #getFileForInput getFileForInput} for an example.
       
   594      *
       
   595      * @param location a location
       
   596      * @param packageName a package name
       
   597      * @param relativeName a relative name
       
   598      * @param sibling a file object to be used as hint for placement;
       
   599      * might be {@code null}
       
   600      * @return a file object
       
   601      * @throws IllegalArgumentException if sibling is not known to
       
   602      * this file manager, or if the location is not known to this file
       
   603      * manager and the file manager does not support unknown
       
   604      * locations, or if {@code relativeName} is not valid
       
   605      * @throws IOException if an I/O error occurred, or if {@link
       
   606      * #close} has been called and this file manager cannot be
       
   607      * reopened
       
   608      * @throws IllegalStateException if {@link #close} has been called
       
   609      * and this file manager cannot be reopened
       
   610      */
       
   611     @Override @DefinedBy(Api.COMPILER)
       
   612     public FileObject getFileForOutput(JavaFileManager.Location location,
       
   613             String packageName,
       
   614             String relativeName,
       
   615             FileObject sibling)
       
   616             throws IOException {
       
   617         throw new UnsupportedOperationException("getFileForOutput: location: " + location +
       
   618                 ", packageName: " + packageName +
       
   619                 ", relativeName: " + relativeName +
       
   620                 ", sibling: " + sibling);
       
   621     }
       
   622 
       
   623     /**
       
   624      * Flushes any resources opened for output by this file manager
       
   625      * directly or indirectly.  Flushing a closed file manager has no
       
   626      * effect.
       
   627      *
       
   628      * @throws IOException if an I/O error occurred
       
   629      * @see #close
       
   630      */
       
   631     @Override @DefinedBy(Api.COMPILER)
       
   632     public void flush() throws IOException {
       
   633         // Nothing to flush
       
   634     }
       
   635 
       
   636     /**
       
   637      * Releases any resources opened by this file manager directly or
       
   638      * indirectly.  This might render this file manager useless and
       
   639      * the effect of subsequent calls to methods on this object or any
       
   640      * objects obtained through this object is undefined unless
       
   641      * explicitly allowed.  However, closing a file manager which has
       
   642      * already been closed has no effect.
       
   643      *
       
   644      * @throws IOException if an I/O error occurred
       
   645      * @see #flush
       
   646      */
       
   647     @Override @DefinedBy(Api.COMPILER)
       
   648     public void close() throws IOException {
       
   649         // Nothing to close
       
   650     }
       
   651 }