1/*
2 * Copyright (c) 2010, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.io.File;
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.OutputStream;
28import java.io.Reader;
29import java.io.Writer;
30import java.net.URI;
31import java.util.ArrayList;
32import java.util.Collections;
33import java.util.List;
34import java.util.Objects;
35import java.util.regex.Pattern;
36import javax.lang.model.element.Modifier;
37import javax.lang.model.element.NestingKind;
38import javax.tools.JavaFileManager.Location;
39import javax.tools.JavaFileObject;
40import javax.tools.StandardJavaFileManager;
41
42import com.sun.tools.javac.api.WrappingJavaFileManager;
43
44/**
45 * A JavaFileManager that can throw IOException on attempting to read or write
46 * selected files that match a regular expression.
47 */
48public class FileManager
49        extends WrappingJavaFileManager<StandardJavaFileManager>
50        implements StandardJavaFileManager {
51    private static final String CANT_READ = "cantRead:";
52    private static final String CANT_WRITE = "cantWrite:";
53
54    private Pattern cantRead;
55    private Pattern cantWrite;
56
57    public FileManager(StandardJavaFileManager fm, List<String> opts) {
58        super(fm);
59        for (String opt: opts) {
60            if (opt.startsWith(CANT_READ))
61                cantRead = Pattern.compile(opt.substring(CANT_READ.length()));
62            else if (opt.startsWith(CANT_WRITE))
63                cantWrite = Pattern.compile(opt.substring(CANT_WRITE.length()));
64            else
65                throw new IllegalArgumentException(opt);
66        }
67    }
68
69    @Override
70    protected JavaFileObject wrap(JavaFileObject fo) {
71        return (fo == null) ? null : new WrappedFileObject(fo);
72    }
73
74    @Override
75    protected JavaFileObject unwrap(JavaFileObject fo) {
76        if (fo instanceof WrappedFileObject)
77            return ((WrappedFileObject) fo).delegate;
78        else
79            return fo;
80    }
81
82    public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
83        return wrap2(fileManager.getJavaFileObjectsFromFiles(files));
84    }
85
86    public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
87        return wrap2(fileManager.getJavaFileObjects(files));
88    }
89
90    public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
91        return wrap2(fileManager.getJavaFileObjectsFromStrings(names));
92    }
93
94    public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
95        return wrap2(fileManager.getJavaFileObjects(names));
96    }
97
98    /* This method is regrettably necessary because WrappingJavaFileManager.wrap takes
99     *          Iterable<JavaFileObject> fileObjects
100     * instead of
101     *          Iterable<? extends JavaFileObject> fileObjects
102     */
103    protected Iterable<JavaFileObject> wrap2(Iterable<? extends JavaFileObject> fileObjects) {
104        List<JavaFileObject> mapped = new ArrayList<JavaFileObject>();
105        for (JavaFileObject fileObject : fileObjects)
106            mapped.add(wrap(fileObject));
107        return Collections.unmodifiableList(mapped);
108    }
109
110    public void setLocation(Location location, Iterable<? extends File> path) throws IOException {
111        fileManager.setLocation(location, path);
112    }
113
114    public Iterable<? extends File> getLocation(Location location) {
115        return fileManager.getLocation(location);
116    }
117
118    class WrappedFileObject implements JavaFileObject {
119        WrappedFileObject(JavaFileObject fileObject) {
120            delegate = Objects.requireNonNull(fileObject);
121        }
122
123        public Kind getKind() {
124            return delegate.getKind();
125        }
126
127        public boolean isNameCompatible(String simpleName, Kind kind) {
128            return delegate.isNameCompatible(simpleName, kind);
129        }
130
131        public NestingKind getNestingKind() {
132            return delegate.getNestingKind();
133        }
134
135        public Modifier getAccessLevel() {
136            return delegate.getAccessLevel();
137        }
138
139        public URI toUri() {
140            return delegate.toUri();
141        }
142
143        public String getName() {
144            return delegate.getName();
145        }
146
147        public InputStream openInputStream() throws IOException {
148            checkRead();
149            return delegate.openInputStream();
150        }
151
152        public OutputStream openOutputStream() throws IOException {
153            checkWrite();
154            return delegate.openOutputStream();
155        }
156
157        public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
158            checkRead();
159            return delegate.openReader(ignoreEncodingErrors);
160        }
161
162        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
163            checkRead();
164            return delegate.getCharContent(ignoreEncodingErrors);
165        }
166
167        public Writer openWriter() throws IOException {
168            checkWrite();
169            return delegate.openWriter();
170        }
171
172        public long getLastModified() {
173            return delegate.getLastModified();
174        }
175
176        public boolean delete() {
177            return delegate.delete();
178        }
179
180        void checkRead() throws IOException {
181            String canonName = getName().replace(File.separatorChar, '/');
182            if (cantRead != null && cantRead.matcher(canonName).matches())
183                throw new IOException("FileManager: Can't read");
184        }
185
186        void checkWrite() throws IOException {
187            String canonName = getName().replace(File.separatorChar, '/');
188            if (cantWrite != null && cantWrite.matcher(canonName).matches())
189                throw new IOException("FileManager: Can't write");
190        }
191
192        JavaFileObject delegate;
193    }
194}
195