1 /*
2  * Copyright (c) 2005, 2020, 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 javax.tools;
27 
28 import java.io.*;
29 import java.net.URI;
30 import java.nio.CharBuffer;
31 import java.util.Objects;
32 import javax.lang.model.element.Modifier;
33 import javax.lang.model.element.NestingKind;
34 
35 /**
36  * Provides simple implementations for most methods in JavaFileObject.
37  * This class is designed to be subclassed and used as a basis for
38  * JavaFileObject implementations.  Subclasses can override the
39  * implementation and specification of any method of this class as
40  * long as the general contract of JavaFileObject is obeyed.
41  *
42  * @author Peter von der Ahé
43  * @since 1.6
44  */
45 public class SimpleJavaFileObject implements JavaFileObject {
46     /**
47      * A URI for this file object.
48      */
49     protected final URI uri;
50 
51     /**
52      * The kind of this file object.
53      */
54     protected final Kind kind;
55 
56     /**
57      * Construct a SimpleJavaFileObject of the given kind and with the
58      * given URI.
59      *
60      * @param uri  the URI for this file object
61      * @param kind the kind of this file object
62      */
SimpleJavaFileObject(URI uri, Kind kind)63     protected SimpleJavaFileObject(URI uri, Kind kind) {
64         Objects.requireNonNull(uri);
65         Objects.requireNonNull(kind);
66         if (uri.getPath() == null)
67             throw new IllegalArgumentException("URI must have a path: " + uri);
68         this.uri = uri;
69         this.kind = kind;
70     }
71 
toUri()72     public URI toUri() {
73         return uri;
74     }
75 
getName()76     public String getName() {
77         return toUri().getPath();
78     }
79 
80     /**
81      * This implementation always throws {@linkplain
82      * UnsupportedOperationException}.  Subclasses can change this
83      * behavior as long as the contract of {@link FileObject} is
84      * obeyed.
85      */
openInputStream()86     public InputStream openInputStream() throws IOException {
87         throw new UnsupportedOperationException();
88     }
89 
90     /**
91      * This implementation always throws {@linkplain
92      * UnsupportedOperationException}.  Subclasses can change this
93      * behavior as long as the contract of {@link FileObject} is
94      * obeyed.
95      */
openOutputStream()96     public OutputStream openOutputStream() throws IOException {
97         throw new UnsupportedOperationException();
98     }
99 
100     /**
101      * Wraps the result of {@linkplain #getCharContent} in a Reader.
102      * Subclasses can change this behavior as long as the contract of
103      * {@link FileObject} is obeyed.
104      *
105      * @param  ignoreEncodingErrors {@inheritDoc}
106      * @return a Reader wrapping the result of getCharContent
107      * @throws IllegalStateException {@inheritDoc}
108      * @throws UnsupportedOperationException {@inheritDoc}
109      * @throws IOException {@inheritDoc}
110      */
openReader(boolean ignoreEncodingErrors)111     public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
112         CharSequence charContent = getCharContent(ignoreEncodingErrors);
113         if (charContent == null)
114             throw new UnsupportedOperationException();
115         if (charContent instanceof CharBuffer) {
116             CharBuffer buffer = (CharBuffer)charContent;
117             if (buffer.hasArray())
118                 return new CharArrayReader(buffer.array());
119         }
120         return new StringReader(charContent.toString());
121     }
122 
123     /**
124      * This implementation always throws {@linkplain
125      * UnsupportedOperationException}.  Subclasses can change this
126      * behavior as long as the contract of {@link FileObject} is
127      * obeyed.
128      */
getCharContent(boolean ignoreEncodingErrors)129     public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
130         throw new UnsupportedOperationException();
131     }
132 
133     /**
134      * Wraps the result of openOutputStream in a Writer.  Subclasses
135      * can change this behavior as long as the contract of {@link
136      * FileObject} is obeyed.
137      *
138      * @return a Writer wrapping the result of openOutputStream
139      * @throws IllegalStateException {@inheritDoc}
140      * @throws UnsupportedOperationException {@inheritDoc}
141      * @throws IOException {@inheritDoc}
142      */
openWriter()143     public Writer openWriter() throws IOException {
144         return new OutputStreamWriter(openOutputStream());
145     }
146 
147     /**
148      * This implementation returns {@code 0L}.  Subclasses can change
149      * this behavior as long as the contract of {@link FileObject} is
150      * obeyed.
151      *
152      * @return {@code 0L}
153      */
getLastModified()154     public long getLastModified() {
155         return 0L;
156     }
157 
158     /**
159      * This implementation does nothing.  Subclasses can change this
160      * behavior as long as the contract of {@link FileObject} is
161      * obeyed.
162      *
163      * @return {@code false}
164      */
delete()165     public boolean delete() {
166         return false;
167     }
168 
169     /**
170      * @return {@code this.kind}
171      */
getKind()172     public Kind getKind() {
173         return kind;
174     }
175 
176     /**
177      * This implementation compares the path of its URI to the given
178      * simple name.  This method returns true if the given kind is
179      * equal to the kind of this object, and if the path is equal to
180      * {@code simpleName + kind.extension} or if it ends with {@code
181      * "/" + simpleName + kind.extension}.
182      *
183      * <p>This method calls {@link #getKind} and {@link #toUri} and
184      * does not access the fields {@link #uri} and {@link #kind}
185      * directly.
186      *
187      * <p>Subclasses can change this behavior as long as the contract
188      * of {@link JavaFileObject} is obeyed.
189      */
isNameCompatible(String simpleName, Kind kind)190     public boolean isNameCompatible(String simpleName, Kind kind) {
191         String baseName = simpleName + kind.extension;
192         return kind.equals(getKind())
193             && (baseName.equals(toUri().getPath())
194                 || toUri().getPath().endsWith("/" + baseName));
195     }
196 
197     /**
198      * This implementation returns {@code null}.  Subclasses can
199      * change this behavior as long as the contract of
200      * {@link JavaFileObject} is obeyed.
201      */
getNestingKind()202     public NestingKind getNestingKind() { return null; }
203 
204     /**
205      * This implementation returns {@code null}.  Subclasses can
206      * change this behavior as long as the contract of
207      * {@link JavaFileObject} is obeyed.
208      */
getAccessLevel()209     public Modifier getAccessLevel()  { return null; }
210 
211     @Override
toString()212     public String toString() {
213         return getClass().getName() + "[" + toUri() + "]";
214     }
215 }
216