blob: 4aaae65a60aaddb1594e119040cf282d68038f1b [file] [log] [blame]
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/
package org.netbeans.api.java.source;
import com.sun.source.util.JavacTask;
import java.beans.PropertyVetoException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.regex.Pattern;
import javax.swing.event.ChangeListener;
import junit.framework.Assert;
import org.netbeans.api.editor.mimelookup.MimePath;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.junit.NbTestCase;
import org.netbeans.modules.java.JavaDataLoader;
import org.netbeans.modules.java.source.indexing.JavaCustomIndexer;
import org.netbeans.modules.java.source.parsing.JavacParser;
import org.netbeans.modules.java.source.parsing.JavacParserFactory;
import org.netbeans.modules.java.source.usages.IndexUtil;
import org.netbeans.modules.parsing.api.indexing.IndexingManager;
import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
import org.netbeans.spi.java.classpath.ClassPathProvider;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.LocalFileSystem;
import org.openide.filesystems.MIMEResolver;
import org.openide.filesystems.MultiFileSystem;
import org.openide.filesystems.Repository;
import org.openide.filesystems.URLMapper;
import org.openide.filesystems.XMLFileSystem;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.openide.util.lookup.ServiceProvider;
import org.xml.sax.SAXException;
/**
*
* @author Jan Lahoda
*/
public final class SourceUtilsTestUtil extends ProxyLookup {
private static SourceUtilsTestUtil DEFAULT_LOOKUP = null;
public SourceUtilsTestUtil() {
// Assert.assertNull(DEFAULT_LOOKUP);
DEFAULT_LOOKUP = this;
}
/**
* Set the global default lookup with some fixed instances including META-INF/services/*.
*/
/**
* Set the global default lookup with some fixed instances including META-INF/services/*.
*/
public static void setLookup(Object[] instances, ClassLoader cl) {
DEFAULT_LOOKUP.setLookups(new Lookup[] {
Lookups.fixed(instances),
Lookups.metaInfServices(cl),
Lookups.singleton(cl),
});
}
private static Object[] extraLookupContent = null;
public static void prepareTest(String[] additionalLayers, Object[] additionalLookupContent) throws IOException, SAXException, PropertyVetoException {
List<URL> layers = new LinkedList<URL>();
for (int cntr = 0; cntr < additionalLayers.length; cntr++) {
boolean found = false;
for (Enumeration<URL> en = Thread.currentThread().getContextClassLoader().getResources(additionalLayers[cntr]); en.hasMoreElements(); ) {
found = true;
layers.add(en.nextElement());
}
Assert.assertTrue(additionalLayers[cntr], found);
}
XMLFileSystem xmlFS = new XMLFileSystem();
xmlFS.setXmlUrls(layers.toArray(new URL[0]));
FileSystem system = new MultiFileSystem(new FileSystem[] {FileUtil.createMemoryFileSystem(), xmlFS});
Repository repository = new Repository(system);
extraLookupContent = new Object[additionalLookupContent.length + 1];
System.arraycopy(additionalLookupContent, 0, extraLookupContent, 1, additionalLookupContent.length);
extraLookupContent[0] = repository;
SourceUtilsTestUtil.setLookup(extraLookupContent, SourceUtilsTestUtil.class.getClassLoader());
SourceUtilsTestUtil2.disableLocks();
Set<String> mimeTypes = MimeTypes.getAllMimeTypes();
if (mimeTypes == null) {
mimeTypes = new HashSet<String>();
} else {
mimeTypes = new HashSet<String>(mimeTypes);
}
mimeTypes.add("text/x-java");
MimeTypes.setAllMimeTypes(mimeTypes);
org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
}
static {
SourceUtilsTestUtil.class.getClassLoader().setDefaultAssertionStatus(true);
System.setProperty("org.openide.util.Lookup", SourceUtilsTestUtil.class.getName());
Assert.assertEquals(SourceUtilsTestUtil.class, Lookup.getDefault().getClass());
}
public static void prepareTest(FileObject sourceRoot, FileObject buildRoot, FileObject cache) throws Exception {
prepareTest(sourceRoot, buildRoot, cache, new FileObject[0]);
}
public static void prepareTest(FileObject sourceRoot, FileObject buildRoot, FileObject cache, FileObject[] classPathElements) throws Exception {
if (extraLookupContent == null)
prepareTest(new String[0], new Object[0]);
Object[] lookupContent = new Object[extraLookupContent.length + 4];
System.arraycopy(extraLookupContent, 0, lookupContent, 4, extraLookupContent.length);
lookupContent[0] = new TestProxyClassPathProvider(sourceRoot, buildRoot, classPathElements);
lookupContent[1] = new TestSourceForBinaryQuery(sourceRoot, buildRoot);
lookupContent[2] = new TestSourceLevelQueryImplementation();
lookupContent[3] = JavaDataLoader.getLoader(JavaDataLoader.class);
setLookup(lookupContent, SourceUtilsTestUtil.class.getClassLoader());
IndexUtil.setCacheFolder(FileUtil.toFile(cache));
}
private static Map<FileObject, String> file2SourceLevel = new WeakHashMap<FileObject, String>();
public static void setSourceLevel(FileObject file, String level) {
file2SourceLevel.put(file, level);
}
/**This method assures that all java classes under sourceRoot are compiled,
* and the caches are created for them.
*/
public static void compileRecursively(FileObject sourceRoot) throws Exception {
IndexingManager.getDefault().refreshIndexAndWait(sourceRoot.getURL(), null);
}
private static List<URL> bootClassPath;
private static Logger log = Logger.getLogger(SourceUtilsTestUtil.class.getName());
public static synchronized List<URL> getBootClassPath() {
if (bootClassPath == null) {
try {
String cp = System.getProperty("sun.boot.class.path");
List<URL> urls = new ArrayList<URL>();
String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
for (String path : paths) {
File f = new File(path);
if (!f.canRead())
continue;
FileObject fo = FileUtil.toFileObject(f);
if (FileUtil.isArchiveFile(fo)) {
fo = FileUtil.getArchiveRoot(fo);
}
if (fo != null) {
urls.add(fo.getURL());
}
}
bootClassPath = urls;
} catch (FileStateInvalidException e) {
if (log.isLoggable(Level.SEVERE))
log.log(Level.SEVERE, e.getMessage(), e);
}
}
return bootClassPath;
}
private static class TestSourceForBinaryQuery implements SourceForBinaryQueryImplementation {
private final FileObject sourceRoot;
private final FileObject buildRoot;
public TestSourceForBinaryQuery(FileObject sourceRoot, FileObject buildRoot) {
this.sourceRoot = sourceRoot;
this.buildRoot = buildRoot;
}
public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
FileObject f = URLMapper.findFileObject(binaryRoot);
if (buildRoot.equals(f)) {
return new SourceForBinaryQuery.Result() {
public FileObject[] getRoots() {
return new FileObject[] {
sourceRoot,
};
}
public void addChangeListener(ChangeListener l) {
}
public void removeChangeListener(ChangeListener l) {
}
};
}
return null;
}
}
private static class TestProxyClassPathProvider implements ClassPathProvider {
private FileObject sourceRoot;
private FileObject buildRoot;
private FileObject[] classPathElements;
public TestProxyClassPathProvider(FileObject sourceRoot, FileObject buildRoot, FileObject[] classPathElements) {
this.sourceRoot = sourceRoot;
this.buildRoot = buildRoot;
this.classPathElements = classPathElements;
}
public ClassPath findClassPath(FileObject file, String type) {
try {
if (ClassPath.BOOT == type) {
return ClassPathSupport.createClassPath(getBootClassPath().toArray(new URL[0]));
}
if (ClassPath.SOURCE == type) {
return ClassPathSupport.createClassPath(new FileObject[] {
sourceRoot
});
}
if (ClassPath.COMPILE == type) {
return ClassPathSupport.createClassPath(classPathElements);
}
if (ClassPath.EXECUTE == type) {
return ClassPathSupport.createClassPath(new FileObject[] {
buildRoot
});
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public static class TestSourceLevelQueryImplementation implements SourceLevelQueryImplementation {
public String getSourceLevel(FileObject javaFile) {
String level = file2SourceLevel.get(javaFile);
if (level == null) {
if (javaFile.isFolder()) {
for (FileObject data : file2SourceLevel.keySet()) {
if (FileUtil.isParentOf(javaFile, data)) {
return file2SourceLevel.get(data);
}
}
}
return "1.5";
} else
return level;
}
}
/**Copied from org.netbeans.api.project.
* Create a scratch directory for tests.
* Will be in /tmp or whatever, and will be empty.
* If you just need a java.io.File use clearWorkDir + getWorkDir.
*/
public static FileObject makeScratchDir(NbTestCase test) throws IOException {
test.clearWorkDir();
File root = test.getWorkDir();
assert root.isDirectory() && root.list().length == 0;
FileObject fo = FileUtil.toFileObject(root);
if (fo != null) {
// Presumably using masterfs.
return fo;
} else {
// For the benefit of those not using masterfs.
LocalFileSystem lfs = new LocalFileSystem();
try {
lfs.setRootDirectory(root);
} catch (PropertyVetoException e) {
assert false : e;
}
Repository.getDefault().addFileSystem(lfs);
return lfs.getRoot();
}
}
public static JavacTask getJavacTaskFor(CompilationInfo info) {
return info.impl.getJavacTask();
}
/** Blocking call for CompilationInfo after given phase is reached.
* @param phase to be reached
* @return CompilationInfo or null
* XXX: REMOVE ME!!!!!!!
*/
public static CompilationInfo getCompilationInfo(JavaSource js, Phase phase ) throws IOException {
if (phase == null || phase == Phase.MODIFIED) {
throw new IllegalArgumentException (String.format("The %s is not a legal value of phase",phase)); //NOI18N
}
final DeadlockTask bt = new DeadlockTask(phase);
js.runUserActionTask(bt,true);
return bt.info;
}
private static class DeadlockTask implements Task<CompilationController> {
private final Phase phase;
private CompilationInfo info;
public DeadlockTask(Phase phase) {
assert phase != null;
this.phase = phase;
}
public void run( CompilationController info ) {
try {
info.toPhase(this.phase);
this.info = info;
} catch (IOException ioe) {
if (log.isLoggable(Level.SEVERE))
log.log(Level.SEVERE, ioe.getMessage(), ioe);
}
}
}
@ServiceProvider(service=MimeDataProvider.class)
public static final class JavacParserProvider implements MimeDataProvider {
private Lookup javaLookup = Lookups.fixed(new JavacParserFactory(), new JavaCustomIndexer.Factory());
public Lookup getLookup(MimePath mimePath) {
if (mimePath.getPath().endsWith(JavacParser.MIME_TYPE)) {
return javaLookup;
}
return Lookup.EMPTY;
}
}
@ServiceProvider(service=MIMEResolver.class)
public static final class JavaMimeResolver extends MIMEResolver {
public JavaMimeResolver() {
super(JavacParser.MIME_TYPE);
}
@Override
public String findMIMEType(FileObject fo) {
if ("java".equals(fo.getExt())) {
return JavacParser.MIME_TYPE;
}
return null;
}
}
}