| /******************************************************************************* |
| * Copyright (c) 2006, 2015 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.apt.util; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.nio.charset.Charset; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.zip.ZipException; |
| |
| import javax.tools.FileObject; |
| import javax.tools.JavaFileObject; |
| import javax.tools.JavaFileObject.Kind; |
| import javax.tools.StandardJavaFileManager; |
| import javax.tools.StandardLocation; |
| |
| import org.eclipse.jdt.core.compiler.IProblem; |
| import org.eclipse.jdt.internal.compiler.batch.FileSystem; |
| import org.eclipse.jdt.internal.compiler.batch.Main; |
| import org.eclipse.jdt.internal.compiler.batch.Main.ResourceBundleFactory; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.env.AccessRestriction; |
| import org.eclipse.jdt.internal.compiler.env.AccessRule; |
| import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| |
| /** |
| * Implementation of the Standard Java File Manager |
| */ |
| public class EclipseFileManager implements StandardJavaFileManager { |
| private static final String NO_EXTENSION = "";//$NON-NLS-1$ |
| static final int HAS_EXT_DIRS = 1; |
| static final int HAS_BOOTCLASSPATH = 2; |
| static final int HAS_ENDORSED_DIRS = 4; |
| static final int HAS_PROCESSORPATH = 8; |
| |
| Map<File, Archive> archivesCache; |
| Charset charset; |
| Locale locale; |
| Map<String, Iterable<? extends File>> locations; |
| int flags; |
| public ResourceBundle bundle; |
| |
| public EclipseFileManager(Locale locale, Charset charset) { |
| this.locale = locale == null ? Locale.getDefault() : locale; |
| this.charset = charset == null ? Charset.defaultCharset() : charset; |
| this.locations = new HashMap<>(); |
| this.archivesCache = new HashMap<>(); |
| try { |
| this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath()); |
| Iterable<? extends File> defaultClasspath = getDefaultClasspath(); |
| this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath); |
| this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath); |
| } catch (IOException e) { |
| // ignore |
| } |
| try { |
| this.bundle = ResourceBundleFactory.getBundle(this.locale); |
| } catch(MissingResourceException e) { |
| System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#close() |
| */ |
| @Override |
| public void close() throws IOException { |
| if (this.locations != null) this.locations.clear(); |
| for (Archive archive : this.archivesCache.values()) { |
| archive.close(); |
| } |
| this.archivesCache.clear(); |
| } |
| |
| private void collectAllMatchingFiles(File file, String normalizedPackageName, Set<Kind> kinds, boolean recurse, ArrayList<JavaFileObject> collector) { |
| if (!isArchive(file)) { |
| // we must have a directory |
| File currentFile = new File(file, normalizedPackageName); |
| if (!currentFile.exists()) return; |
| String path; |
| try { |
| path = currentFile.getCanonicalPath(); |
| } catch (IOException e) { |
| return; |
| } |
| if (File.separatorChar == '/') { |
| if (!path.endsWith(normalizedPackageName)) return; |
| } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return; |
| File[] files = currentFile.listFiles(); |
| if (files != null) { |
| // this was a directory |
| for (File f : files) { |
| if (f.isDirectory() && recurse) { |
| collectAllMatchingFiles(file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector); |
| } else { |
| final Kind kind = getKind(f); |
| if (kinds.contains(kind)) { |
| collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset)); |
| } |
| } |
| } |
| } |
| } else { |
| Archive archive = this.getArchive(file); |
| if (archive == Archive.UNKNOWN_ARCHIVE) return; |
| String key = normalizedPackageName; |
| if (!normalizedPackageName.endsWith("/")) {//$NON-NLS-1$ |
| key += '/'; |
| } |
| // we have an archive file |
| if (recurse) { |
| for (String packageName : archive.allPackages()) { |
| if (packageName.startsWith(key)) { |
| List<String> types = archive.getTypes(packageName); |
| if (types != null) { |
| for (String typeName : types) { |
| final Kind kind = getKind(getExtension(typeName)); |
| if (kinds.contains(kind)) { |
| collector.add(archive.getArchiveFileObject(packageName + typeName, this.charset)); |
| } |
| } |
| } |
| } |
| } |
| } else { |
| List<String> types = archive.getTypes(key); |
| if (types != null) { |
| for (String typeName : types) { |
| final Kind kind = getKind(getExtension(typeName)); |
| if (kinds.contains(kind)) { |
| collector.add(archive.getArchiveFileObject(key + typeName, this.charset)); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private Iterable<? extends File> concatFiles(Iterable<? extends File> iterable, Iterable<? extends File> iterable2) { |
| ArrayList<File> list = new ArrayList<>(); |
| if (iterable2 == null) return iterable; |
| for (Iterator<? extends File> iterator = iterable.iterator(); iterator.hasNext(); ) { |
| list.add(iterator.next()); |
| } |
| for (Iterator<? extends File> iterator = iterable2.iterator(); iterator.hasNext(); ) { |
| list.add(iterator.next()); |
| } |
| return list; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#flush() |
| */ |
| @Override |
| public void flush() throws IOException { |
| for (Archive archive : this.archivesCache.values()) { |
| archive.flush(); |
| } |
| } |
| |
| private Archive getArchive(File f) { |
| // check the archive (jar/zip) cache |
| Archive archive = this.archivesCache.get(f); |
| if (archive == null) { |
| archive = Archive.UNKNOWN_ARCHIVE; |
| // create a new archive |
| if (f.exists()) { |
| try { |
| archive = new Archive(f); |
| } catch (ZipException e) { |
| // ignore |
| } catch (IOException e) { |
| // ignore |
| } |
| if (archive != null) { |
| this.archivesCache.put(f, archive); |
| } |
| } |
| this.archivesCache.put(f, archive); |
| } |
| return archive; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#getClassLoader(javax.tools.JavaFileManager.Location) |
| */ |
| @Override |
| public ClassLoader getClassLoader(Location location) { |
| Iterable<? extends File> files = getLocation(location); |
| if (files == null) { |
| // location is unknown |
| return null; |
| } |
| ArrayList<URL> allURLs = new ArrayList<>(); |
| for (File f : files) { |
| try { |
| allURLs.add(f.toURI().toURL()); |
| } catch (MalformedURLException e) { |
| // the url is malformed - this should not happen |
| throw new RuntimeException(e); |
| } |
| } |
| URL[] result = new URL[allURLs.size()]; |
| return new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader()); |
| } |
| |
| private Iterable<? extends File> getPathsFrom(String path) { |
| ArrayList<FileSystem.Classpath> paths = new ArrayList<>(); |
| ArrayList<File> files = new ArrayList<>(); |
| try { |
| this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false); |
| } catch (IllegalArgumentException e) { |
| return null; |
| } |
| for (FileSystem.Classpath classpath : paths) { |
| files.add(new File(classpath.getPath())); |
| } |
| return files; |
| } |
| |
| Iterable<? extends File> getDefaultBootclasspath() { |
| List<File> files = new ArrayList<>(); |
| String javaversion = System.getProperty("java.version");//$NON-NLS-1$ |
| if(javaversion.length() > 3) |
| javaversion = javaversion.substring(0, 3); |
| long jdkLevel = CompilerOptions.versionToJdkLevel(javaversion); |
| if (jdkLevel < ClassFileConstants.JDK1_6) { |
| // wrong jdk - 1.6 or above is required |
| return null; |
| } |
| |
| for (String fileName : org.eclipse.jdt.internal.compiler.util.Util.collectFilesNames()) { |
| files.add(new File(fileName)); |
| } |
| return files; |
| } |
| |
| Iterable<? extends File> getDefaultClasspath() { |
| // default classpath |
| ArrayList<File> files = new ArrayList<>(); |
| String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$ |
| if ((classProp == null) || (classProp.length() == 0)) { |
| return null; |
| } else { |
| StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator); |
| String token; |
| while (tokenizer.hasMoreTokens()) { |
| token = tokenizer.nextToken(); |
| File file = new File(token); |
| if (file.exists()) { |
| files.add(file); |
| } |
| } |
| } |
| return files; |
| } |
| |
| private Iterable<? extends File> getEndorsedDirsFrom(String path) { |
| ArrayList<FileSystem.Classpath> paths = new ArrayList<>(); |
| ArrayList<File> files = new ArrayList<>(); |
| try { |
| this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false); |
| } catch (IllegalArgumentException e) { |
| return null; |
| } |
| for (FileSystem.Classpath classpath : paths) { |
| files.add(new File(classpath.getPath())); |
| } |
| return files; |
| } |
| |
| private Iterable<? extends File> getExtdirsFrom(String path) { |
| ArrayList<FileSystem.Classpath> paths = new ArrayList<>(); |
| ArrayList<File> files = new ArrayList<>(); |
| try { |
| this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false); |
| } catch (IllegalArgumentException e) { |
| return null; |
| } |
| for (FileSystem.Classpath classpath : paths) { |
| files.add(new File(classpath.getPath())); |
| } |
| return files; |
| } |
| |
| private String getExtension(File file) { |
| String name = file.getName(); |
| return getExtension(name); |
| } |
| private String getExtension(String name) { |
| int index = name.lastIndexOf('.'); |
| if (index == -1) { |
| return EclipseFileManager.NO_EXTENSION; |
| } |
| return name.substring(index); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#getFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String) |
| */ |
| @Override |
| public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { |
| Iterable<? extends File> files = getLocation(location); |
| if (files == null) { |
| throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ |
| } |
| String normalizedFileName = normalizedFileName(packageName, relativeName); |
| for (File file : files) { |
| if (file.isDirectory()) { |
| // handle directory |
| File f = new File(file, normalizedFileName); |
| if (f.exists()) { |
| return new EclipseFileObject(packageName + File.separator + relativeName, f.toURI(), getKind(f), this.charset); |
| } else { |
| continue; // go to next entry in the location |
| } |
| } else if (isArchive(file)) { |
| // handle archive file |
| Archive archive = getArchive(file); |
| if (archive != Archive.UNKNOWN_ARCHIVE) { |
| if (archive.contains(normalizedFileName)) { |
| return archive.getArchiveFileObject(normalizedFileName, this.charset); |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private String normalizedFileName(String packageName, String relativeName) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append(normalized(packageName)); |
| if (sb.length() > 0) { |
| sb.append('/'); |
| } |
| sb.append(relativeName.replace('\\', '/')); |
| return sb.toString(); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#getFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String, javax.tools.FileObject) |
| */ |
| @Override |
| public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) |
| throws IOException { |
| Iterable<? extends File> files = getLocation(location); |
| if (files == null) { |
| throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ |
| } |
| final Iterator<? extends File> iterator = files.iterator(); |
| if (iterator.hasNext()) { |
| File file = iterator.next(); |
| String normalizedFileName = normalized(packageName) + '/' + relativeName.replace('\\', '/'); |
| File f = new File(file, normalizedFileName); |
| return new EclipseFileObject(packageName + File.separator + relativeName, f.toURI(), getKind(f), this.charset); |
| } else { |
| throw new IllegalArgumentException("location is empty : " + location);//$NON-NLS-1$ |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#getJavaFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind) |
| */ |
| @Override |
| public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { |
| if (kind != Kind.CLASS && kind != Kind.SOURCE) { |
| throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$ |
| } |
| Iterable<? extends File> files = getLocation(location); |
| if (files == null) { |
| throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ |
| } |
| String normalizedFileName = normalized(className); |
| normalizedFileName += kind.extension; |
| for (File file : files) { |
| if (file.isDirectory()) { |
| // handle directory |
| File f = new File(file, normalizedFileName); |
| if (f.exists()) { |
| return new EclipseFileObject(className, f.toURI(), kind, this.charset); |
| } else { |
| continue; // go to next entry in the location |
| } |
| } else if (isArchive(file)) { |
| // handle archive file |
| Archive archive = getArchive(file); |
| if (archive != Archive.UNKNOWN_ARCHIVE) { |
| if (archive.contains(normalizedFileName)) { |
| return archive.getArchiveFileObject(normalizedFileName, this.charset); |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject) |
| */ |
| @Override |
| public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) |
| throws IOException { |
| if (kind != Kind.CLASS && kind != Kind.SOURCE) { |
| throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$ |
| } |
| Iterable<? extends File> files = getLocation(location); |
| if (files == null) { |
| if (!location.equals(StandardLocation.CLASS_OUTPUT) |
| && !location.equals(StandardLocation.SOURCE_OUTPUT)) |
| throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ |
| // we will use either the sibling or user.dir |
| if (sibling != null) { |
| String normalizedFileName = normalized(className); |
| int index = normalizedFileName.lastIndexOf('/'); |
| if (index != -1) { |
| normalizedFileName = normalizedFileName.substring(index + 1); |
| } |
| normalizedFileName += kind.extension; |
| URI uri = sibling.toUri(); |
| URI uri2 = null; |
| try { |
| String path = uri.getPath(); |
| index = path.lastIndexOf('/'); |
| if (index != -1) { |
| path = path.substring(0, index + 1); |
| path += normalizedFileName; |
| } |
| uri2 = new URI(uri.getScheme(), uri.getHost(), path, uri.getFragment()); |
| } catch (URISyntaxException e) { |
| throw new IllegalArgumentException("invalid sibling", e);//$NON-NLS-1$ |
| } |
| return new EclipseFileObject(className, uri2, kind, this.charset); |
| } else { |
| String normalizedFileName = normalized(className); |
| normalizedFileName += kind.extension; |
| File f = new File(System.getProperty("user.dir"), normalizedFileName);//$NON-NLS-1$ |
| return new EclipseFileObject(className, f.toURI(), kind, this.charset); |
| } |
| } |
| final Iterator<? extends File> iterator = files.iterator(); |
| if (iterator.hasNext()) { |
| File file = iterator.next(); |
| String normalizedFileName = normalized(className); |
| normalizedFileName += kind.extension; |
| File f = new File(file, normalizedFileName); |
| return new EclipseFileObject(className, f.toURI(), kind, this.charset); |
| } else { |
| throw new IllegalArgumentException("location is empty : " + location);//$NON-NLS-1$ |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#getJavaFileObjects(java.io.File[]) |
| */ |
| @Override |
| public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) { |
| return getJavaFileObjectsFromFiles(Arrays.asList(files)); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#getJavaFileObjects(java.lang.String[]) |
| */ |
| @Override |
| public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) { |
| return getJavaFileObjectsFromStrings(Arrays.asList(names)); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#getJavaFileObjectsFromFiles(java.lang.Iterable) |
| */ |
| @Override |
| public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) { |
| ArrayList<JavaFileObject> javaFileArrayList = new ArrayList<>(); |
| for (File f : files) { |
| if (f.isDirectory()) { |
| throw new IllegalArgumentException("file : " + f.getAbsolutePath() + " is a directory"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| javaFileArrayList.add(new EclipseFileObject(f.getAbsolutePath(), f.toURI(), getKind(f), this.charset)); |
| } |
| return javaFileArrayList; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#getJavaFileObjectsFromStrings(java.lang.Iterable) |
| */ |
| @Override |
| public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) { |
| ArrayList<File> files = new ArrayList<>(); |
| for (String name : names) { |
| files.add(new File(name)); |
| } |
| return getJavaFileObjectsFromFiles(files); |
| } |
| |
| public Kind getKind(File f) { |
| return getKind(getExtension(f)); |
| } |
| |
| private Kind getKind(String extension) { |
| if (Kind.CLASS.extension.equals(extension)) { |
| return Kind.CLASS; |
| } else if (Kind.SOURCE.extension.equals(extension)) { |
| return Kind.SOURCE; |
| } else if (Kind.HTML.extension.equals(extension)) { |
| return Kind.HTML; |
| } |
| return Kind.OTHER; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#getLocation(javax.tools.JavaFileManager.Location) |
| */ |
| @Override |
| public Iterable<? extends File> getLocation(Location location) { |
| if (this.locations == null) return null; |
| return this.locations.get(location.getName()); |
| } |
| |
| private Iterable<? extends File> getOutputDir(String string) { |
| if ("none".equals(string)) {//$NON-NLS-1$ |
| return null; |
| } |
| File file = new File(string); |
| if (file.exists() && !file.isDirectory()) { |
| throw new IllegalArgumentException("file : " + file.getAbsolutePath() + " is not a directory");//$NON-NLS-1$//$NON-NLS-2$ |
| } |
| ArrayList<File> list = new ArrayList<>(1); |
| list.add(file); |
| return list; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#handleOption(java.lang.String, java.util.Iterator) |
| */ |
| @Override |
| public boolean handleOption(String current, Iterator<String> remaining) { |
| try { |
| if ("-bootclasspath".equals(current)) {//$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| final Iterable<? extends File> bootclasspaths = getPathsFrom(remaining.next()); |
| if (bootclasspaths != null) { |
| Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); |
| if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) == 0 |
| && (this.flags & EclipseFileManager.HAS_EXT_DIRS) == 0) { |
| // override default bootclasspath |
| setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths); |
| } else if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) != 0) { |
| // endorseddirs have been processed first |
| setLocation(StandardLocation.PLATFORM_CLASS_PATH, |
| concatFiles(iterable, bootclasspaths)); |
| } else { |
| // extdirs have been processed first |
| setLocation(StandardLocation.PLATFORM_CLASS_PATH, |
| prependFiles(iterable, bootclasspaths)); |
| } |
| } |
| this.flags |= EclipseFileManager.HAS_BOOTCLASSPATH; |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-classpath".equals(current) || "-cp".equals(current)) {//$NON-NLS-1$//$NON-NLS-2$ |
| if (remaining.hasNext()) { |
| final Iterable<? extends File> classpaths = getPathsFrom(remaining.next()); |
| if (classpaths != null) { |
| Iterable<? extends File> iterable = getLocation(StandardLocation.CLASS_PATH); |
| if (iterable != null) { |
| setLocation(StandardLocation.CLASS_PATH, |
| concatFiles(iterable, classpaths)); |
| } else { |
| setLocation(StandardLocation.CLASS_PATH, classpaths); |
| } |
| if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) { |
| setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths); |
| } |
| } |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-encoding".equals(current)) {//$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| this.charset = Charset.forName(remaining.next()); |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-sourcepath".equals(current)) {//$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| final Iterable<? extends File> sourcepaths = getPathsFrom(remaining.next()); |
| if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths); |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-extdirs".equals(current)) {//$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); |
| setLocation(StandardLocation.PLATFORM_CLASS_PATH, |
| concatFiles(iterable, getExtdirsFrom(remaining.next()))); |
| this.flags |= EclipseFileManager.HAS_EXT_DIRS; |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-endorseddirs".equals(current)) {//$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); |
| setLocation(StandardLocation.PLATFORM_CLASS_PATH, |
| prependFiles(iterable, getEndorsedDirsFrom(remaining.next()))); |
| this.flags |= EclipseFileManager.HAS_ENDORSED_DIRS; |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-d".equals(current)) { //$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| final Iterable<? extends File> outputDir = getOutputDir(remaining.next()); |
| if (outputDir != null) { |
| setLocation(StandardLocation.CLASS_OUTPUT, outputDir); |
| } |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-s".equals(current)) { //$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| final Iterable<? extends File> outputDir = getOutputDir(remaining.next()); |
| if (outputDir != null) { |
| setLocation(StandardLocation.SOURCE_OUTPUT, outputDir); |
| } |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| if ("-processorpath".equals(current)) {//$NON-NLS-1$ |
| if (remaining.hasNext()) { |
| final Iterable<? extends File> processorpaths = getPathsFrom(remaining.next()); |
| if (processorpaths != null) { |
| setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths); |
| } |
| this.flags |= EclipseFileManager.HAS_PROCESSORPATH; |
| return true; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| } catch (IOException e) { |
| // ignore |
| } |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#hasLocation(javax.tools.JavaFileManager.Location) |
| */ |
| @Override |
| public boolean hasLocation(Location location) { |
| return this.locations != null && this.locations.containsKey(location.getName()); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#inferBinaryName(javax.tools.JavaFileManager.Location, javax.tools.JavaFileObject) |
| */ |
| @Override |
| public String inferBinaryName(Location location, JavaFileObject file) { |
| String name = file.getName(); |
| JavaFileObject javaFileObject = null; |
| int index = name.lastIndexOf('.'); |
| if (index != -1) { |
| name = name.substring(0, index); |
| } |
| try { |
| javaFileObject = getJavaFileForInput(location, name, file.getKind()); |
| } catch (IOException e) { |
| // ignore |
| } catch (IllegalArgumentException iae) { |
| return null; // Either unknown kind or location not present |
| } |
| if (javaFileObject == null) { |
| return null; |
| } |
| return name.replace('/', '.'); |
| } |
| |
| private boolean isArchive(File f) { |
| String extension = getExtension(f); |
| return extension.equalsIgnoreCase(".jar") || extension.equalsIgnoreCase(".zip");//$NON-NLS-1$//$NON-NLS-2$ |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#isSameFile(javax.tools.FileObject, javax.tools.FileObject) |
| */ |
| @Override |
| public boolean isSameFile(FileObject fileObject1, FileObject fileObject2) { |
| // EclipseFileManager creates only EcliseFileObject |
| if (!(fileObject1 instanceof EclipseFileObject)) throw new IllegalArgumentException("Unsupported file object class : " + fileObject1.getClass());//$NON-NLS-1$ |
| if (!(fileObject2 instanceof EclipseFileObject)) throw new IllegalArgumentException("Unsupported file object class : " + fileObject2.getClass());//$NON-NLS-1$ |
| return fileObject1.equals(fileObject2); |
| } |
| /* (non-Javadoc) |
| * @see javax.tools.OptionChecker#isSupportedOption(java.lang.String) |
| */ |
| @Override |
| public int isSupportedOption(String option) { |
| return Options.processOptionsFileManager(option); |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.JavaFileManager#list(javax.tools.JavaFileManager.Location, java.lang.String, java.util.Set, boolean) |
| */ |
| @Override |
| public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) |
| throws IOException { |
| |
| Iterable<? extends File> allFilesInLocations = getLocation(location); |
| if (allFilesInLocations == null) { |
| throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ |
| } |
| |
| ArrayList<JavaFileObject> collector = new ArrayList<>(); |
| String normalizedPackageName = normalized(packageName); |
| for (File file : allFilesInLocations) { |
| collectAllMatchingFiles(file, normalizedPackageName, kinds, recurse, collector); |
| } |
| return collector; |
| } |
| |
| private String normalized(String className) { |
| char[] classNameChars = className.toCharArray(); |
| for (int i = 0, max = classNameChars.length; i < max; i++) { |
| switch(classNameChars[i]) { |
| case '\\' : |
| classNameChars[i] = '/'; |
| break; |
| case '.' : |
| classNameChars[i] = '/'; |
| } |
| } |
| return new String(classNameChars); |
| } |
| |
| private Iterable<? extends File> prependFiles(Iterable<? extends File> iterable, |
| Iterable<? extends File> iterable2) { |
| if (iterable2 == null) return iterable; |
| ArrayList<File> list = new ArrayList<>(); |
| for (Iterator<? extends File> iterator = iterable2.iterator(); iterator.hasNext(); ) { |
| list.add(iterator.next()); |
| } |
| for (Iterator<? extends File> iterator = iterable.iterator(); iterator.hasNext(); ) { |
| list.add(iterator.next()); |
| } |
| return list; |
| } |
| |
| /* (non-Javadoc) |
| * @see javax.tools.StandardJavaFileManager#setLocation(javax.tools.JavaFileManager.Location, java.lang.Iterable) |
| */ |
| @Override |
| public void setLocation(Location location, Iterable<? extends File> path) throws IOException { |
| if (path != null) { |
| if (location.isOutputLocation()) { |
| // output location |
| int count = 0; |
| for (Iterator<? extends File> iterator = path.iterator(); iterator.hasNext(); ) { |
| iterator.next(); |
| count++; |
| } |
| if (count != 1) { |
| throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$ |
| } |
| } |
| this.locations.put(location.getName(), path); |
| } |
| } |
| |
| public void setLocale(Locale locale) { |
| this.locale = locale == null ? Locale.getDefault() : locale; |
| try { |
| this.bundle = ResourceBundleFactory.getBundle(this.locale); |
| } catch(MissingResourceException e) { |
| System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$ |
| throw e; |
| } |
| } |
| |
| @SuppressWarnings({"unchecked", "rawtypes"}) |
| public void processPathEntries(final int defaultSize, final ArrayList paths, |
| final String currentPath, String customEncoding, boolean isSourceOnly, |
| boolean rejectDestinationPathOnJars) { |
| |
| String currentClasspathName = null; |
| String currentDestinationPath = null; |
| ArrayList currentRuleSpecs = new ArrayList(defaultSize); |
| StringTokenizer tokenizer = new StringTokenizer(currentPath, |
| File.pathSeparator + "[]", true); //$NON-NLS-1$ |
| ArrayList tokens = new ArrayList(); |
| while (tokenizer.hasMoreTokens()) { |
| tokens.add(tokenizer.nextToken()); |
| } |
| // state machine |
| final int start = 0; |
| final int readyToClose = 1; |
| // 'path' 'path1[rule];path2' |
| final int readyToCloseEndingWithRules = 2; |
| // 'path[rule]' 'path1;path2[rule]' |
| final int readyToCloseOrOtherEntry = 3; |
| // 'path[rule];' 'path;' 'path1;path2;' |
| final int rulesNeedAnotherRule = 4; |
| // 'path[rule1;' |
| final int rulesStart = 5; |
| // 'path[' 'path1;path2[' |
| final int rulesReadyToClose = 6; |
| // 'path[rule' 'path[rule1;rule2' |
| final int destinationPathReadyToClose = 7; |
| // 'path[-d bin' |
| final int readyToCloseEndingWithDestinationPath = 8; |
| // 'path[-d bin]' 'path[rule][-d bin]' |
| final int destinationPathStart = 9; |
| // 'path[rule][' |
| final int bracketOpened = 10; |
| // '.*[.*' |
| final int bracketClosed = 11; |
| // '.*([.*])+' |
| |
| final int error = 99; |
| int state = start; |
| String token = null; |
| int cursor = 0, tokensNb = tokens.size(), bracket = -1; |
| while (cursor < tokensNb && state != error) { |
| token = (String) tokens.get(cursor++); |
| if (token.equals(File.pathSeparator)) { |
| switch (state) { |
| case start: |
| case readyToCloseOrOtherEntry: |
| case bracketOpened: |
| break; |
| case readyToClose: |
| case readyToCloseEndingWithRules: |
| case readyToCloseEndingWithDestinationPath: |
| state = readyToCloseOrOtherEntry; |
| addNewEntry(paths, currentClasspathName, currentRuleSpecs, |
| customEncoding, currentDestinationPath, isSourceOnly, |
| rejectDestinationPathOnJars); |
| currentRuleSpecs.clear(); |
| break; |
| case rulesReadyToClose: |
| state = rulesNeedAnotherRule; |
| break; |
| case destinationPathReadyToClose: |
| throw new IllegalArgumentException( |
| this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$ |
| currentPath)); |
| case bracketClosed: |
| cursor = bracket + 1; |
| state = rulesStart; |
| break; |
| default: |
| state = error; |
| } |
| } else if (token.equals("[")) { //$NON-NLS-1$ |
| switch (state) { |
| case start: |
| currentClasspathName = ""; //$NON-NLS-1$ |
| //$FALL-THROUGH$ |
| case readyToClose: |
| bracket = cursor - 1; |
| //$FALL-THROUGH$ |
| case bracketClosed: |
| state = bracketOpened; |
| break; |
| case readyToCloseEndingWithRules: |
| state = destinationPathStart; |
| break; |
| case readyToCloseEndingWithDestinationPath: |
| state = rulesStart; |
| break; |
| case bracketOpened: |
| default: |
| state = error; |
| } |
| } else if (token.equals("]")) { //$NON-NLS-1$ |
| switch (state) { |
| case rulesReadyToClose: |
| state = readyToCloseEndingWithRules; |
| break; |
| case destinationPathReadyToClose: |
| state = readyToCloseEndingWithDestinationPath; |
| break; |
| case bracketOpened: |
| state = bracketClosed; |
| break; |
| case bracketClosed: |
| default: |
| state = error; |
| } |
| } else { |
| // regular word |
| switch (state) { |
| case start: |
| case readyToCloseOrOtherEntry: |
| state = readyToClose; |
| currentClasspathName = token; |
| break; |
| case rulesStart: |
| if (token.startsWith("-d ")) { //$NON-NLS-1$ |
| if (currentDestinationPath != null) { |
| throw new IllegalArgumentException( |
| this.bind("configure.duplicateDestinationPathEntry", //$NON-NLS-1$ |
| currentPath)); |
| } |
| currentDestinationPath = token.substring(3).trim(); |
| state = destinationPathReadyToClose; |
| break; |
| } // else we proceed with a rule |
| //$FALL-THROUGH$ |
| case rulesNeedAnotherRule: |
| if (currentDestinationPath != null) { |
| throw new IllegalArgumentException( |
| this.bind("configure.accessRuleAfterDestinationPath", //$NON-NLS-1$ |
| currentPath)); |
| } |
| state = rulesReadyToClose; |
| currentRuleSpecs.add(token); |
| break; |
| case destinationPathStart: |
| if (!token.startsWith("-d ")) { //$NON-NLS-1$ |
| state = error; |
| } else { |
| currentDestinationPath = token.substring(3).trim(); |
| state = destinationPathReadyToClose; |
| } |
| break; |
| case bracketClosed: |
| for (int i = bracket; i < cursor ; i++) { |
| currentClasspathName += (String) tokens.get(i); |
| } |
| state = readyToClose; |
| break; |
| case bracketOpened: |
| break; |
| default: |
| state = error; |
| } |
| } |
| if (state == bracketClosed && cursor == tokensNb) { |
| cursor = bracket + 1; |
| state = rulesStart; |
| } |
| } |
| switch(state) { |
| case readyToCloseOrOtherEntry: |
| break; |
| case readyToClose: |
| case readyToCloseEndingWithRules: |
| case readyToCloseEndingWithDestinationPath: |
| addNewEntry(paths, currentClasspathName, currentRuleSpecs, |
| customEncoding, currentDestinationPath, isSourceOnly, |
| rejectDestinationPathOnJars); |
| break; |
| case bracketOpened: |
| case bracketClosed: |
| default : |
| // we go on anyway |
| } |
| } |
| @SuppressWarnings({"rawtypes", "unchecked"}) |
| protected void addNewEntry(ArrayList paths, String currentClasspathName, |
| ArrayList currentRuleSpecs, String customEncoding, |
| String destPath, boolean isSourceOnly, |
| boolean rejectDestinationPathOnJars) { |
| |
| int rulesSpecsSize = currentRuleSpecs.size(); |
| AccessRuleSet accessRuleSet = null; |
| if (rulesSpecsSize != 0) { |
| AccessRule[] accessRules = new AccessRule[currentRuleSpecs.size()]; |
| boolean rulesOK = true; |
| Iterator i = currentRuleSpecs.iterator(); |
| int j = 0; |
| while (i.hasNext()) { |
| String ruleSpec = (String) i.next(); |
| char key = ruleSpec.charAt(0); |
| String pattern = ruleSpec.substring(1); |
| if (pattern.length() > 0) { |
| switch (key) { |
| case '+': |
| accessRules[j++] = new AccessRule(pattern |
| .toCharArray(), 0); |
| break; |
| case '~': |
| accessRules[j++] = new AccessRule(pattern |
| .toCharArray(), |
| IProblem.DiscouragedReference); |
| break; |
| case '-': |
| accessRules[j++] = new AccessRule(pattern |
| .toCharArray(), |
| IProblem.ForbiddenReference); |
| break; |
| case '?': |
| accessRules[j++] = new AccessRule(pattern |
| .toCharArray(), |
| IProblem.ForbiddenReference, true/*keep looking for accessible type*/); |
| break; |
| default: |
| rulesOK = false; |
| } |
| } else { |
| rulesOK = false; |
| } |
| } |
| if (rulesOK) { |
| accessRuleSet = new AccessRuleSet(accessRules, AccessRestriction.COMMAND_LINE, currentClasspathName); |
| } else { |
| return; |
| } |
| } |
| if (Main.NONE.equals(destPath)) { |
| destPath = Main.NONE; // keep == comparison valid |
| } |
| if (rejectDestinationPathOnJars && destPath != null && |
| (currentClasspathName.endsWith(".jar") || //$NON-NLS-1$ |
| currentClasspathName.endsWith(".zip"))) { //$NON-NLS-1$ |
| throw new IllegalArgumentException( |
| this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$ |
| currentClasspathName)); |
| } |
| FileSystem.Classpath currentClasspath = FileSystem.getClasspath( |
| currentClasspathName, |
| customEncoding, |
| isSourceOnly, |
| accessRuleSet, |
| destPath, null); |
| if (currentClasspath != null) { |
| paths.add(currentClasspath); |
| } |
| } |
| /* |
| * Lookup the message with the given ID in this catalog and bind its |
| * substitution locations with the given string. |
| */ |
| private String bind(String id, String binding) { |
| return bind(id, new String[] { binding }); |
| } |
| |
| /* |
| * Lookup the message with the given ID in this catalog and bind its |
| * substitution locations with the given string values. |
| */ |
| private String bind(String id, String[] arguments) { |
| if (id == null) |
| return "No message available"; //$NON-NLS-1$ |
| String message = null; |
| try { |
| message = this.bundle.getString(id); |
| } catch (MissingResourceException e) { |
| // If we got an exception looking for the message, fail gracefully by just returning |
| // the id we were looking for. In most cases this is semi-informative so is not too bad. |
| return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| return MessageFormat.format(message, (Object[]) arguments); |
| } |
| } |