diff -r 9db4e8ed858b projectapi/src/org/netbeans/modules/projectapi/GenericProjectFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projectapi/src/org/netbeans/modules/projectapi/GenericProjectFactory.java Sun Dec 26 11:14:14 2010 +0100 @@ -0,0 +1,144 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2010 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.projectapi; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager.Result; +import org.netbeans.spi.project.ProjectFactory2; +import org.netbeans.spi.project.ProjectState; +import org.openide.filesystems.FileObject; +import org.openide.util.ImageUtilities; +import org.openide.util.Lookup; + +/** + * + * @author Jaroslav Tulach + */ +public final class GenericProjectFactory implements ProjectFactory2 { + private final String mimeType; + private final List relativeFiles; + private final String iconBase; + private final String clazz; + private final String method; + + private GenericProjectFactory( + String mimeType, List relativeFiles, String iconBase, + String clazz, String method + ) { + this.mimeType = mimeType; + this.relativeFiles = relativeFiles; + this.iconBase = iconBase; + this.clazz = clazz; + this.method = method; + } + + public static GenericProjectFactory create(FileObject fo) { + List arr = new ArrayList(); + for (int cnt = 0; ; cnt++) { + Object attr = fo.getAttribute("relativeFile." + cnt); + if (attr instanceof String) { + arr.add((String)attr); + } else { + break; + } + } + return new GenericProjectFactory( + (String)fo.getAttribute("mimeType"), + arr, + (String)fo.getAttribute("iconBase"), + (String)fo.getAttribute("class"), + (String)fo.getAttribute("method") + ); + } + + @Override + public Result isProject2(FileObject projectDirectory) { + if (isProject(projectDirectory)) { + return new Result(ImageUtilities.loadImageIcon(iconBase, true)); + } + return null; + } + + @Override + public boolean isProject(FileObject projectDirectory) { + for (String rp: relativeFiles) { + FileObject fo = projectDirectory.getFileObject(rp); + if (fo == null) { + continue; + } + if (mimeType != null && !mimeType.equals(fo.getMIMEType())) { + continue; + } + return true; + } + return false; + } + + @Override + public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException { + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class); + if (l == null) { + l = Thread.currentThread().getContextClassLoader(); + } + if (l == null) { + l = GenericProjectFactory.class.getClassLoader(); + } + try { + Class real = Class.forName(this.clazz, true, l); + Method m = real.getMethod(method, FileObject.class); + return (Project) m.invoke(null, projectDirectory); + } catch (Exception ex) { + throw new IOException(ex); + } + } + + @Override + public void saveProject(Project project) throws IOException, ClassCastException { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff -r 9db4e8ed858b projectapi/src/org/netbeans/modules/projectapi/GenericProjectProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projectapi/src/org/netbeans/modules/projectapi/GenericProjectProcessor.java Sun Dec 26 11:14:14 2010 +0100 @@ -0,0 +1,121 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2010 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.projectapi; + +import java.util.List; +import java.util.Set; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import org.netbeans.api.project.Project; +import org.netbeans.spi.project.ProjectRegistration; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.annotations.LayerBuilder.File; +import org.openide.filesystems.annotations.LayerGeneratingProcessor; +import org.openide.filesystems.annotations.LayerGenerationException; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Jaroslav Tulach + */ +@SupportedAnnotationTypes("org.netbeans.spi.project.ProjectRegistration") +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@ServiceProvider(service=Processor.class) +public final class GenericProjectProcessor extends LayerGeneratingProcessor { + @Override + protected boolean handleProcess(Set annotations, RoundEnvironment roundEnv) throws LayerGenerationException { + for (Element e : roundEnv.getElementsAnnotatedWith(ProjectRegistration.class)) { + ProjectRegistration pr = e.getAnnotation(ProjectRegistration.class); + String[] param = getMethod(e); + File f = layer(e).file("Services/ProjectFactories/" + + param[0].replace('.', '-') + "-" + param[1] + ".instance" + ); + f.methodvalue("instanceCreate", GenericProjectFactory.class.getName(), "create"); + if (pr.mimeType().length() > 0) { + f.stringvalue("mimeType", pr.mimeType()); + } + f.stringvalue("iconBase", pr.iconBase()); + int cnt = 0; + for (String p : pr.relativeFile()) { + f.stringvalue("relativeFile." + cnt++, p); + } + f.stringvalue("class", param[0]); + f.stringvalue("method", param[1]); + f.write(); + } + return true; + } + + private String[] getMethod(Element originatingElement) throws LayerGenerationException { + TypeMirror projectMirror = processingEnv.getTypeUtils().getDeclaredType( + processingEnv.getElementUtils().getTypeElement(Project.class.getName()) + ); + TypeMirror foMirror = processingEnv.getTypeUtils().getDeclaredType( + processingEnv.getElementUtils().getTypeElement(FileObject.class.getName()) + ); + String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) originatingElement.getEnclosingElement()).toString(); + String method = originatingElement.getSimpleName().toString(); + if (!originatingElement.getModifiers().contains(Modifier.STATIC)) { + throw new LayerGenerationException(clazz + "." + method + " must be static", originatingElement); + } + final List params = ((ExecutableElement) originatingElement).getParameters(); + boolean sameType = processingEnv.getTypeUtils().isSameType(params.get(0).asType(), foMirror); + if (params.size() != 1 || !sameType) { + throw new LayerGenerationException(clazz + "." + method + " must take org.openide.filesystems.FileObject agrument", originatingElement); + } + if (projectMirror != null && !processingEnv.getTypeUtils().isAssignable(((ExecutableElement) originatingElement).getReturnType(), projectMirror)) { + throw new LayerGenerationException(clazz + "." + method + " is not assignable to " + projectMirror, originatingElement); + } + return new String[] {clazz, method}; + } + +} diff -r 9db4e8ed858b projectapi/src/org/netbeans/spi/project/ProjectRegistration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projectapi/src/org/netbeans/spi/project/ProjectRegistration.java Sun Dec 26 11:14:14 2010 +0100 @@ -0,0 +1,85 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2010 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.project; + +import java.io.IOException; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.netbeans.api.project.Project; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.MIMEResolver; + +/** Annotate static factory method that converts + * {@link FileObject} to {@link Project} (the method + * can return null and also thrown an {@link IOException}). + * + * @author Jaroslav Tulach + * @since 1.35 + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +public @interface ProjectRegistration { + /** Path to icon that represents the project produced + * by this factory method. + * @return icon path + */ + String iconBase(); + + /** File or list of relative files to check for. At least one + * of these files must be present and must have appropriate + * {@link #mimeType} (if specified). + * + * @return relative paths separated by '/' + */ + String[] relativeFile(); + /** The mime type of one of the relative files. By specifying + * the mime type you can also check inside of the {@link #relativeFile relative files}. + * See {@link MIMEResolver} for a way to specify mime type based + * on content of a file. + * @return required mime type + */ + String mimeType() default ""; +} + diff -r 9db4e8ed858b projectapi/test/unit/src/org/netbeans/spi/project/ProjectRegistrationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projectapi/test/unit/src/org/netbeans/spi/project/ProjectRegistrationTest.java Sun Dec 26 11:14:14 2010 +0100 @@ -0,0 +1,131 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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]" + * + * 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. + * + * Contributor(s): + * + * Portions Copyrighted 2010 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.project; + +import java.io.IOException; +import java.util.Collection; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.ProjectManager.Result; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.projectapi.GenericProjectFactory; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.ImageUtilities; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; +import org.openide.util.test.MockLookup; + +public class ProjectRegistrationTest extends NbTestCase { + static { + FileUtil.setMIMEType("tu", "application/x-jarda"); + } + static int cnt; + + public ProjectRegistrationTest(String name) { + super(name); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + MockLookup.init(); + MockLookup.setLookup( + Lookups.singleton(ProjectRegistrationTest.class.getClassLoader()), + Lookups.forPath("Services/ProjectFactories") + ); + Collection all2 = Lookup.getDefault().lookupAll(ProjectFactory.class); + assertEquals("One ", 1, all2.size()); + assertTrue(all2.iterator().next() instanceof GenericProjectFactory); + } + + + + @ProjectRegistration( + iconBase="org/netbeans/api/project/resources/icon-1.png", + relativeFile="jar/da.tu" + ) + public static Project recognize(FileObject fo) throws IOException { + cnt++; + return new MyPrj(fo); + } + + public void testRegognize() throws IOException { + FileObject root = FileUtil.createMemoryFileSystem().getRoot(); + FileObject tu = FileUtil.createData(root, "my/x/jar/da.tu"); + FileObject jar = tu.getParent(); + FileObject x = jar.getParent(); + + assertFalse("Not a project", ProjectManager.getDefault().isProject(jar)); + assertTrue("Possibly a project", ProjectManager.getDefault().isProject(x)); + assertEquals("No calls to factory yet", 0, cnt); + Result res = ProjectManager.getDefault().isProject2(x); + assertEquals("The same icon", + res.getIcon(), + ImageUtilities.loadImageIcon("org/netbeans/api/project/resources/icon-1.png", true) + ); + Project p = ProjectManager.getDefault().findProject(x); + assertNotNull("Project really created"); + assertEquals("One call to factory", 1, cnt); + assertEquals("The right type", MyPrj.class, p.getClass()); + } + + private static class MyPrj implements Project { + private final FileObject prj; + + public MyPrj(FileObject prj) { + this.prj = prj; + } + + @Override + public FileObject getProjectDirectory() { + return prj; + } + + @Override + public Lookup getLookup() { + return Lookup.EMPTY; + } + + } +} \ No newline at end of file