src/share/classes/com/sun/tools/apt/mirror/apt/FilerImpl.java

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 789
878c8f760ded
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 2004, 2010, 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  */
    26 package com.sun.tools.apt.mirror.apt;
    29 import java.io.*;
    30 import java.util.Collection;
    31 import java.util.EnumMap;
    32 import java.util.HashSet;
    33 import java.util.Set;
    35 import com.sun.mirror.apt.Filer;
    36 import com.sun.tools.apt.mirror.declaration.DeclarationMaker;
    37 import com.sun.tools.javac.util.Context;
    38 import com.sun.tools.javac.util.Options;
    39 import com.sun.tools.javac.util.Position;
    40 import com.sun.tools.apt.util.Bark;
    42 import static com.sun.mirror.apt.Filer.Location.*;
    45 /**
    46  * Implementation of Filer.
    47  */
    48 @SuppressWarnings("deprecation")
    49 public class FilerImpl implements Filer {
    50     /*
    51      * The Filer class must maintain a number of constraints.  First,
    52      * multiple attempts to open the same path within the same
    53      * invocation of apt results in an IOException being thrown.  For
    54      * example, trying to open the same source file twice:
    55      *
    56      * createSourceFile("foo.Bar")
    57      * ...
    58      * createSourceFile("foo.Bar")
    59      *
    60      * is disallowed as is opening a text file that happens to have
    61      * the same name as a source file:
    62      *
    63      * createSourceFile("foo.Bar")
    64      * ...
    65      * createTextFile(SOURCE_TREE, "foo", new File("Bar"), null)
    66      *
    67      * Additionally, creating a source file that corresponds to an
    68      * already created class file (or vice versa) generates at least a
    69      * warning.  This is an error if -XclassesAsDecls is being used
    70      * since you can't create the same type twice.  However, if the
    71      * Filer is used to create a text file named *.java that happens
    72      * to correspond to an existing class file, a warning is *not*
    73      * generated.  Similarly, a warning is not generated for a binary
    74      * file named *.class and an existing source file.
    75      *
    76      * The reason for this difference is that source files and class
    77      * files are registered with apt and can get passed on as
    78      * declarations to the next round of processing.  Files that are
    79      * just named *.java and *.class are not processed in that manner;
    80      * although having extra source files and class files on the
    81      * source path and class path can alter the behavior of the tool
    82      * and any final compile.
    83      */
    85     private enum FileKind {
    86         SOURCE {
    87             void register(File file, String name, FilerImpl that) throws IOException {
    88                 // Check for corresponding class file
    89                 if (that.filesCreated.contains(new File(that.locations.get(CLASS_TREE),
    90                                                         that.nameToPath(name, ".class")))) {
    92                     that.bark.aptWarning("CorrespondingClassFile", name);
    93                     if (that.opts.get("-XclassesAsDecls") != null)
    94                         throw new IOException();
    95                 }
    96                 that.sourceFileNames.add(file.getPath());
    97             }
    98         },
   100         CLASS  {
   101             void register(File file, String name, FilerImpl that) throws IOException {
   102                 if (that.filesCreated.contains(new File(that.locations.get(SOURCE_TREE),
   103                                                         that.nameToPath(name, ".java")))) {
   104                     that.bark.aptWarning("CorrespondingSourceFile", name);
   105                     if (that.opts.get("-XclassesAsDecls") != null)
   106                         throw new IOException();
   107                 }
   108                 // Track the binary name instead of the filesystem location
   109                 that.classFileNames.add(name);
   110             }
   111         },
   113         OTHER  {
   114             // Nothing special to do
   115             void register(File file, String name, FilerImpl that) throws IOException {}
   116         };
   118         abstract void register(File file, String name, FilerImpl that) throws IOException;
   119     }
   121     private final Options opts;
   122     private final DeclarationMaker declMaker;
   123     private final com.sun.tools.apt.main.AptJavaCompiler comp;
   125     // Platform's default encoding
   126     private final static String DEFAULT_ENCODING =
   127             new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
   129     private String encoding;    // name of charset used for source files
   131     private final EnumMap<Location, File> locations;    // where new files go
   134     private static final Context.Key<FilerImpl> filerKey =
   135             new Context.Key<FilerImpl>();
   137     // Set of files opened.
   138     private Collection<Flushable> wc;
   140     private Bark bark;
   142     // All created files.
   143     private final Set<File> filesCreated;
   145     // Names of newly created source files
   146     private HashSet<String> sourceFileNames = new HashSet<String>();
   148     // Names of newly created class files
   149     private HashSet<String> classFileNames  = new HashSet<String>();
   151     private boolean roundOver;
   153     public static FilerImpl instance(Context context) {
   154         FilerImpl instance = context.get(filerKey);
   155         if (instance == null) {
   156             instance = new FilerImpl(context);
   157         }
   158         return instance;
   159     }
   161     // flush all output streams;
   162     public void flush() {
   163         for(Flushable opendedFile: wc) {
   164             try {
   165                 opendedFile.flush();
   166                 if (opendedFile instanceof FileOutputStream) {
   167                     try {
   168                         ((FileOutputStream) opendedFile).getFD().sync() ;
   169                     } catch (java.io.SyncFailedException sfe) {}
   170                 }
   171             } catch (IOException e) { }
   172         }
   173     }
   175     private FilerImpl(Context context) {
   176         context.put(filerKey, this);
   177         opts = Options.instance(context);
   178         declMaker = DeclarationMaker.instance(context);
   179         bark = Bark.instance(context);
   180         comp = com.sun.tools.apt.main.AptJavaCompiler.instance(context);
   181         roundOver = false;
   182         this.filesCreated = comp.getAggregateGenFiles();
   184         // Encoding
   185         encoding = opts.get("-encoding");
   186         if (encoding == null) {
   187             encoding = DEFAULT_ENCODING;
   188         }
   190         wc = new HashSet<Flushable>();
   192         // Locations
   193         locations = new EnumMap<Location, File>(Location.class);
   194         String s = opts.get("-s");      // location for new source files
   195         String d = opts.get("-d");      // location for new class files
   196         locations.put(SOURCE_TREE, new File(s != null ? s : "."));
   197         locations.put(CLASS_TREE,  new File(d != null ? d : "."));
   198     }
   201     /**
   202      * {@inheritDoc}
   203      */
   204     public PrintWriter createSourceFile(String name) throws IOException {
   205         String pathname = nameToPath(name, ".java");
   206         File file = new File(locations.get(SOURCE_TREE),
   207                              pathname);
   208         PrintWriter pw = getPrintWriter(file, encoding, name, FileKind.SOURCE);
   209         return pw;
   210     }
   212     /**
   213      * {@inheritDoc}
   214      */
   215     public OutputStream createClassFile(String name) throws IOException {
   216         String pathname = nameToPath(name, ".class");
   217         File file = new File(locations.get(CLASS_TREE),
   218                              pathname);
   219         OutputStream os = getOutputStream(file, name, FileKind.CLASS);
   220         return os;
   221     }
   223     /**
   224      * {@inheritDoc}
   225      */
   226     public PrintWriter createTextFile(Location loc,
   227                                       String pkg,
   228                                       File relPath,
   229                                       String charsetName) throws IOException {
   230         File file = (pkg.length() == 0)
   231                         ? relPath
   232                         : new File(nameToPath(pkg), relPath.getPath());
   233         if (charsetName == null) {
   234             charsetName = encoding;
   235         }
   236         return getPrintWriter(loc, file.getPath(), charsetName, null, FileKind.OTHER);
   237     }
   239     /**
   240      * {@inheritDoc}
   241      */
   242     public OutputStream createBinaryFile(Location loc,
   243                                          String pkg,
   244                                          File relPath) throws IOException {
   245         File file = (pkg.length() == 0)
   246                         ? relPath
   247                         : new File(nameToPath(pkg), relPath.getPath());
   248         return getOutputStream(loc, file.getPath(), null, FileKind.OTHER);
   249     }
   252     /**
   253      * Converts the canonical name of a top-level type or package to a
   254      * pathname.  Suffix is ".java" or ".class" or "".
   255      */
   256     private String nameToPath(String name, String suffix) throws IOException {
   257         if (!DeclarationMaker.isJavaIdentifier(name.replace('.', '_'))) {
   258             bark.aptWarning("IllegalFileName", name);
   259             throw new IOException();
   260         }
   261         return name.replace('.', File.separatorChar) + suffix;
   262     }
   264     private String nameToPath(String name) throws IOException {
   265         return nameToPath(name, "");
   266     }
   268     /**
   269      * Returns a writer for a text file given its location, its
   270      * pathname relative to that location, and its encoding.
   271      */
   272     private PrintWriter getPrintWriter(Location loc, String pathname,
   273                                        String encoding, String name, FileKind kind) throws IOException {
   274         File file = new File(locations.get(loc), pathname);
   275         return getPrintWriter(file, encoding, name, kind);
   276     }
   278     /**
   279      * Returns a writer for a text file given its encoding.
   280      */
   281     private PrintWriter getPrintWriter(File file,
   282                                        String encoding, String name, FileKind kind) throws IOException {
   283         prepareFile(file, name, kind);
   284         PrintWriter pw =
   285             new PrintWriter(
   286                     new BufferedWriter(
   287                          new OutputStreamWriter(new FileOutputStream(file),
   288                                                 encoding)));
   289         wc.add(pw);
   290         return pw;
   291     }
   293     /**
   294      * Returns an output stream for a binary file given its location
   295      * and its pathname relative to that location.
   296      */
   297     private OutputStream getOutputStream(Location loc, String pathname, String name, FileKind kind)
   298                                                         throws IOException {
   299         File file = new File(locations.get(loc), pathname);
   300         return getOutputStream(file, name, kind);
   301     }
   303     private OutputStream getOutputStream(File file, String name, FileKind kind) throws IOException {
   304         prepareFile(file, name, kind);
   305         OutputStream os = new FileOutputStream(file);
   306         wc.add(os);
   307         return os;
   309     }
   311     public Set<String> getSourceFileNames() {
   312         return sourceFileNames;
   313     }
   315     public Set<String> getClassFileNames() {
   316         return classFileNames;
   317     }
   319     public void roundOver() {
   320         roundOver = true;
   321     }
   323     /**
   324      * Checks that the file has not already been created during this
   325      * invocation.  If not, creates intermediate directories, and
   326      * deletes the file if it already exists.
   327      */
   328     private void prepareFile(File file, String name, FileKind kind) throws IOException {
   329         if (roundOver) {
   330             bark.aptWarning("NoNewFilesAfterRound", file.toString());
   331             throw new IOException();
   332         }
   334         if (filesCreated.contains(file)) {
   335             bark.aptWarning("FileReopening", file.toString());
   336             throw new IOException();
   337         } else {
   338             if (file.exists()) {
   339                 file.delete();
   340             } else {
   341                 File parent = file.getParentFile();
   342                 if (parent != null && !parent.exists()) {
   343                     if(!parent.mkdirs()) {
   344                         bark.aptWarning("BadParentDirectory", file.toString());
   345                         throw new IOException();
   346                     }
   347                 }
   348             }
   350             kind.register(file, name, this);
   351             filesCreated.add(file);
   352         }
   353     }
   354 }

mercurial