/* * The contents of this file are subject to the terms of the Common Development * and Distribution License (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.html * or http://www.netbeans.org/cddl.txt. * * When distributing Covered Code, include this CDDL Header Notice in each file * and include the License file at http://www.netbeans.org/cddl.txt. * If applicable, add the following below the CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" */ package org.netbeans.modules.gwt4nb; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import java.util.logging.Level; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.netbeans.api.project.Project; import org.netbeans.api.project.Sources; import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.modules.gwt4nb.common.IOUtils; import org.netbeans.modules.gwt4nb.common.IOUtils.FileNameExtensionPredicate; import org.netbeans.spi.project.AuxiliaryConfiguration; import org.netbeans.spi.project.support.ant.EditableProperties; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class GWTProjectInfo { public static final String BUILD_GWT = "build-gwt.xml"; // NOI18N public static final String PRJ_DIR = "nbproject"; // NOI18N public static final String GWT_PROPERTIES = "gwt.properties"; // NOI18N public static final String RESOURCE_BASE = "org/netbeans/modules/gwt4nb/resources/"; // NOI18N public static final String WELCOME_FILE = "welcomeGWT.html"; // NOI18N private static final String GWT_MODULE_EXTENSION = ".gwt.xml"; private static Map<Project, WeakReference<GWTProjectInfo>> infos = new WeakHashMap<Project, WeakReference<GWTProjectInfo>>(); /** * @param module a GWT module like "org.yournamehere.Main" * @return package for server classes (default module) */ public static String getServerPackage(String module) { return getModulePackage(module) + ".server"; // NOI18N } /** * Finds the first name of a registered "source-root" in a web project. * This method uses the {@code AuxiliaryConfiguration} and reads in the * web-apps data section to find the <source-roots> element and * the <root> elements it contains. * * @param project the {@code Project} to find the source-root of * @return the reference to the source-root as described in the * project.xml file */ private static String getSourcesDirReference(final Project project) { final AuxiliaryConfiguration configuration = ProjectUtils.getAuxiliaryConfiguration(project); final Element webappElement = configuration.getConfigurationFragment( "data", "http://www.netbeans.org/ns/web-project/3", true); // NOI18N if(webappElement != null) { final Element sourceRootsElement = (Element)webappElement. getElementsByTagName("source-roots").item(0); // NOI18N if(sourceRootsElement != null) { final NodeList sourceRoots = sourceRootsElement.getElementsByTagName("root"); // NOI18N for(int i = 0; i < sourceRoots.getLength(); i++) { final Element root = (Element)sourceRoots.item(i); final String id = root.getAttribute("id"); // NOI18N if(id.length() > 0) { return id; } } } } return "src.dir"; // NOI18N } /** * @param module a GWT module like org.yournamehere.Main * @return package for client classes */ public static String getClientPackage(String module) { return getModulePackage(module) + ".client"; // NOI18N } /** * Test whether a project is a GWT project. * * @param project a project * @return true = Ant or Maven based GWT project */ public static boolean isGWTProject(Project project) { return get(project) != null; } /** * Test whether a project is a GWT project. * * @param project a project * @return true = Ant or Maven based GWT project */ public static boolean isAntGWTProject(Project project) { GWTProjectInfo info = get(project); return info != null && !info.isMaven(); } /** * Test whether a project is a Maven project and GWT project. * * @param project a project or null * @return true = Maven based GWT project */ public static boolean isMavenGWTProject(Project project) { GWTProjectInfo info = get(project); return info != null && info.isMaven(); } /** * Reads a property from gwt.properties * * @param project a project * @param propName name of the property * @return value of the property or null if absent */ public static String readGWTPropertyAnt(Project project, String propName){ GWTProjectInfo info = get(project); String r = null; if (info != null) r = info.getAntProperty(propName); return r; } public static void writeGWTPropertyAnt(Project project, String propName, String propValue) { GWTProjectInfo info = get(project); if (info != null) { info.setAntProperty(propName, propValue); } } /** * Determines package name from a module name * * @param module module name like org.yournamehere.Main * @return package name "org.yournamehere" */ public static String getModulePackage(String module){ int end = module.lastIndexOf("."); // NOI18N if (end <= 0) { //fallback to full modulename (which may contain no dot) return module; } return module.substring(0, end); } /** * @param project a GWT project * @return directory for sources (/src) */ public static FileObject getSourcesDir(final Project project) { return get(project).getSourcesDir(); } /** * Returns (maybe cached) GWT project information. * * @param p a project (Maven or Ant) * @return GWT project information or null if p is not a GWT project */ public static GWTProjectInfo get(Project p) { WeakReference<GWTProjectInfo> infor = infos.get(p); GWTProjectInfo info; if (infor != null) info = infor.get(); else info = null; if (info == null) { final FileObject projectDirectory = p.getProjectDirectory(); FileObject pom = projectDirectory.getFileObject("pom.xml"); // NOI18N if (pom != null) { try { Document pomDoc = GWT4NBUtil.parseXMLFile(pom); XPathFactory factory = XPathFactory.newInstance(); XPath xp = factory.newXPath(); NodeList nl = (NodeList) xp.evaluate( "//project/build/plugins/plugin[artifactId='gwt-maven-plugin']", // NOI18N pomDoc, XPathConstants.NODESET); if (nl.getLength() > 0) info = new GWTProjectInfo(p, true); } catch (Exception ex) { GWT4NBUtil.LOGGER.log(Level.FINE, null, ex); } } else { FileObject buildGWT = projectDirectory. getFileObject(PRJ_DIR + "/" + BUILD_GWT); // NOI18N if (buildGWT != null) info = new GWTProjectInfo(p, false); } if (info != null) infos.put(p, new WeakReference<GWTProjectInfo>(info)); } return info; } /** * Removes cache entry for a project. * * @param p GWT project (Maven or Ant) */ public static void removeCacheEntry(Project p) { infos.remove(p); } private final Project project; private boolean maven; /** * @param p a GWT project (Maven or Ant) * @param maven true = Maven, false = Ant */ private GWTProjectInfo(Project p, boolean maven) { this.project = p; this.maven = maven; } /** * @return true = Maven, false = Ant */ public boolean isMaven() { return maven; } /** * Changes the value of a property in nbproject/gwt.properties. Does * nothing for Maven projects. * * @param propName name of the property * @param propValue value of the property */ public void setAntProperty(String propName, String propValue) { EditableProperties p = getProperties(); if (p != null) { p.setProperty(propName, propValue); setProperties(p); } } /** * gwt.properties * * @return gwt.properties or null for Maven projects */ public EditableProperties getProperties() { if (!maven) { EditableProperties props = new EditableProperties(false); FileObject propsFile = project.getProjectDirectory(). getFileObject(PRJ_DIR + "/" + GWT_PROPERTIES); // NOI18N if (propsFile != null) { try { InputStream is = propsFile.getInputStream(); props.load(is); is.close(); } catch (IOException e) { GWT4NBUtil.LOGGER.log(Level.SEVERE, "", e); // NOI18N } } return props; } else { return null; } } /** * Reads a property from nbproject/gwt.properties. * * @param propName name of the property * @return property value or null if absent or it is a Maven project */ public String getAntProperty(String propName) { EditableProperties p = getProperties(); if (p != null) return p.getProperty(propName); else return null; } /** * @return GWT version. */ public Version getGWTVersion() { Version r = null; if (maven) r = new Version(new int[] {1, 7, 0}); else { String versionString = readGWTPropertyAnt(project, "gwt.version"); // NOI18N if (versionString == null) { File d = GWT4NBUtil.getProjectGWTDir(project); if (d != null) versionString = GWT4NBUtil.findGWTVersion(d); if (versionString == null) versionString = "1.6"; // NOI18N writeGWTPropertyAnt(project, "gwt.version", versionString); // NOI18N } if (versionString != null) r = new Version(versionString); } return r; } /** * @return GWT modules like "org.yournamehere.Main" */ public List<String> getModules() { List<String> r = new ArrayList<String>(); if (maven){ FileObject pom = project.getProjectDirectory().getFileObject("pom.xml"); // NOI18N r.addAll(getModulesFromPOM(pom)); r.addAll(getModulesFromFileSystem(project)); } else { String gm = readGWTPropertyAnt(project, "gwt.module"); // NOI18N if (gm == null) gm = ""; String[] s = gm.split(" "); // NOI18N if (s.length > 0) { r.addAll(Arrays.asList(s)); } } return r; } /** * Reads the available modules from the pom.xml at <pre>configuration/modules/module</pre> * @param pom * @return */ private Collection<String> getModulesFromPOM(FileObject pom) { List<String> r=new ArrayList<String>(); if (pom != null) { try { Document pomDoc = GWT4NBUtil.parseXMLFile(pom); XPathFactory factory = XPathFactory.newInstance(); XPath xp = factory.newXPath(); NodeList nl = (NodeList) xp.evaluate( "//project/build/plugins/plugin[artifactId='gwt-maven-plugin']/configuration/modules/module", // NOI18N pomDoc, XPathConstants.NODESET); if (nl.getLength() > 0) { for (int i = 0; i < nl.getLength(); i++) { Node item = nl.item(i); r.add(item.getTextContent()); } } } catch (Exception ex) { Exceptions.printStackTrace(ex); } } return r; } /** * Reads the available modules from the source and resource roots from the projects. * * The logic for the auto-detection works like the gwt-maven-plugin. */ private Collection<String> getModulesFromFileSystem(Project project) { Sources sources = ProjectUtils.getSources(project); List<SourceGroup> sourceGroups = new ArrayList<SourceGroup>(); sourceGroups.addAll(Arrays.asList(sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA))); sourceGroups.addAll(Arrays.asList(sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES))); List<String> modules = new ArrayList<String>(); for (SourceGroup sourceGroup : sourceGroups) { File sourceRootDir = FileUtil.toFile(sourceGroup.getRootFolder()); Collection<File> moduleFiles = IOUtils.findRecursive(sourceRootDir, new FileNameExtensionPredicate(GWT_MODULE_EXTENSION)); for (File moduleFile : moduleFiles) { modules.add(getModuleNameFromFileName(moduleFile, sourceRootDir)); } } return modules; } private String getModuleNameFromFileName(File file, File sourceRootDir) { String fileName = file.getAbsolutePath(); //file=C:\Users\markiewb\Documents\NetBeansProjects\GWTGAEProjectSample\src\main\java\org\yournamehere\Main.gwt.xml //sourceRootDir=C:\Users\markiewb\Documents\NetBeansProjects\GWTGAEProjectSample\src\main\java //keep only the path relative to src/main/java or src/main/resources if (file.getAbsolutePath().startsWith(sourceRootDir.getAbsolutePath())) { fileName = file.getAbsolutePath().substring(sourceRootDir.getAbsolutePath().length()); } String path = fileName.substring(0, fileName.length() - GWT_MODULE_EXTENSION.length()); path = path.replace(File.separatorChar, '.'); if (path.startsWith(".") && path.length() > 1) { path = path.substring(1); } return path; } /** * @return first directory for source files */ public FileObject getSourcesDir() { final Sources sources = ProjectUtils.getSources(project); final SourceGroup[] javaSources = sources.getSourceGroups( JavaProjectConstants.SOURCES_TYPE_JAVA); final String referenceName = getSourcesDirReference(project); for(final SourceGroup sg : javaSources) { final String name = sg.getName(); if(name.equals(referenceName) || // ${referenceName} name.regionMatches(2, referenceName, 0, referenceName.length())) { return sg.getRootFolder(); } } // SourceRoot is used by Maven projects for(final SourceGroup sg : javaSources) { final String name = sg.getName(); if(name.equals("SourceRoot")) { // NOI18N return sg.getRootFolder(); } } if (javaSources.length > 0) return javaSources[0].getRootFolder(); else return project.getProjectDirectory(). getFileObject("src/java"); // NOI18N } /** * Registers a new GWT module in gwt.properties * * @param module name of the module */ public void registerModule(String module) { if (!maven) { String gm = readGWTPropertyAnt(project, "gwt.module"); // NOI18N if (gm == null) gm = ""; // NOI18N gm = gm.trim(); if (gm.length() != 0) gm += " "; // NOI18N gm += module; writeGWTPropertyAnt(project, "gwt.module", gm); // NOI18N } } /** * Saves gwt.properties. No-op for Maven projects. * * @param props gwt.properties */ public void setProperties(EditableProperties props) { if (!maven) { FileObject propsFile = project.getProjectDirectory(). getFileObject(PRJ_DIR + "/" + GWT_PROPERTIES); // NOI18N try { OutputStream os = propsFile.getOutputStream(); props.store(os); os.close(); } catch (IOException e) { GWT4NBUtil.LOGGER.log(Level.SEVERE, "", e); // NOI18N } } } }