1 /* 2 * Copyright (c) 1998, 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.javadoc.internal.doclets.toolkit.util; 27 28 import java.io.BufferedReader; 29 import java.io.BufferedWriter; 30 import java.io.FileNotFoundException; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.InputStreamReader; 34 import java.io.OutputStream; 35 import java.io.OutputStreamWriter; 36 import java.io.UnsupportedEncodingException; 37 import java.io.Writer; 38 39 import javax.tools.JavaFileManager.Location; 40 import javax.tools.StandardLocation; 41 42 import jdk.javadoc.internal.doclets.toolkit.Configuration; 43 44 /** 45 * Abstraction for handling files, which may be specified directly 46 * (e.g. via a path on the command line) or relative to a Location. 47 * 48 * <p><b>This is NOT part of any supported API. 49 * If you write code that depends on this, you do so at your own risk. 50 * This code and its internal interfaces are subject to change or 51 * deletion without notice.</b> 52 * 53 * @since 8 54 */ 55 public abstract class DocFile { 56 57 /** Create a DocFile for a directory. */ 58 public static DocFile createFileForDirectory(Configuration configuration, String file) { 59 return DocFileFactory.getFactory(configuration).createFileForDirectory(file); 60 } 61 62 /** Create a DocFile for a file that will be opened for reading. */ 63 public static DocFile createFileForInput(Configuration configuration, String file) { 64 return DocFileFactory.getFactory(configuration).createFileForInput(file); 65 } 66 67 /** Create a DocFile for a file that will be opened for writing. */ 68 public static DocFile createFileForOutput(Configuration configuration, DocPath path) { 69 return DocFileFactory.getFactory(configuration).createFileForOutput(path); 70 } 71 72 private final Configuration configuration; 73 74 /** 75 * The location for this file. Maybe null if the file was created without 76 * a location or path. 77 */ 78 protected final Location location; 79 80 /** 81 * The path relative to the (output) location. Maybe null if the file was 82 * created without a location or path. 83 */ 84 protected final DocPath path; 85 86 /** 87 * List the directories and files found in subdirectories along the 88 * elements of the given location. 89 * @param configuration the doclet configuration 90 * @param location currently, only {@link StandardLocation#SOURCE_PATH} is supported. 91 * @param path the subdirectory of the directories of the location for which to 92 * list files 93 */ 94 public static Iterable<DocFile> list(Configuration configuration, Location location, DocPath path) { 95 return DocFileFactory.getFactory(configuration).list(location, path); 96 } 97 98 /** Create a DocFile without a location or path */ 99 protected DocFile(Configuration configuration) { 100 this.configuration = configuration; 101 this.location = null; 102 this.path = null; 103 } 104 105 /** Create a DocFile for a given location and relative path. */ 106 protected DocFile(Configuration configuration, Location location, DocPath path) { 107 this.configuration = configuration; 108 this.location = location; 109 this.path = path; 110 } 111 112 /** Open an input stream for the file. */ 113 public abstract InputStream openInputStream() throws IOException; 114 115 /** 116 * Open an output stream for the file. 117 * The file must have been created with a location of 118 * {@link DocumentationTool.Location#DOCUMENTATION_OUTPUT} 119 * and a corresponding relative path. 120 */ 121 public abstract OutputStream openOutputStream() throws IOException, UnsupportedEncodingException; 122 123 /** 124 * Open an writer for the file, using the encoding (if any) given in the 125 * doclet configuration. 126 * The file must have been created with a location of 127 * {@link DocumentationTool.Location#DOCUMENTATION_OUTPUT} and a corresponding relative path. 128 */ 129 public abstract Writer openWriter() throws IOException, UnsupportedEncodingException; 130 131 /** 132 * Copy the contents of another file directly to this file. 133 */ 134 public void copyFile(DocFile fromFile) throws IOException { 135 try (OutputStream output = openOutputStream(); 136 InputStream input = fromFile.openInputStream()) { 137 byte[] bytearr = new byte[1024]; 138 int len; 139 while ((len = input.read(bytearr)) != -1) { 140 output.write(bytearr, 0, len); 141 } 142 } 143 catch (FileNotFoundException | SecurityException exc) { 144 } 145 } 146 147 /** 148 * Copy the contents of a resource file to this file. 149 * @param resource the path of the resource, relative to the package of this class 150 * @param overwrite whether or not to overwrite the file if it already exists 151 * @param replaceNewLine if false, the file is copied as a binary file; 152 * if true, the file is written line by line, using the platform line 153 * separator 154 */ 155 public void copyResource(DocPath resource, boolean overwrite, boolean replaceNewLine) { 156 if (exists() && !overwrite) 157 return; 158 159 try { 160 InputStream in = Configuration.class.getResourceAsStream(resource.getPath()); 161 if (in == null) 162 return; 163 164 try (OutputStream out = openOutputStream()) { 165 if (!replaceNewLine) { 166 byte[] buf = new byte[2048]; 167 int n; 168 while ((n = in.read(buf)) > 0) 169 out.write(buf, 0, n); 170 } else { 171 try (BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 172 BufferedWriter writer = new BufferedWriter(configuration.docencoding == null 173 ? new OutputStreamWriter(out) 174 : new OutputStreamWriter(out, configuration.docencoding))) { 175 String line; 176 while ((line = reader.readLine()) != null) { 177 writer.write(line); 178 writer.write(DocletConstants.NL); 179 } 180 } 181 } 182 } finally { 183 in.close(); 184 } 185 } catch (IOException e) { 186 e.printStackTrace(System.err); 187 throw new DocletAbortException(e); 188 } 189 } 190 191 /** Return true if the file can be read. */ 192 public abstract boolean canRead(); 193 194 /** Return true if the file can be written. */ 195 public abstract boolean canWrite(); 196 197 /** Return true if the file exists. */ 198 public abstract boolean exists(); 199 200 /** Return the base name (last component) of the file name. */ 201 public abstract String getName(); 202 203 /** Return the file system path for this file. */ 204 public abstract String getPath(); 205 206 /** Return true if file has an absolute path name. */ 207 public abstract boolean isAbsolute(); 208 209 /** Return true if file identifies a directory. */ 210 public abstract boolean isDirectory(); 211 212 /** Return true if file identifies a file. */ 213 public abstract boolean isFile(); 214 215 /** Return true if this file is the same as another. */ 216 public abstract boolean isSameFile(DocFile other); 217 218 /** If the file is a directory, list its contents. */ 219 public abstract Iterable<DocFile> list() throws IOException; 220 221 /** Create the file as a directory, including any parent directories. */ 222 public abstract boolean mkdirs(); 223 224 /** 225 * Derive a new file by resolving a relative path against this file. 226 * The new file will inherit the configuration and location of this file 227 * If this file has a path set, the new file will have a corresponding 228 * new path. 229 */ 230 public abstract DocFile resolve(DocPath p); 231 232 /** 233 * Derive a new file by resolving a relative path against this file. 234 * The new file will inherit the configuration and location of this file 235 * If this file has a path set, the new file will have a corresponding 236 * new path. 237 */ 238 public abstract DocFile resolve(String p); 239 240 /** 241 * Resolve a relative file against the given output location. 242 * @param locn Currently, only 243 * {@link DocumentationTool.Location#DOCUMENTATION_OUTPUT} is supported. 244 */ 245 public abstract DocFile resolveAgainst(Location locn); 246 }