Java tutorial
package org.jfrog.jade.plugins.idea; /* * Copyright 2005-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.StringUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.jfrog.maven.annomojo.annotations.MojoExecute; import org.jfrog.maven.annomojo.annotations.MojoGoal; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Creates the module (*.iml) files for IntelliJ Idea * * @author Edwin Punzalan */ @MojoGoal("module") @MojoExecute(phase = "generate-sources") public class IdeaModuleMojo extends AbstractModuleIdeaMojo { /** * Create IDEA (.iml) project files. * * @throws org.apache.maven.plugin.MojoExecutionException * */ public void execute() throws MojoExecutionException { try { doDependencyResolution(); } catch (Exception e) { throw new MojoExecutionException("Unable to build project dependencies.", e); } rewriteModule(); } public void rewriteModule() throws MojoExecutionException { MavenProject executedProject = getExecutedProject(); File moduleFile = new File(executedProject.getBasedir(), getIdeProjectName() + ".iml"); try { Document document = readXmlDocument(moduleFile, "module.xml"); Element module = document.getRootElement(); // TODO: how can we let the WAR/EJBs plugin hook in and provide this? // TODO: merge in ejb-module, etc. if ("war".equals(executedProject.getPackaging())) { addWebModule(module); } else if ("ejb".equals(executedProject.getPackaging())) { addEjbModule(module); } else if ("ear".equals(executedProject.getPackaging())) { addEarModule(module); } else if (isIdeaPlugin()) { addPluginModule(module); } Element component = findComponent(module, "NewModuleRootManager"); Element output = findElement(component, "output"); output.addAttribute("url", getModuleFileUrl(executedProject.getBuild().getOutputDirectory())); Element outputTest = findElement(component, "output-test"); outputTest.addAttribute("url", getModuleFileUrl(executedProject.getBuild().getTestOutputDirectory())); Element content = findElement(component, "content"); removeOldElements(content, "sourceFolder"); for (Iterator i = executedProject.getCompileSourceRoots().iterator(); i.hasNext();) { String directory = (String) i.next(); addSourceFolder(content, directory, false); } for (Iterator i = executedProject.getTestCompileSourceRoots().iterator(); i.hasNext();) { String directory = (String) i.next(); addSourceFolder(content, directory, true); } for (Iterator i = executedProject.getBuild().getResources().iterator(); i.hasNext();) { Resource resource = (Resource) i.next(); String directory = resource.getDirectory(); if (resource.getTargetPath() == null && !resource.isFiltering()) { addSourceFolder(content, directory, false); } else { getLog().info( "Not adding resource directory as it has an incompatible target path or filtering: " + directory); } } for (Iterator i = executedProject.getBuild().getTestResources().iterator(); i.hasNext();) { Resource resource = (Resource) i.next(); String directory = resource.getDirectory(); if (resource.getTargetPath() == null && !resource.isFiltering()) { addSourceFolder(content, directory, true); } else { getLog().info( "Not adding test resource directory as it has an incompatible target path or filtering: " + directory); } } removeOldElements(content, "excludeFolder"); //For excludeFolder File target = new File(executedProject.getBuild().getDirectory()); File classes = new File(executedProject.getBuild().getOutputDirectory()); File testClasses = new File(executedProject.getBuild().getTestOutputDirectory()); List sourceFolders = content.elements("sourceFolder"); List<String> filteredExcludes = new ArrayList<String>(); filteredExcludes.addAll(getExcludedDirectories(target, filteredExcludes, sourceFolders)); filteredExcludes.addAll(getExcludedDirectories(classes, filteredExcludes, sourceFolders)); filteredExcludes.addAll(getExcludedDirectories(testClasses, filteredExcludes, sourceFolders)); if (getExclude() != null) { String[] dirs = getExclude().split("[,\\s]+"); for (int i = 0; i < dirs.length; i++) { File excludedDir = new File(executedProject.getBasedir(), dirs[i]); filteredExcludes.addAll(getExcludedDirectories(excludedDir, filteredExcludes, sourceFolders)); } } // even though we just ran all the directories in the filteredExcludes List through the intelligent // getExcludedDirectories method, we never actually were guaranteed the order that they were added was // in the order required to make the most optimized exclude list. In addition, the smart logic from // that method is entirely skipped if the directory doesn't currently exist. A simple string matching // will do pretty much the same thing and make the list more concise. List<String> actuallyExcluded = new ArrayList<String>(); Collections.sort(filteredExcludes); for (Iterator i = filteredExcludes.iterator(); i.hasNext();) { String dirToExclude = i.next().toString(); String dirToExcludeTemp = dirToExclude.replace('\\', '/'); boolean addExclude = true; for (Iterator iterator = actuallyExcluded.iterator(); iterator.hasNext();) { String dir = iterator.next().toString(); String dirTemp = dir.replace('\\', '/'); if (dirToExcludeTemp.startsWith(dirTemp + "/")) { addExclude = false; break; } else if (dir.startsWith(dirToExcludeTemp + "/")) { actuallyExcluded.remove(dir); } } if (addExclude) { actuallyExcluded.add(dirToExclude); addExcludeFolder(content, dirToExclude); } } rewriteDependencies(component); writeXmlDocument(moduleFile, document); } catch (DocumentException e) { throw new MojoExecutionException("Error parsing existing IML file " + moduleFile.getAbsolutePath(), e); } catch (IOException e) { throw new MojoExecutionException("Error parsing existing IML file " + moduleFile.getAbsolutePath(), e); } } private void rewriteDependencies(Element component) { Map<String, Element> modulesByName = new HashMap<String, Element>(); Map<String, Element> modulesByUrl = new HashMap<String, Element>(); Set<Element> unusedModules = new HashSet<Element>(); for (Iterator children = component.elementIterator("orderEntry"); children.hasNext();) { Element orderEntry = (Element) children.next(); String type = orderEntry.attributeValue("type"); if ("module".equals(type)) { modulesByName.put(orderEntry.attributeValue("module-name"), orderEntry); } else if ("module-library".equals(type)) { // keep track for later so we know what is left unusedModules.add(orderEntry); Element lib = orderEntry.element("library"); String name = lib.attributeValue("name"); if (name != null) { modulesByName.put(name, orderEntry); } else { Element classesChild = lib.element("CLASSES"); if (classesChild != null) { Element rootChild = classesChild.element("root"); if (rootChild != null) { String url = rootChild.attributeValue("url"); if (url != null) { // Need to ignore case because of Windows drive letters modulesByUrl.put(url.toLowerCase(), orderEntry); } } } } } } List testClasspathElements = getExecutedProject().getTestArtifacts(); for (Iterator i = testClasspathElements.iterator(); i.hasNext();) { Artifact a = (Artifact) i.next(); Library library = findLibrary(a); if (library != null && library.isExclude()) { continue; } String moduleName; if (isUseFullNames()) { moduleName = a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getType() + ':' + a.getVersion(); } else { moduleName = getNameProvider().getProjectName(a); } Element dep = (Element) modulesByName.get(moduleName); if (dep == null) { // Need to ignore case because of Windows drive letters dep = (Element) modulesByUrl.get(getLibraryUrl(a).toLowerCase()); } if (dep != null) { unusedModules.remove(dep); } else { dep = createElement(component, "orderEntry"); } boolean isIdeaModule = false; if (isLinkModules()) { isIdeaModule = isReactorProject(a.getGroupId(), a.getArtifactId()); if (isIdeaModule) { dep.addAttribute("type", "module"); dep.addAttribute("module-name", moduleName); } } if (a.getFile() != null && !isIdeaModule) { dep.addAttribute("type", "module-library"); Element lib = dep.element("library"); if (lib == null) { lib = createElement(dep, "library"); } if (isDependenciesAsLibraries()) { lib.addAttribute("name", moduleName); } // replace classes removeOldElements(lib, "CLASSES"); Element classes = createElement(lib, "CLASSES"); if (library != null && library.getSplitClasses().length > 0) { lib.addAttribute("name", moduleName); String[] libraryClasses = library.getSplitClasses(); for (int k = 0; k < libraryClasses.length; k++) { String classpath = libraryClasses[k]; extractMacro(classpath); Element classEl = createElement(classes, "root"); classEl.addAttribute("url", classpath); } } else { createElement(classes, "root").addAttribute("url", getLibraryUrl(a)); } if (library != null && library.getSplitSources().length > 0) { removeOldElements(lib, "SOURCES"); Element sourcesElement = createElement(lib, "SOURCES"); String[] sources = library.getSplitSources(); for (int k = 0; k < sources.length; k++) { String source = sources[k]; extractMacro(source); Element sourceEl = createElement(sourcesElement, "root"); sourceEl.addAttribute("url", source); } } else if (isDownloadSources()) { resolveClassifier(createOrGetElement(lib, "SOURCES"), a, getSourceClassifier()); } if (isDownloadJavadocs()) { resolveClassifier(createOrGetElement(lib, "JAVADOC"), a, getJavadocClassifier()); } } } for (Iterator i = unusedModules.iterator(); i.hasNext();) { Element orderEntry = (Element) i.next(); component.remove(orderEntry); } } private Element createOrGetElement(Element lib, String name) { Element el = lib.element("name"); if (el == null) { el = createElement(lib, name); } return el; } private void addEarModule(Element module) { module.addAttribute("type", "J2EE_APPLICATION_MODULE"); Element component = findComponent(module, "ApplicationModuleProperties"); addDeploymentDescriptor(component, "application.xml", "1.3", getExecutedProject().getBuild().getDirectory() + "/application.xml"); } private void addEjbModule(Element module) { module.addAttribute("type", "J2EE_EJB_MODULE"); MavenProject executedProject = getExecutedProject(); String explodedDir = executedProject.getBuild().getDirectory() + "/" + getIdeProjectName(); Element component = findComponent(module, "EjbModuleBuildComponent"); Element setting = findSetting(component, "EXPLODED_URL"); setting.addAttribute("value", getModuleFileUrl(explodedDir)); component = findComponent(module, "EjbModuleProperties"); addDeploymentDescriptor(component, "ejb-jar.xml", "2.x", "src/main/resources/META-INF/ejb-jar.xml"); removeOldElements(component, "containerElement"); List artifacts = executedProject.getTestArtifacts(); for (Iterator i = artifacts.iterator(); i.hasNext();) { Artifact artifact = (Artifact) i.next(); Element containerElement = createElement(component, "containerElement"); if (isLinkModules() && isReactorProject(artifact.getGroupId(), artifact.getArtifactId())) { containerElement.addAttribute("type", "module"); containerElement.addAttribute("name", getNameProvider().getProjectName(artifact)); Element methodAttribute = createElement(containerElement, "attribute"); methodAttribute.addAttribute("name", "method"); methodAttribute.addAttribute("value", "6"); Element uriAttribute = createElement(containerElement, "attribute"); uriAttribute.addAttribute("name", "URI"); uriAttribute.addAttribute("value", "/WEB-INF/classes"); } else if (artifact.getFile() != null) { containerElement.addAttribute("type", "library"); containerElement.addAttribute("level", "module"); containerElement.addAttribute("name", getNameProvider().getProjectName(artifact)); Element methodAttribute = createElement(containerElement, "attribute"); methodAttribute.addAttribute("name", "method"); methodAttribute.addAttribute("value", "2"); Element uriAttribute = createElement(containerElement, "attribute"); uriAttribute.addAttribute("name", "URI"); uriAttribute.addAttribute("value", "/WEB-INF/lib/" + artifact.getFile().getName()); } } } private void extractMacro(String path) { if (getMacros() != null) { Pattern p = Pattern.compile(".*\\$([^\\$]+)\\$.*"); Matcher matcher = p.matcher(path); while (matcher.find()) { String macro = matcher.group(1); getMacros().add(macro); } } } private Library findLibrary(Artifact a) { Library[] libraries = getLibraries(); if (libraries != null) { for (int j = 0; j < libraries.length; j++) { Library library = libraries[j]; if (a.getArtifactId().equals(library.getName())) { return library; } } } return null; } private List<String> getExcludedDirectories(File target, List excludeList, List sourceFolders) { List<String> foundFolders = new ArrayList<String>(); int totalDirs = 0, excludedDirs = 0; if (target.exists() && !excludeList.contains(target.getAbsolutePath())) { File[] files = target.listFiles(); for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isDirectory() && !excludeList.contains(file.getAbsolutePath())) { totalDirs++; // the '/' character is added to the directory path since the // source urls end with this character String absolutePath = file.getAbsolutePath() + "/"; String url = getModuleFileUrl(absolutePath); boolean addToExclude = true; for (Iterator sources = sourceFolders.iterator(); sources.hasNext();) { String source = ((Element) sources.next()).attributeValue("url"); if (source.equals(url)) { addToExclude = false; break; } else if (source.indexOf(url) == 0) { foundFolders.addAll( getExcludedDirectories(new File(absolutePath), excludeList, sourceFolders)); addToExclude = false; break; } } if (addToExclude) { excludedDirs++; foundFolders.add(absolutePath); } } } //if all directories are excluded, then just exclude the parent directory if (totalDirs > 0 && totalDirs == excludedDirs) { foundFolders.clear(); foundFolders.add(target.getAbsolutePath()); } } else if (!target.exists()) { //might as well exclude a non-existent dir so that it won't show when it suddenly appears foundFolders.add(target.getAbsolutePath()); } return foundFolders; } /** * Adds the Web module to the (.iml) project file. * * @param module Xpp3Dom element */ private void addWebModule(Element module) { // TODO: this is bad - reproducing war plugin defaults, etc! // --> this is where the OGNL out of a plugin would be helpful as we could run package first and // grab stuff from the mojo MavenProject executedProject = getExecutedProject(); String warWebapp = executedProject.getBuild().getDirectory() + "/" + executedProject.getArtifactId(); String warSrc = getPluginSetting("maven-war-plugin", "warSourceDirectory", "src/main/webapp"); String webXml = warSrc + "/WEB-INF/web.xml"; module.addAttribute("type", "J2EE_WEB_MODULE"); Element component = findComponent(module, "WebModuleBuildComponent"); Element setting = findSetting(component, "EXPLODED_URL"); setting.addAttribute("value", getModuleFileUrl(warWebapp)); component = findComponent(module, "WebModuleProperties"); removeOldElements(component, "containerElement"); List artifacts = executedProject.getTestArtifacts(); for (Iterator i = artifacts.iterator(); i.hasNext();) { Artifact artifact = (Artifact) i.next(); Element containerElement = createElement(component, "containerElement"); if (isLinkModules() && isReactorProject(artifact.getGroupId(), artifact.getArtifactId())) { containerElement.addAttribute("type", "module"); containerElement.addAttribute("name", getNameProvider().getProjectName(artifact)); Element methodAttribute = createElement(containerElement, "attribute"); methodAttribute.addAttribute("name", "method"); methodAttribute.addAttribute("value", "5"); Element uriAttribute = createElement(containerElement, "attribute"); uriAttribute.addAttribute("name", "URI"); // TODO: Find a way to get this info from the war plugin uriAttribute.addAttribute("value", "/WEB-INF/lib/" + artifact.getArtifactId() + "-" + artifact.getVersion() + ".jar"); } else if (artifact.getFile() != null) { containerElement.addAttribute("type", "library"); containerElement.addAttribute("level", "module"); Element methodAttribute = createElement(containerElement, "attribute"); methodAttribute.addAttribute("name", "method"); if (Artifact.SCOPE_PROVIDED.equalsIgnoreCase(artifact.getScope())) { methodAttribute.addAttribute("value", "0");// If scope is provided, do not package. } else { methodAttribute.addAttribute("value", "1");// IntelliJ 5.0.2 is bugged and doesn't read it } Element uriAttribute = createElement(containerElement, "attribute"); uriAttribute.addAttribute("name", "URI"); uriAttribute.addAttribute("value", "/WEB-INF/lib/" + artifact.getFile().getName()); Element url = createElement(containerElement, "url"); url.setText(getLibraryUrl(artifact)); } } addDeploymentDescriptor(component, "web.xml", "2.3", webXml); Element element = findElement(component, "webroots"); removeOldElements(element, "root"); element = createElement(element, "root"); element.addAttribute("relative", "/"); element.addAttribute("url", getModuleFileUrl(warSrc)); } private void addPluginModule(Element module) { module.addAttribute("type", "PLUGIN_MODULE"); // this is where the META-INF/plugin.xml file is located Element pluginDevElement = createElement(module, "component"); pluginDevElement.addAttribute("name", "DevKit.ModuleBuildProperties"); pluginDevElement.addAttribute("url", getModuleFileUrl("src/main/resources/META-INF/plugin.xml")); } /** * Translate the relative path of the file into module path * * @param basedir File to use as basedir * @param path Absolute path string to translate to ModuleFileUrl * @return moduleFileUrl Translated Module File URL */ private String getModuleFileUrl(File basedir, String path) { return "file://$MODULE_DIR$/" + toRelative(basedir, path); } private String getModuleFileUrl(String file) { return getModuleFileUrl(getExecutedProject().getBasedir(), file); } /** * Adds a sourceFolder element to IDEA (.iml) project file * * @param content Xpp3Dom element * @param directory Directory to set as url. * @param isTest True if directory isTestSource. */ private void addSourceFolder(Element content, String directory, boolean isTest) { if (!StringUtils.isEmpty(directory) && new File(directory).isDirectory()) { Element sourceFolder = createElement(content, "sourceFolder"); sourceFolder.addAttribute("url", getModuleFileUrl(directory)); sourceFolder.addAttribute("isTestSource", Boolean.toString(isTest)); } } private void addExcludeFolder(Element content, String directory) { Element excludeFolder = createElement(content, "excludeFolder"); excludeFolder.addAttribute("url", getModuleFileUrl(directory)); } private boolean isReactorProject(String groupId, String artifactId) { List reactorProjects = getReactorProjects(); if (reactorProjects != null) { for (Iterator j = reactorProjects.iterator(); j.hasNext();) { MavenProject p = (MavenProject) j.next(); if (p.getGroupId().equals(groupId) && p.getArtifactId().equals(artifactId)) { return true; } } } return false; } private void resolveClassifier(Element element, Artifact a, String classifier) { String id = a.getId() + '-' + classifier; String path = getAttemptDownloadMgr().getDownloadedPath(this, id, a, classifier); if (path != null) { String jarPath = "jar://" + path + "!/"; getLog().debug("Setting " + classifier + " for " + id + " to " + jarPath); removeOldElements(element, "root"); createElement(element, "root").addAttribute("url", jarPath); } } /** * Returns a an Xpp3Dom element (setting). * * @param component Xpp3Dom element * @param name Setting attribute to find * @return setting Xpp3Dom element */ private Element findSetting(Element component, String name) { return findElement(component, "setting", name); } private String getLibraryUrl(Artifact artifact) { return "jar://" + artifact.getFile().getAbsolutePath().replace('\\', '/') + "!/"; } private Element addDeploymentDescriptor(Element component, String name, String version, String file) { Element deploymentDescriptor = findElement(component, "deploymentDescriptor"); if (deploymentDescriptor.attributeValue("version") == null) { deploymentDescriptor.addAttribute("version", version); } if (deploymentDescriptor.attributeValue("name") == null) { deploymentDescriptor.addAttribute("name", name); } deploymentDescriptor.addAttribute("optional", "false"); if (deploymentDescriptorFile == null) { deploymentDescriptorFile = file; } deploymentDescriptor.addAttribute("url", getModuleFileUrl(deploymentDescriptorFile)); return deploymentDescriptor; } }