8002079: update DocFile to use a JavaFileManager
authorjjg
Thu, 15 Nov 2012 19:54:20 -0800
changeset 14544 d71d992cb905
parent 14543 43edeaf6d0a9
child 14545 2e7bab0639b8
8002079: update DocFile to use a JavaFileManager Reviewed-by: darcy
langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFile.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFileFactory.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocPath.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/PathDocFileFactory.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SimpleDocFileFactory.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/StandardDocFileFactory.java
langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java	Thu Nov 15 14:41:31 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java	Thu Nov 15 19:54:20 2012 -0800
@@ -28,9 +28,13 @@
 import java.net.*;
 import java.util.*;
 
+import javax.tools.JavaFileManager;
+
 import com.sun.javadoc.*;
 import com.sun.tools.doclets.internal.toolkit.*;
 import com.sun.tools.doclets.internal.toolkit.util.*;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
 
 /**
  * Configure the output based on the command line options.
@@ -195,6 +199,7 @@
     /**
      * Return the build date for the doclet.
      */
+    @Override
     public String getDocletSpecificBuildDate() {
         return BUILD_DATE;
     }
@@ -205,6 +210,7 @@
      *
      * @param options The array of option names and values.
      */
+    @Override
     public void setSpecificDocletOptions(String[][] options) {
         for (int oi = 0; oi < options.length; ++oi) {
             String[] os = options[oi];
@@ -323,6 +329,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean validOptions(String options[][],
             DocErrorReporter reporter) {
         boolean helpfile = false;
@@ -411,6 +418,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public MessageRetriever getDocletSpecificMsg() {
         return standardmessage;
     }
@@ -480,6 +488,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public WriterFactory getWriterFactory() {
         return new WriterFactoryImpl(this);
     }
@@ -487,6 +496,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Comparator<ProgramElementDoc> getMemberComparator() {
         return null;
     }
@@ -494,10 +504,22 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public Locale getLocale() {
         if (root instanceof com.sun.tools.javadoc.RootDocImpl)
             return ((com.sun.tools.javadoc.RootDocImpl)root).getLocale();
         else
             return Locale.getDefault();
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public JavaFileManager getFileManager() {
+        if (root instanceof com.sun.tools.javadoc.RootDocImpl)
+            return ((com.sun.tools.javadoc.RootDocImpl)root).getFileManager();
+        else
+            return new JavacFileManager(new Context(), false, null);
+    }
 }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java	Thu Nov 15 14:41:31 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java	Thu Nov 15 19:54:20 2012 -0800
@@ -31,6 +31,7 @@
 import com.sun.javadoc.*;
 import com.sun.tools.doclets.formats.html.ConfigurationImpl;
 import com.sun.tools.doclets.internal.toolkit.*;
+import com.sun.tools.doclets.internal.toolkit.util.DocFile;
 import com.sun.tools.doclets.internal.toolkit.util.DocLink;
 import com.sun.tools.doclets.internal.toolkit.util.DocPath;
 import com.sun.tools.doclets.internal.toolkit.util.DocPaths;
@@ -63,7 +64,7 @@
             throws IOException {
         super(configuration, filename);
         configuration.message.notice("doclet.Generating_0",
-            filename.resolveAgainst(configuration.destDirName));
+            DocFile.createFileForOutput(configuration, filename).getPath());
     }
 
     /**
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java	Thu Nov 15 14:41:31 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java	Thu Nov 15 19:54:20 2012 -0800
@@ -32,6 +32,7 @@
 import com.sun.tools.doclets.internal.toolkit.builders.BuilderFactory;
 import com.sun.tools.doclets.internal.toolkit.taglets.*;
 import com.sun.tools.doclets.internal.toolkit.util.*;
+import javax.tools.JavaFileManager;
 
 /**
  * Configure the output based on the options. Doclets should sub-class
@@ -752,7 +753,7 @@
      * @return the input steam to the builder XML.
      * @throws FileNotFoundException when the given XML file cannot be found.
      */
-    public InputStream getBuilderXML() throws FileNotFoundException {
+    public InputStream getBuilderXML() throws IOException {
         return builderXMLPath == null ?
             Configuration.class.getResourceAsStream(DEFAULT_BUILDER_XML) :
             DocFile.createFileForInput(this, builderXMLPath).openInputStream();
@@ -764,6 +765,11 @@
     public abstract Locale getLocale();
 
     /**
+     * Return the current file manager.
+     */
+    public abstract JavaFileManager getFileManager();
+
+    /**
      * Return the comparator that will be used to sort member documentation.
      * To no do any sorting, return null.
      *
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFile.java	Thu Nov 15 14:41:31 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFile.java	Thu Nov 15 19:54:20 2012 -0800
@@ -25,30 +25,21 @@
 
 package com.sun.tools.doclets.internal.toolkit.util;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
 
 import javax.tools.JavaFileManager.Location;
 import javax.tools.StandardLocation;
 
 import com.sun.tools.doclets.internal.toolkit.Configuration;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
 
 /**
  * Abstraction for handling files, which may be specified directly
@@ -61,46 +52,36 @@
  *
  * @since 8
  */
-public class DocFile {
+public abstract class DocFile {
+
+    /** Create a DocFile for a directory. */
+    public static DocFile createFileForDirectory(Configuration configuration, String file) {
+        return DocFileFactory.getFactory(configuration).createFileForDirectory(file);
+    }
 
-    /**
-     * The doclet configuration.
-     * Provides access to options such as docencoding, output directory, etc.
-     */
+    /** Create a DocFile for a file that will be opened for reading. */
+    public static DocFile createFileForInput(Configuration configuration, String file) {
+        return DocFileFactory.getFactory(configuration).createFileForInput(file);
+    }
+
+    /** Create a DocFile for a file that will be opened for writing. */
+    public static DocFile createFileForOutput(Configuration configuration, DocPath path) {
+        return DocFileFactory.getFactory(configuration).createFileForOutput(path);
+    }
+
     private final Configuration configuration;
 
     /**
      * The location for this file. Maybe null if the file was created without
      * a location or path.
      */
-    private final Location location;
+    protected final Location location;
 
     /**
      * The path relative to the (output) location. Maybe null if the file was
      * created without a location or path.
      */
-    private final DocPath path;
-
-    /**
-     * The file object itself.
-     * This is temporary, until we create different subtypes of DocFile.
-     */
-    private final File file;
-
-    /** Create a DocFile for a directory. */
-    public static DocFile createFileForDirectory(Configuration configuration, String file) {
-        return new DocFile(configuration, new File(file));
-    }
-
-    /** Create a DocFile for a file that will be opened for reading. */
-    public static DocFile createFileForInput(Configuration configuration, String file) {
-        return new DocFile(configuration, new File(file));
-    }
-
-    /** Create a DocFile for a file that will be opened for writing. */
-    public static DocFile createFileForOutput(Configuration configuration, DocPath path) {
-        return new DocFile(configuration, StandardLocation.CLASS_OUTPUT, path);
-    }
+    protected final DocPath path;
 
     /**
      * List the directories and files found in subdirectories along the
@@ -111,56 +92,32 @@
      *  list files
      */
     public static Iterable<DocFile> list(Configuration configuration, Location location, DocPath path) {
-        if (location != StandardLocation.SOURCE_PATH)
-            throw new IllegalArgumentException();
-
-        Set<DocFile> files = new LinkedHashSet<DocFile>();
-        for (String s : configuration.sourcepath.split(File.pathSeparator)) {
-            if (s.isEmpty())
-                continue;
-            File f = new File(s);
-            if (f.isDirectory()) {
-                f = new File(f, path.getPath());
-                if (f.exists())
-                    files.add(new DocFile(configuration, f));
-            }
-        }
-        return files;
+        return DocFileFactory.getFactory(configuration).list(location, path);
     }
 
-    /** Create a DocFile for a given file. */
-    private DocFile(Configuration configuration, File file) {
+    /** Create a DocFile without a location or path */
+    protected DocFile(Configuration configuration) {
         this.configuration = configuration;
         this.location = null;
         this.path = null;
-        this.file = file;
     }
 
     /** Create a DocFile for a given location and relative path. */
-    private DocFile(Configuration configuration, Location location, DocPath path) {
+    protected DocFile(Configuration configuration, Location location, DocPath path) {
         this.configuration = configuration;
         this.location = location;
         this.path = path;
-        this.file = path.resolveAgainst(configuration.destDirName);
     }
 
     /** Open an input stream for the file. */
-    public InputStream openInputStream() throws FileNotFoundException {
-        return new BufferedInputStream(new FileInputStream(file));
-    }
+    public abstract InputStream openInputStream() throws IOException;
 
     /**
      * Open an output stream for the file.
      * The file must have been created with a location of
      * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
      */
-    public OutputStream openOutputStream() throws IOException, UnsupportedEncodingException {
-        if (location != StandardLocation.CLASS_OUTPUT)
-            throw new IllegalStateException();
-
-        createDirectoryForFile(file);
-        return new BufferedOutputStream(new FileOutputStream(file));
-    }
+    public abstract OutputStream openOutputStream() throws IOException, UnsupportedEncodingException;
 
     /**
      * Open an writer for the file, using the encoding (if any) given in the
@@ -168,28 +125,12 @@
      * The file must have been created with a location of
      * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
      */
-    public Writer openWriter() throws IOException, UnsupportedEncodingException {
-        if (location != StandardLocation.CLASS_OUTPUT)
-            throw new IllegalStateException();
-
-        createDirectoryForFile(file);
-        FileOutputStream fos = new FileOutputStream(file);
-        if (configuration.docencoding == null) {
-            return new BufferedWriter(new OutputStreamWriter(fos));
-        } else {
-            return new BufferedWriter(new OutputStreamWriter(fos, configuration.docencoding));
-        }
-    }
+    public abstract Writer openWriter() throws IOException, UnsupportedEncodingException;
 
     /**
      * Copy the contents of another file directly to this file.
      */
     public void copyFile(DocFile fromFile) throws IOException {
-        if (location != StandardLocation.CLASS_OUTPUT)
-            throw new IllegalStateException();
-
-        createDirectoryForFile(file);
-
         InputStream input = fromFile.openInputStream();
         OutputStream output = openOutputStream();
         try {
@@ -215,20 +156,15 @@
      *     separator
      */
     public void copyResource(DocPath resource, boolean overwrite, boolean replaceNewLine) {
-        if (location != StandardLocation.CLASS_OUTPUT)
-            throw new IllegalStateException();
-
-        if (file.exists() && !overwrite)
+        if (exists() && !overwrite)
             return;
 
-        createDirectoryForFile(file);
-
         try {
             InputStream in = Configuration.class.getResourceAsStream(resource.getPath());
             if (in == null)
                 return;
 
-            OutputStream out = new FileOutputStream(file);
+            OutputStream out = openOutputStream();
             try {
                 if (!replaceNewLine) {
                     byte[] buf = new byte[2048];
@@ -265,68 +201,37 @@
     }
 
     /** Return true if the file can be read. */
-    public boolean canRead() {
-        return file.canRead();
-    }
+    public abstract boolean canRead();
 
     /** Return true if the file can be written. */
-    public boolean canWrite() {
-        return file.canRead();
-    }
+    public abstract boolean canWrite();
 
     /** Return true if the file exists. */
-    public boolean exists() {
-        return file.exists();
-    }
+    public abstract boolean exists();
 
     /** Return the base name (last component) of the file name. */
-    public String getName() {
-        return file.getName();
-    }
+    public abstract String getName();
 
     /** Return the file system path for this file. */
-    public String getPath() {
-        return file.getPath();
-    }
+    public abstract String getPath();
 
-    /** Return true is file has an absolute path name. */
-    boolean isAbsolute() {
-        return file.isAbsolute();
-    }
+    /** Return true if file has an absolute path name. */
+    public abstract boolean isAbsolute();
 
-    /** Return true is file identifies a directory. */
-    public boolean isDirectory() {
-        return file.isDirectory();
-    }
+    /** Return true if file identifies a directory. */
+    public abstract boolean isDirectory();
 
-    /** Return true is file identifies a file. */
-    public boolean isFile() {
-        return file.isFile();
-    }
+    /** Return true if file identifies a file. */
+    public abstract boolean isFile();
 
     /** Return true if this file is the same as another. */
-    public boolean isSameFile(DocFile other) {
-        try {
-            return file.exists()
-                    && file.getCanonicalFile().equals(other.file.getCanonicalFile());
-        } catch (IOException e) {
-            return false;
-        }
-    }
+    public abstract boolean isSameFile(DocFile other);
 
     /** If the file is a directory, list its contents. */
-    public Iterable<DocFile> list() {
-        List<DocFile> files = new ArrayList<DocFile>();
-        for (File f: file.listFiles()) {
-            files.add(new DocFile(configuration, f));
-        }
-        return files;
-    }
+    public abstract Iterable<DocFile> list() throws IOException;
 
     /** Create the file as a directory, including any parent directories. */
-    public boolean mkdirs() {
-        return file.mkdirs();
-    }
+    public abstract boolean mkdirs();
 
     /**
      * Derive a new file by resolving a relative path against this file.
@@ -334,9 +239,7 @@
      * If this file has a path set, the new file will have a corresponding
      * new path.
      */
-    public DocFile resolve(DocPath p) {
-        return resolve(p.getPath());
-    }
+    public abstract DocFile resolve(DocPath p);
 
     /**
      * Derive a new file by resolving a relative path against this file.
@@ -344,56 +247,11 @@
      * If this file has a path set, the new file will have a corresponding
      * new path.
      */
-    public DocFile resolve(String p) {
-        if (location == null && path == null) {
-            return new DocFile(configuration, new File(file, p));
-        } else {
-            return new DocFile(configuration, location, path.resolve(p));
-        }
-    }
+    public abstract DocFile resolve(String p);
 
     /**
      * Resolve a relative file against the given output location.
      * @param locn Currently, only SOURCE_OUTPUT is supported.
      */
-    public DocFile resolveAgainst(StandardLocation locn) {
-        if (locn != StandardLocation.CLASS_OUTPUT)
-            throw new IllegalArgumentException();
-        return new DocFile(configuration,
-                new File(configuration.destDirName, file.getPath()));
-    }
-
-    /**
-     * Given a path string create all the directories in the path. For example,
-     * if the path string is "java/applet", the method will create directory
-     * "java" and then "java/applet" if they don't exist. The file separator
-     * string "/" is platform dependent system property.
-     *
-     * @param path Directory path string.
-     */
-    private void createDirectoryForFile(File file) {
-        File dir = file.getParentFile();
-        if (dir == null || dir.exists() || dir.mkdirs())
-            return;
-
-        configuration.message.error(
-               "doclet.Unable_to_create_directory_0", dir.getPath());
-        throw new DocletAbortException();
-    }
-
-    /** Return a string to identify the contents of this object,
-     * for debugging purposes.
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("DocFile[");
-        if (location != null)
-            sb.append("locn:").append(location).append(",");
-        if (path != null)
-            sb.append("path:").append(path.getPath()).append(",");
-        sb.append("file:").append(file);
-        sb.append("]");
-        return sb.toString();
-    }
+    public abstract DocFile resolveAgainst(StandardLocation locn);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFileFactory.java	Thu Nov 15 19:54:20 2012 -0800
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclets.internal.toolkit.util;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+
+import com.sun.tools.doclets.internal.toolkit.Configuration;
+
+/**
+ * Factory for DocFile objects.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @since 1.8
+ */
+abstract class DocFileFactory {
+    private static Map<Configuration, DocFileFactory> factories =
+            new WeakHashMap<Configuration, DocFileFactory>();
+
+    /**
+     * Get the appropriate factory, based on the file manager given in the
+     * configuration.
+     */
+    static synchronized DocFileFactory getFactory(Configuration configuration) {
+        DocFileFactory f = factories.get(configuration);
+        if (f == null) {
+            JavaFileManager fm = configuration.getFileManager();
+            if (fm instanceof StandardJavaFileManager)
+                f = new StandardDocFileFactory(configuration);
+            else {
+                try {
+                    Class<?> pathFileManagerClass =
+                            Class.forName("com.sun.tools.javac.nio.PathFileManager");
+                    if (pathFileManagerClass.isAssignableFrom(fm.getClass()))
+                        f = new PathDocFileFactory(configuration);
+                } catch (Throwable t) {
+                    throw new IllegalStateException(t);
+                }
+            }
+        }
+        return f;
+    }
+
+    protected Configuration configuration;
+
+    protected DocFileFactory(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    /** Create a DocFile for a directory. */
+    abstract DocFile createFileForDirectory(String file);
+
+    /** Create a DocFile for a file that will be opened for reading. */
+    abstract DocFile createFileForInput(String file);
+
+    /** Create a DocFile for a file that will be opened for writing. */
+    abstract DocFile createFileForOutput(DocPath path);
+
+    /**
+     * List the directories and files found in subdirectories along the
+     * elements of the given location.
+     * @param location currently, only {@link StandardLocation#SOURCE_PATH} is supported.
+     * @param path the subdirectory of the directories of the location for which to
+     *  list files
+     */
+    abstract Iterable<DocFile> list(Location location, DocPath path);
+}
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocPath.java	Thu Nov 15 14:41:31 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocPath.java	Thu Nov 15 19:54:20 2012 -0800
@@ -27,7 +27,6 @@
 
 import com.sun.javadoc.ClassDoc;
 import com.sun.javadoc.PackageDoc;
-import java.io.File;
 
 /**
  * Abstraction for immutable relative paths.
@@ -159,15 +158,6 @@
     }
 
     /**
-     * Get the file created by evaluating the path against a specified directory.
-     */
-    // Temporary: this signature should not use String for dir.
-    // Eventually, this should involve javax.tools.Location.
-    public File resolveAgainst(String dir) {
-        return dir.isEmpty() ? new File(path) : new File(dir, path);
-    }
-
-    /**
      * Return the inverse path for this path.
      * For example, if the path is a/b/c, the inverse path is ../../..
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/PathDocFileFactory.java	Thu Nov 15 19:54:20 2012 -0800
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.doclets.internal.toolkit.util;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+
+import com.sun.tools.doclets.internal.toolkit.Configuration;
+import com.sun.tools.javac.nio.PathFileManager;
+
+
+/**
+ * Implementation of DocFileFactory using a {@link PathFileManager}.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @since 1.8
+ */
+class PathDocFileFactory extends DocFileFactory {
+    private final PathFileManager fileManager;
+    private final Path destDir;
+
+    public PathDocFileFactory(Configuration configuration) {
+        super(configuration);
+        fileManager = (PathFileManager) configuration.getFileManager();
+
+        if (!configuration.destDirName.isEmpty()
+                || !fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) {
+            try {
+                String dirName = configuration.destDirName.isEmpty() ? "." : configuration.destDirName;
+                Path dir = fileManager.getDefaultFileSystem().getPath(dirName);
+                fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(dir));
+            } catch (IOException e) {
+                throw new DocletAbortException();
+            }
+        }
+
+        destDir = fileManager.getLocation(StandardLocation.CLASS_OUTPUT).iterator().next();
+    }
+
+    public DocFile createFileForDirectory(String file) {
+        return new StandardDocFile(fileManager.getDefaultFileSystem().getPath(file));
+    }
+
+    public DocFile createFileForInput(String file) {
+        return new StandardDocFile(fileManager.getDefaultFileSystem().getPath(file));
+    }
+
+    public DocFile createFileForOutput(DocPath path) {
+        return new StandardDocFile(StandardLocation.CLASS_OUTPUT, path);
+    }
+
+    @Override
+    Iterable<DocFile> list(Location location, DocPath path) {
+        if (location != StandardLocation.SOURCE_PATH)
+            throw new IllegalArgumentException();
+
+        Set<DocFile> files = new LinkedHashSet<DocFile>();
+        if (fileManager.hasLocation(location)) {
+            for (Path f: fileManager.getLocation(location)) {
+                if (Files.isDirectory(f)) {
+                    f = f.resolve(path.getPath());
+                    if (Files.exists(f))
+                        files.add(new StandardDocFile(f));
+                }
+            }
+        }
+        return files;
+    }
+
+    class StandardDocFile extends DocFile {
+        private Path file;
+
+        /** Create a StandardDocFile for a given file. */
+        private StandardDocFile(Path file) {
+            super(configuration);
+            this.file = file;
+        }
+
+        /** Create a StandardDocFile for a given location and relative path. */
+        private StandardDocFile(Location location, DocPath path) {
+            super(configuration, location, path);
+            this.file = destDir.resolve(path.getPath());
+        }
+
+        /** Open an input stream for the file. */
+        public InputStream openInputStream() throws IOException {
+            JavaFileObject fo = getJavaFileObjectForInput(file);
+            return new BufferedInputStream(fo.openInputStream());
+        }
+
+        /**
+         * Open an output stream for the file.
+         * The file must have been created with a location of
+         * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
+         */
+        public OutputStream openOutputStream() throws IOException, UnsupportedEncodingException {
+            if (location != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalStateException();
+
+            OutputStream out = getFileObjectForOutput(path).openOutputStream();
+            return new BufferedOutputStream(out);
+        }
+
+        /**
+         * Open an writer for the file, using the encoding (if any) given in the
+         * doclet configuration.
+         * The file must have been created with a location of
+         * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
+         */
+        public Writer openWriter() throws IOException, UnsupportedEncodingException {
+            if (location != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalStateException();
+
+            OutputStream out = getFileObjectForOutput(path).openOutputStream();
+            if (configuration.docencoding == null) {
+                return new BufferedWriter(new OutputStreamWriter(out));
+            } else {
+                return new BufferedWriter(new OutputStreamWriter(out, configuration.docencoding));
+            }
+        }
+
+        /** Return true if the file can be read. */
+        public boolean canRead() {
+            return Files.isReadable(file);
+        }
+
+        /** Return true if the file can be written. */
+        public boolean canWrite() {
+            return Files.isWritable(file);
+        }
+
+        /** Return true if the file exists. */
+        public boolean exists() {
+            return Files.exists(file);
+        }
+
+        /** Return the base name (last component) of the file name. */
+        public String getName() {
+            return file.getFileName().toString();
+        }
+
+        /** Return the file system path for this file. */
+        public String getPath() {
+            return file.toString();
+        }
+
+        /** Return true is file has an absolute path name. */
+        public boolean isAbsolute() {
+            return file.isAbsolute();
+        }
+
+        /** Return true is file identifies a directory. */
+        public boolean isDirectory() {
+            return Files.isDirectory(file);
+        }
+
+        /** Return true is file identifies a file. */
+        public boolean isFile() {
+            return Files.isRegularFile(file);
+        }
+
+        /** Return true if this file is the same as another. */
+        public boolean isSameFile(DocFile other) {
+            if (!(other instanceof StandardDocFile))
+                return false;
+
+            try {
+                return Files.isSameFile(file, ((StandardDocFile) other).file);
+            } catch (IOException e) {
+                return false;
+            }
+        }
+
+        /** If the file is a directory, list its contents. */
+        public Iterable<DocFile> list() throws IOException {
+            List<DocFile> files = new ArrayList<DocFile>();
+            for (Path f: Files.newDirectoryStream(file)) {
+                files.add(new StandardDocFile(f));
+            }
+            return files;
+        }
+
+        /** Create the file as a directory, including any parent directories. */
+        public boolean mkdirs() {
+            try {
+                Files.createDirectories(file);
+                return true;
+            } catch (IOException e) {
+                return false;
+            }
+        }
+
+        /**
+         * Derive a new file by resolving a relative path against this file.
+         * The new file will inherit the configuration and location of this file
+         * If this file has a path set, the new file will have a corresponding
+         * new path.
+         */
+        public DocFile resolve(DocPath p) {
+            return resolve(p.getPath());
+        }
+
+        /**
+         * Derive a new file by resolving a relative path against this file.
+         * The new file will inherit the configuration and location of this file
+         * If this file has a path set, the new file will have a corresponding
+         * new path.
+         */
+        public DocFile resolve(String p) {
+            if (location == null && path == null) {
+                return new StandardDocFile(file.resolve(p));
+            } else {
+                return new StandardDocFile(location, path.resolve(p));
+            }
+        }
+
+        /**
+         * Resolve a relative file against the given output location.
+         * @param locn Currently, only SOURCE_OUTPUT is supported.
+         */
+        public DocFile resolveAgainst(StandardLocation locn) {
+            if (locn != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalArgumentException();
+            return new StandardDocFile(destDir.resolve(file));
+        }
+
+        /** Return a string to identify the contents of this object,
+         * for debugging purposes.
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("PathDocFile[");
+            if (location != null)
+                sb.append("locn:").append(location).append(",");
+            if (path != null)
+                sb.append("path:").append(path.getPath()).append(",");
+            sb.append("file:").append(file);
+            sb.append("]");
+            return sb.toString();
+        }
+
+        private JavaFileObject getJavaFileObjectForInput(Path file) {
+            return fileManager.getJavaFileObjects(file).iterator().next();
+        }
+
+        private FileObject getFileObjectForOutput(DocPath path) throws IOException {
+            // break the path into a package-part and the rest, by finding
+            // the position of the last '/' before an invalid character for a
+            // package name, such as the "." before an extension or the "-"
+            // in filenames like package-summary.html, doc-files or src-html.
+            String p = path.getPath();
+            int lastSep = -1;
+            for (int i = 0; i < p.length(); i++) {
+                char ch = p.charAt(i);
+                if (ch == '/') {
+                    lastSep = i;
+                } else if (i == lastSep + 1 && !Character.isJavaIdentifierStart(ch)
+                        || !Character.isJavaIdentifierPart(ch)) {
+                    break;
+                }
+            }
+            String pkg = (lastSep == -1) ? "" : p.substring(0, lastSep);
+            String rest = p.substring(lastSep + 1);
+            return fileManager.getFileForOutput(location, pkg, rest, null);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SimpleDocFileFactory.java	Thu Nov 15 19:54:20 2012 -0800
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclets.internal.toolkit.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.tools.JavaFileManager.Location;
+import javax.tools.StandardLocation;
+
+import com.sun.tools.doclets.internal.toolkit.Configuration;
+
+/**
+ * Implementation of DocFileFactory that just uses java.io.File API,
+ * and does not use a JavaFileManager..
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @since 1.8
+ */
+class SimpleDocFileFactory extends DocFileFactory {
+
+    public SimpleDocFileFactory(Configuration configuration) {
+        super(configuration);
+    }
+
+    public DocFile createFileForDirectory(String file) {
+        return new SimpleDocFile(new File(file));
+    }
+
+    public DocFile createFileForInput(String file) {
+        return new SimpleDocFile(new File(file));
+    }
+
+    public DocFile createFileForOutput(DocPath path) {
+        return new SimpleDocFile(StandardLocation.CLASS_OUTPUT, path);
+    }
+
+    @Override
+    Iterable<DocFile> list(Location location, DocPath path) {
+        if (location != StandardLocation.SOURCE_PATH)
+            throw new IllegalArgumentException();
+
+        Set<DocFile> files = new LinkedHashSet<DocFile>();
+        for (String s : configuration.sourcepath.split(File.pathSeparator)) {
+            if (s.isEmpty())
+                continue;
+            File f = new File(s);
+            if (f.isDirectory()) {
+                f = new File(f, path.getPath());
+                if (f.exists())
+                    files.add(new SimpleDocFile(f));
+            }
+        }
+        return files;
+    }
+
+    class SimpleDocFile extends DocFile {
+        private File file;
+
+        /** Create a DocFile for a given file. */
+        private SimpleDocFile(File file) {
+            super(configuration);
+            this.file = file;
+        }
+
+        /** Create a DocFile for a given location and relative path. */
+        private SimpleDocFile(Location location, DocPath path) {
+            super(configuration, location, path);
+            String destDirName = configuration.destDirName;
+            this.file = destDirName.isEmpty() ? new File(path.getPath())
+                    : new File(destDirName, path.getPath());
+        }
+
+        /** Open an input stream for the file. */
+        public InputStream openInputStream() throws FileNotFoundException {
+            return new BufferedInputStream(new FileInputStream(file));
+        }
+
+        /**
+         * Open an output stream for the file.
+         * The file must have been created with a location of
+         * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
+         */
+        public OutputStream openOutputStream() throws IOException, UnsupportedEncodingException {
+            if (location != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalStateException();
+
+            createDirectoryForFile(file);
+            return new BufferedOutputStream(new FileOutputStream(file));
+        }
+
+        /**
+         * Open an writer for the file, using the encoding (if any) given in the
+         * doclet configuration.
+         * The file must have been created with a location of
+         * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
+         */
+        public Writer openWriter() throws IOException, UnsupportedEncodingException {
+            if (location != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalStateException();
+
+            createDirectoryForFile(file);
+            FileOutputStream fos = new FileOutputStream(file);
+            if (configuration.docencoding == null) {
+                return new BufferedWriter(new OutputStreamWriter(fos));
+            } else {
+                return new BufferedWriter(new OutputStreamWriter(fos, configuration.docencoding));
+            }
+        }
+
+        /** Return true if the file can be read. */
+        public boolean canRead() {
+            return file.canRead();
+        }
+
+        /** Return true if the file can be written. */
+        public boolean canWrite() {
+            return file.canRead();
+        }
+
+        /** Return true if the file exists. */
+        public boolean exists() {
+            return file.exists();
+        }
+
+        /** Return the base name (last component) of the file name. */
+        public String getName() {
+            return file.getName();
+        }
+
+        /** Return the file system path for this file. */
+        public String getPath() {
+            return file.getPath();
+        }
+
+        /** Return true is file has an absolute path name. */
+        public boolean isAbsolute() {
+            return file.isAbsolute();
+        }
+
+        /** Return true is file identifies a directory. */
+        public boolean isDirectory() {
+            return file.isDirectory();
+        }
+
+        /** Return true is file identifies a file. */
+        public boolean isFile() {
+            return file.isFile();
+        }
+
+        /** Return true if this file is the same as another. */
+        public boolean isSameFile(DocFile other) {
+            if (!(other instanceof SimpleDocFile))
+                return false;
+
+            try {
+                return file.exists()
+                        && file.getCanonicalFile().equals(((SimpleDocFile)other).file.getCanonicalFile());
+            } catch (IOException e) {
+                return false;
+            }
+        }
+
+        /** If the file is a directory, list its contents. */
+        public Iterable<DocFile> list() {
+            List<DocFile> files = new ArrayList<DocFile>();
+            for (File f: file.listFiles()) {
+                files.add(new SimpleDocFile(f));
+            }
+            return files;
+        }
+
+        /** Create the file as a directory, including any parent directories. */
+        public boolean mkdirs() {
+            return file.mkdirs();
+        }
+
+        /**
+         * Derive a new file by resolving a relative path against this file.
+         * The new file will inherit the configuration and location of this file
+         * If this file has a path set, the new file will have a corresponding
+         * new path.
+         */
+        public DocFile resolve(DocPath p) {
+            return resolve(p.getPath());
+        }
+
+        /**
+         * Derive a new file by resolving a relative path against this file.
+         * The new file will inherit the configuration and location of this file
+         * If this file has a path set, the new file will have a corresponding
+         * new path.
+         */
+        public DocFile resolve(String p) {
+            if (location == null && path == null) {
+                return new SimpleDocFile(new File(file, p));
+            } else {
+                return new SimpleDocFile(location, path.resolve(p));
+            }
+        }
+
+        /**
+         * Resolve a relative file against the given output location.
+         * @param locn Currently, only SOURCE_OUTPUT is supported.
+         */
+        public DocFile resolveAgainst(StandardLocation locn) {
+            if (locn != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalArgumentException();
+            return new SimpleDocFile(
+                    new File(configuration.destDirName, file.getPath()));
+        }
+
+        /**
+         * Given a path string create all the directories in the path. For example,
+         * if the path string is "java/applet", the method will create directory
+         * "java" and then "java/applet" if they don't exist. The file separator
+         * string "/" is platform dependent system property.
+         *
+         * @param path Directory path string.
+         */
+        private void createDirectoryForFile(File file) {
+            File dir = file.getParentFile();
+            if (dir == null || dir.exists() || dir.mkdirs())
+                return;
+
+            configuration.message.error(
+                   "doclet.Unable_to_create_directory_0", dir.getPath());
+            throw new DocletAbortException();
+        }
+
+        /** Return a string to identify the contents of this object,
+         * for debugging purposes.
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("DocFile[");
+            if (location != null)
+                sb.append("locn:").append(location).append(",");
+            if (path != null)
+                sb.append("path:").append(path.getPath()).append(",");
+            sb.append("file:").append(file);
+            sb.append("]");
+            return sb.toString();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/StandardDocFileFactory.java	Thu Nov 15 19:54:20 2012 -0800
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.doclets.internal.toolkit.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+
+import com.sun.tools.doclets.internal.toolkit.Configuration;
+import com.sun.tools.javac.util.Assert;
+
+/**
+ * Implementation of DocFileFactory using a {@link StandardJavaFileManager}.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @since 1.8
+ */
+class StandardDocFileFactory extends DocFileFactory {
+    private final StandardJavaFileManager fileManager;
+    private final File destDir;
+
+    public StandardDocFileFactory(Configuration configuration) {
+        super(configuration);
+        fileManager = (StandardJavaFileManager) configuration.getFileManager();
+
+        if (!configuration.destDirName.isEmpty()
+                || !fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) {
+            try {
+                String dirName = configuration.destDirName.isEmpty() ? "." : configuration.destDirName;
+                File dir = new File(dirName);
+                fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(dir));
+            } catch (IOException e) {
+                throw new DocletAbortException();
+            }
+        }
+
+        destDir = fileManager.getLocation(StandardLocation.CLASS_OUTPUT).iterator().next();
+    }
+
+    public DocFile createFileForDirectory(String file) {
+        return new StandardDocFile(new File(file));
+    }
+
+    public DocFile createFileForInput(String file) {
+        return new StandardDocFile(new File(file));
+    }
+
+    public DocFile createFileForOutput(DocPath path) {
+        return new StandardDocFile(StandardLocation.CLASS_OUTPUT, path);
+    }
+
+    @Override
+    Iterable<DocFile> list(Location location, DocPath path) {
+        if (location != StandardLocation.SOURCE_PATH)
+            throw new IllegalArgumentException();
+
+        Set<DocFile> files = new LinkedHashSet<DocFile>();
+        if (fileManager.hasLocation(location)) {
+            for (File f: fileManager.getLocation(location)) {
+                if (f.isDirectory()) {
+                    f = new File(f, path.getPath());
+                    if (f.exists())
+                        files.add(new StandardDocFile(f));
+                }
+            }
+        }
+        return files;
+    }
+
+    private static File newFile(File dir, String path) {
+        return (dir == null) ? new File(path) : new File(dir, path);
+    }
+
+    class StandardDocFile extends DocFile {
+        private File file;
+
+
+        /** Create a StandardDocFile for a given file. */
+        private StandardDocFile(File file) {
+            super(configuration);
+            this.file = file;
+        }
+
+        /** Create a StandardDocFile for a given location and relative path. */
+        private StandardDocFile(Location location, DocPath path) {
+            super(configuration, location, path);
+            Assert.check(location == StandardLocation.CLASS_OUTPUT);
+            this.file = newFile(destDir, path.getPath());
+        }
+
+        /** Open an input stream for the file. */
+        public InputStream openInputStream() throws IOException {
+            JavaFileObject fo = getJavaFileObjectForInput(file);
+            return new BufferedInputStream(fo.openInputStream());
+        }
+
+        /**
+         * Open an output stream for the file.
+         * The file must have been created with a location of
+         * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
+         */
+        public OutputStream openOutputStream() throws IOException, UnsupportedEncodingException {
+            if (location != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalStateException();
+
+            OutputStream out = getFileObjectForOutput(path).openOutputStream();
+            return new BufferedOutputStream(out);
+        }
+
+        /**
+         * Open an writer for the file, using the encoding (if any) given in the
+         * doclet configuration.
+         * The file must have been created with a location of
+         * {@link StandardLocation#CLASS_OUTPUT} and a corresponding relative path.
+         */
+        public Writer openWriter() throws IOException, UnsupportedEncodingException {
+            if (location != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalStateException();
+
+            OutputStream out = getFileObjectForOutput(path).openOutputStream();
+            if (configuration.docencoding == null) {
+                return new BufferedWriter(new OutputStreamWriter(out));
+            } else {
+                return new BufferedWriter(new OutputStreamWriter(out, configuration.docencoding));
+            }
+        }
+
+        /** Return true if the file can be read. */
+        public boolean canRead() {
+            return file.canRead();
+        }
+
+        /** Return true if the file can be written. */
+        public boolean canWrite() {
+            return file.canWrite();
+        }
+
+        /** Return true if the file exists. */
+        public boolean exists() {
+            return file.exists();
+        }
+
+        /** Return the base name (last component) of the file name. */
+        public String getName() {
+            return file.getName();
+        }
+
+        /** Return the file system path for this file. */
+        public String getPath() {
+            return file.getPath();
+        }
+
+        /** Return true is file has an absolute path name. */
+        public boolean isAbsolute() {
+            return file.isAbsolute();
+        }
+
+        /** Return true is file identifies a directory. */
+        public boolean isDirectory() {
+            return file.isDirectory();
+        }
+
+        /** Return true is file identifies a file. */
+        public boolean isFile() {
+            return file.isFile();
+        }
+
+        /** Return true if this file is the same as another. */
+        public boolean isSameFile(DocFile other) {
+            if (!(other instanceof StandardDocFile))
+                return false;
+
+            try {
+                return file.exists()
+                        && file.getCanonicalFile().equals(((StandardDocFile) other).file.getCanonicalFile());
+            } catch (IOException e) {
+                return false;
+            }
+        }
+
+        /** If the file is a directory, list its contents. */
+        public Iterable<DocFile> list() {
+            List<DocFile> files = new ArrayList<DocFile>();
+            for (File f: file.listFiles()) {
+                files.add(new StandardDocFile(f));
+            }
+            return files;
+        }
+
+        /** Create the file as a directory, including any parent directories. */
+        public boolean mkdirs() {
+            return file.mkdirs();
+        }
+
+        /**
+         * Derive a new file by resolving a relative path against this file.
+         * The new file will inherit the configuration and location of this file
+         * If this file has a path set, the new file will have a corresponding
+         * new path.
+         */
+        public DocFile resolve(DocPath p) {
+            return resolve(p.getPath());
+        }
+
+        /**
+         * Derive a new file by resolving a relative path against this file.
+         * The new file will inherit the configuration and location of this file
+         * If this file has a path set, the new file will have a corresponding
+         * new path.
+         */
+        public DocFile resolve(String p) {
+            if (location == null && path == null) {
+                return new StandardDocFile(new File(file, p));
+            } else {
+                return new StandardDocFile(location, path.resolve(p));
+            }
+        }
+
+        /**
+         * Resolve a relative file against the given output location.
+         * @param locn Currently, only SOURCE_OUTPUT is supported.
+         */
+        public DocFile resolveAgainst(StandardLocation locn) {
+            if (locn != StandardLocation.CLASS_OUTPUT)
+                throw new IllegalArgumentException();
+            return new StandardDocFile(newFile(destDir, file.getPath()));
+        }
+
+        /** Return a string to identify the contents of this object,
+         * for debugging purposes.
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("StandardDocFile[");
+            if (location != null)
+                sb.append("locn:").append(location).append(",");
+            if (path != null)
+                sb.append("path:").append(path.getPath()).append(",");
+            sb.append("file:").append(file);
+            sb.append("]");
+            return sb.toString();
+        }
+
+        private JavaFileObject getJavaFileObjectForInput(File file) {
+            return fileManager.getJavaFileObjects(file).iterator().next();
+        }
+
+        private FileObject getFileObjectForOutput(DocPath path) throws IOException {
+            // break the path into a package-part and the rest, by finding
+            // the position of the last '/' before an invalid character for a
+            // package name, such as the "." before an extension or the "-"
+            // in filenames like package-summary.html, doc-files or src-html.
+            String p = path.getPath();
+            int lastSep = -1;
+            for (int i = 0; i < p.length(); i++) {
+                char ch = p.charAt(i);
+                if (ch == '/') {
+                    lastSep = i;
+                } else if (i == lastSep + 1 && !Character.isJavaIdentifierStart(ch)
+                        || !Character.isJavaIdentifierPart(ch)) {
+                    break;
+                }
+            }
+            String pkg = (lastSep == -1) ? "" : p.substring(0, lastSep);
+            String rest = p.substring(lastSep + 1);
+            return fileManager.getFileForOutput(location, pkg, rest, null);
+        }
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java	Thu Nov 15 14:41:31 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java	Thu Nov 15 19:54:20 2012 -0800
@@ -27,6 +27,7 @@
 
 import java.io.IOException;
 import java.util.Locale;
+import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 import javax.tools.StandardJavaFileManager;
 
@@ -368,4 +369,11 @@
     public Locale getLocale() {
         return env.doclocale.locale;
     }
+
+    /**
+     * Return the current file manager.
+     */
+    public JavaFileManager getFileManager() {
+        return env.fileManager;
+    }
 }