Java tutorial
/** * License Agreement. * * Rich Faces - Natural Ajax for Java Server Faces (JSF) * * Copyright (C) 2007 Exadel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.ajax4jsf.builder.mojo; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; 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 org.ajax4jsf.builder.config.ParsingException; import org.ajax4jsf.builder.xml.NamesListComparator; import org.ajax4jsf.builder.xml.XMLBody; import org.ajax4jsf.builder.xml.XMLBodyMerge; import org.ajax4jsf.builder.xml.XPathComparator; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; import org.apache.maven.model.Resource; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectBuilder; import org.apache.maven.project.MavenProjectHelper; import org.apache.maven.project.ProjectBuildingException; import org.apache.velocity.VelocityContext; import org.codehaus.plexus.archiver.UnArchiver; import org.codehaus.plexus.archiver.manager.ArchiverManager; import org.codehaus.plexus.util.DirectoryScanner; import org.w3c.dom.Node; /** * This plugin assembly full components library from modules, included in parent * project. Steps to create library : 1. Got parent project, and check modules * included in them. 2. For every module , build project and got it properties. * 3. Resolve module artifact, check for "jar" type and include/exclude * criteria. for accepted modules, unpack it to classes directory, and put * config files in separate directories. 4. Append unpacked directory to * resources, included in result jar. 5. Merge all META-INF/faces-config.xml , * *.tld, *.taglib.xml , resources-config.xml into ones. 6. append dependencies * of included projects to this. * * @author shura * @goal attached * @phase package * @aggregator */ public class AssemblyAttachedLibraryMojo extends AbstractCDKMojo { private static final String TEMPLATES_PREFIX = "/templates/"; private static final String TEMPLATES12_PREFIX = "/templates12/"; private static final String FACES_CONFIG_TEMPLATE = "faces-config.vm"; private static final String RESOURCES_CONFIG_TEMPLATE = "resources-config.vm"; private static final String TLD_TEMPLATE = "tld.vm"; private static final String TAGLIB_TEMPLATE = "taglib.vm"; private static final String[] TLD_TAG_NAMES = new String[] { "description", "display-name", "icon", "tlib-version", "short-name", "uri", "validator", "listener", "tag", "tag-file", "function", "taglib-extension" }; private static final String[] TAGLIB_TAG_NAMES = new String[] { "library-class", "namespace", "tag", "function" }; /** * Used to look up Artifacts in the remote repository. * * @component */ private org.apache.maven.artifact.factory.ArtifactFactory factory; /** * Used to look up Artifacts in the remote repository. * * @component */ private org.apache.maven.artifact.resolver.ArtifactResolver resolver; /** * The local repository. * * @parameter expression="${localRepository}" */ private ArtifactRepository localRepository; /** * To look up Archiver/UnArchiver implementations * * @component */ private ArchiverManager archiverManager; /** * Project builder * * @component */ private MavenProjectBuilder mavenProjectBuilder; /** * Maven ProjectHelper * * @component */ private MavenProjectHelper projectHelper; /** * The reactor projects. * * @parameter expression="${reactorProjects}" * @required * @readonly */ private List reactorProjects; /** * The reactor projects. * * @parameter expression="${project.parent}" * @readonly */ private MavenProject parentProject; /** * The directory for compiled classes. * * @parameter expression="${project.build.directory}" * @required * @readonly */ private File buildDirectory; /** * The directory for compiled classes. * * @parameter expression="${project.build.directory}/pom.xml" * @required * @readonly */ private File generatedPom; /** * The directory for compiled classes. * * @parameter expression="${project.build.directory}/src" * @required * @readonly */ private File modulesSrc; /** * @parameter */ private String templates; /** * @parameter */ private String includeTld = "META-INF/*.tld"; /** * @parameter */ private String includeTaglib = "META-INF/*.taglib.xml"; /** * @parameter */ private Taglib[] taglibs; /** * */ public AssemblyAttachedLibraryMojo() { // used for plexus init. } /* * (non-Javadoc) * * @see org.apache.maven.plugin.Mojo#execute() */ public void execute() throws MojoExecutionException, MojoFailureException { if (null != reactorProjects) { getLog().info("Reactor projects"); for (Iterator iterator = reactorProjects.iterator(); iterator.hasNext();) { MavenProject reactor = (MavenProject) iterator.next(); getLog().info("Project " + reactor.getGroupId() + ":" + reactor.getArtifactId()); } } // assemblyProjects(); } /** * @throws MojoFailureException * @throws MojoExecutionException */ protected void assemblyProjects() throws MojoFailureException, MojoExecutionException { // Parent project not set for a custom lifecycles. Try to load artifact. if (null == parentProject || null == parentProject.getFile()) { Parent parentModel = project.getModel().getParent(); if (null != parentModel) { String relativePath = parentModel.getRelativePath(); File parentPom = new File(project.getFile().getAbsoluteFile().getParentFile(), relativePath); if (parentPom.isDirectory()) { parentPom = new File(parentPom, "pom.xml"); } if (parentPom.exists()) { try { parentProject = mavenProjectBuilder.build(parentPom, localRepository, null); } catch (ProjectBuildingException e) { throw new MojoFailureException("Error get parent project for a components library"); } } else { throw new MojoFailureException("Parent project pom file not found for a components library"); } } else { throw new MojoFailureException( "Components library project must have parent pom with components modules"); } } if (null != parentProject) { this.checkLibraryConfig(); if (null == templates) { templates = Library.JSF12.equals(library.getJsfVersion()) ? TEMPLATES12_PREFIX : TEMPLATES_PREFIX; } Model generatedProject; try { MavenXpp3Reader reader = new MavenXpp3Reader(); generatedProject = reader.read(new FileReader(project.getFile())); } catch (Exception e1) { throw new MojoExecutionException("Unable to read local POM", e1); } List modules = parentProject.getModules(); List models = new ArrayList(modules.size()); Map<String, Dependency> projectsDependencies = new HashMap<String, Dependency>(); for (Iterator iter = modules.iterator(); iter.hasNext();) { String moduleName = (String) iter.next(); getLog().info("Parent project have module " + moduleName); Model model; File f = new File(parentProject.getBasedir(), moduleName + "/pom.xml"); if (f.exists()) { try { model = mavenProjectBuilder.build(f, localRepository, null).getModel(); } catch (ProjectBuildingException e) { throw new MojoExecutionException("Unable to read local module-POM", e); } } else { getLog().warn("No filesystem module-POM available"); model = new Model(); model.setName(moduleName); model.setUrl(moduleName); } if (project.getGroupId().equals(model.getGroupId()) && "jar".equals(model.getPackaging()) && (!project.getArtifactId().equals(model.getArtifactId()))) { // TODO - check include/exclude getLog().debug("Project " + model.getName() + " included to library set"); List dependencies = model.getDependencies(); for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) { Dependency dependency = (Dependency) iterator.next(); getLog().debug(dependency.getClass().getName() + " : " + dependency + " with key: " + dependency.getManagementKey()); if (!"test".equals(dependency.getScope())) { projectsDependencies.put(dependency.getManagementKey(), dependency); } } models.add(model); } } // Remove modules projects from dependencise Set<String> unwanted = new HashSet<String>(projectsDependencies.size()); for (Iterator iter = models.iterator(); iter.hasNext();) { Model model = (Model) iter.next(); for (Iterator iterator = projectsDependencies.values().iterator(); iterator.hasNext();) { Dependency dependency = (Dependency) iterator.next(); if (model.getGroupId().equals(dependency.getGroupId()) && model.getArtifactId().equals(dependency.getArtifactId())) { getLog().debug("Remove dependency of library module " + dependency.getManagementKey()); unwanted.add(dependency.getManagementKey()); } } // Got module and unpack it to target directory. Artifact artifact = factory.createBuildArtifact(model.getGroupId(), model.getArtifactId(), model.getVersion(), model.getPackaging()); File moduleDir = new File(buildDirectory, model.getArtifactId()); unpackArtifact(artifact, moduleDir, true); artifact = factory.createArtifactWithClassifier(model.getGroupId(), model.getArtifactId(), model.getVersion(), "jar", "sources"); unpackArtifact(artifact, modulesSrc, false); } // Add projects dependencies to this project projectsDependencies.keySet().removeAll(unwanted); generatedProject.getDependencies().addAll(projectsDependencies.values()); writePom(generatedProject); mergeFacesConfig(models); File resourcesConfig = new File(outputDirectory, "META-INF/resources-config.xml"); mergeXML(models, "META-INF/resources-config.xml", RESOURCES_CONFIG_TEMPLATE, "/resource-config/resource", "name/text()", new VelocityContext(), resourcesConfig, null); File tld = new File(outputDirectory, "META-INF/" + library.getTaglib().getShortName() + ".tld"); mergeXML(models, includeTld, TLD_TEMPLATE, "/taglib/tag | /taglib/listener", null, new VelocityContext(), tld, new NamesListComparator( new XPathComparator("name/text()", "listener-class/text()"), TLD_TAG_NAMES)); File taglib = new File(outputDirectory, "META-INF/" + library.getTaglib().getShortName() + ".taglib.xml"); mergeXML(models, includeTaglib, TAGLIB_TEMPLATE, "/facelet-taglib/tag | /facelet-taglib/function", null, new VelocityContext(), taglib, new NamesListComparator( new XPathComparator("tag-name/text()", "function-name/text()"), TAGLIB_TAG_NAMES)); } else { throw new MojoFailureException( "Components library project must have parent pom with components modules"); } } /** * @param models * @throws MojoExecutionException */ private void mergeFacesConfig(List models) throws MojoExecutionException { StringBuffer config = new StringBuffer(); for (int i = 0; i < library.getRenderkits().length; i++) { Renderkit kit = library.getRenderkits()[i]; kit.setContent(new StringBuffer()); } for (Iterator iter = models.iterator(); iter.hasNext();) { Model model = (Model) iter.next(); File moduleFacesConfig = new File(buildDirectory, model.getArtifactId() + "/META-INF/faces-config.xml"); if (moduleFacesConfig.exists()) { getLog().info("Process faces-config.xml for module " + model.getArtifactId()); XMLBody configBody = new XMLBody(); try { configBody.loadXML(new FileInputStream(moduleFacesConfig)); config.append(configBody.getContent("/faces-config/*[name()!=\'render-kit\']")); for (int i = 0; i < library.getRenderkits().length; i++) { Renderkit kit = library.getRenderkits()[i]; kit.getContent().append(configBody.getContent( "/faces-config/render-kit[child::render-kit-id='" + kit.getName() + "']/renderer")); } } catch (FileNotFoundException e) { throw new MojoExecutionException("Could't read faces-config file", e); } catch (ParsingException e) { throw new MojoExecutionException("Error parsing faces-config file", e); } } } VelocityContext context = new VelocityContext(); context.put("content", config.toString()); context.put("library", library); context.put("renderkits", Arrays.asList(library.getRenderkits())); try { writeParsedTemplate(templates + FACES_CONFIG_TEMPLATE, context, new File(outputDirectory, "META-INF/faces-config.xml")); } catch (Exception e) { throw new MojoExecutionException("Error to process faces-config template", e); } } /** * Merge XML files from extracted models to one in build directory. * * @param models * models collected in library. * @param filename * relative path to config file in models/output. * @param templateName - * name of velocity template for result file. * @param commonXpath - * XPath expression fof common part of result file. * @param keyXPath - XPath expression for key part of common parts * @param keySet - {@link Set} to check for duplicate keys. Must not be null * @param context - * Velocity context for template processing. * @throws MojoExecutionException */ private void mergeXML(List<Model> models, String filename, String templateName, String commonXpath, String keyXPath, VelocityContext context, File target, Comparator<Node> comparator) throws MojoExecutionException { StringBuilder content = new StringBuilder(); XMLBodyMerge bodyMerge = new XMLBodyMerge(commonXpath, keyXPath); List<XMLBody> xmls = new ArrayList<XMLBody>(models.size()); String[] split = filename.split(","); for (Iterator<Model> iter = models.iterator(); iter.hasNext();) { Model model = iter.next(); File moduleDir = new File(buildDirectory, model.getArtifactId()); DirectoryScanner ds = new DirectoryScanner(); ds.setFollowSymlinks(true); ds.setBasedir(moduleDir); ds.setIncludes(split); ds.addDefaultExcludes(); ds.scan(); String[] files = ds.getIncludedFiles(); for (int i = 0; i < files.length; i++) { File moduleFacesConfig = new File(moduleDir, files[i]); getLog().info("Process " + files[i] + " for module " + model.getArtifactId()); XMLBody configBody = new XMLBody(); try { configBody.loadXML(new FileInputStream(moduleFacesConfig)); xmls.add(configBody); bodyMerge.add(configBody); } catch (FileNotFoundException e) { throw new MojoExecutionException("Could't read file " + moduleFacesConfig.getPath(), e); } catch (ParsingException e) { throw new MojoExecutionException("Error parsing config file " + moduleFacesConfig.getPath(), e); } } } if (comparator != null) { bodyMerge.sort(comparator); } try { content.append(bodyMerge.getContent()); } catch (Exception e) { // TODO: handle exception } if (xmls.size() > 0) { context.put("content", content); context.put("library", library); context.put("models", models); context.put("xmls", xmls); try { writeParsedTemplate(templates + templateName, context, target); } catch (Exception e) { throw new MojoExecutionException( "Error to process template " + templateName + " for files " + filename, e); } } } private void unpackArtifact(Artifact artifact, File moduleDir, boolean isResource) throws MojoExecutionException { try { resolver.resolve(artifact, Collections.EMPTY_LIST, localRepository); unpack(artifact.getFile(), moduleDir); if (isResource) { Resource resource = new Resource(); resource.setDirectory(moduleDir.getPath()); resource.addExclude("META-INF/faces-config.xml"); resource.addExclude("META-INF/resources-config.xml"); resource.addExclude("META-INF/*.taglib.xml"); resource.addExclude("META-INF/*.tld"); project.addResource(resource); } } catch (ArtifactResolutionException e) { getLog().error("Error with resolve artifact " + artifact, e); } catch (ArtifactNotFoundException e) { getLog().error("Not found artifact " + artifact, e); } } private List<MavenProject> populateReactorProjects() { List<MavenProject> projects = new ArrayList<MavenProject>(); if (reactorProjects != null && reactorProjects.size() > 1) { Iterator reactorItr = reactorProjects.iterator(); while (reactorItr.hasNext()) { MavenProject reactorProject = (MavenProject) reactorItr.next(); if (reactorProject != null && reactorProject.getParent() != null && project.getArtifactId().equals(reactorProject.getParent().getArtifactId())) { String name = reactorProject.getGroupId() + ":" + reactorProject.getArtifactId(); getLog().info("Have reactor project with name " + name); projects.add(reactorProject); } } } return projects; } /** * Unpacks the archive file. * * @param file * File to be unpacked. * @param location * Location where to put the unpacked files. */ private void unpack(File file, File location) throws MojoExecutionException { getLog().debug("Unpack file " + file.getAbsolutePath() + " to: " + location.getAbsolutePath()); try { location.mkdirs(); UnArchiver unArchiver; unArchiver = archiverManager.getUnArchiver(file); unArchiver.setSourceFile(file); unArchiver.setDestDirectory(location); unArchiver.setOverwrite(true); unArchiver.extract(); } catch (Exception e) { throw new MojoExecutionException( "Error unpacking file: " + file + " to: " + location + "\r\n" + e.toString(), e); } } private void writePom(Model pom) throws MojoExecutionException { MavenXpp3Writer pomWriter = new MavenXpp3Writer(); try { FileWriter out = new FileWriter(generatedPom); pomWriter.write(out, pom); } catch (IOException e) { throw new MojoExecutionException("Error for write generated pom", e); } } /** * @return the archiverManager */ public ArchiverManager getArchiverManager() { return this.archiverManager; } /** * @param archiverManager * the archiverManager to set */ public void setArchiverManager(ArchiverManager archiverManager) { this.archiverManager = archiverManager; } /** * @return the buildDirectory */ public File getBuildDirectory() { return this.buildDirectory; } /** * @param buildDirectory * the buildDirectory to set */ public void setBuildDirectory(File buildDirectory) { this.buildDirectory = buildDirectory; } /** * @return the factory */ public org.apache.maven.artifact.factory.ArtifactFactory getFactory() { return this.factory; } /** * @param factory * the factory to set */ public void setFactory(org.apache.maven.artifact.factory.ArtifactFactory factory) { this.factory = factory; } /** * @return the localRepository */ public ArtifactRepository getLocalRepository() { return this.localRepository; } /** * @param localRepository * the localRepository to set */ public void setLocalRepository(ArtifactRepository localRepository) { this.localRepository = localRepository; } /** * @return the mavenProjectBuilder */ public MavenProjectBuilder getMavenProjectBuilder() { return this.mavenProjectBuilder; } /** * @param mavenProjectBuilder * the mavenProjectBuilder to set */ public void setMavenProjectBuilder(MavenProjectBuilder mavenProjectBuilder) { this.mavenProjectBuilder = mavenProjectBuilder; } /** * @return the parentProject */ public MavenProject getParentProject() { return this.parentProject; } /** * @param parentProject * the parentProject to set */ public void setParentProject(MavenProject parentProject) { this.parentProject = parentProject; } /** * @return the reactorProjects */ public List getReactorProjects() { return this.reactorProjects; } /** * @param reactorProjects * the reactorProjects to set */ public void setReactorProjects(List reactorProjects) { this.reactorProjects = reactorProjects; } /** * @return the resolver */ public org.apache.maven.artifact.resolver.ArtifactResolver getResolver() { return this.resolver; } /** * @param resolver * the resolver to set */ public void setResolver(org.apache.maven.artifact.resolver.ArtifactResolver resolver) { this.resolver = resolver; } }