/** * Copyright 2011 meltmedia * * 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. */ package org.xchain.tools.monitoring; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.model.Resource; import java.io.InputStream; import java.io.IOException; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.jar.JarFile; import java.util.jar.JarEntry; import org.xml.sax.Attributes; import org.apache.commons.digester.Digester; import org.apache.commons.digester.Rule; import org.apache.commons.digester.WithDefaultsRulesWrapper; import org.xml.sax.SAXException; import org.codehaus.plexus.util.xml.XMLWriter; import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; /** * @goal monitoring-info * @phase generate-resources * @requiresProject * @requiresDependencyResolution runtime * @author Christian Trimble */ public class MonitoringMojo extends AbstractMojo { /** * Location of the file. * @parameter expression="${project.build.directory}" * @required */ private File outputDirectory; /** * The monitor flag. If true, then the monitoring information will be generated. * @parameter expression="${build.monitor}" default-value="false" */ private boolean monitor; /** * The packaging type. * @parameter expression="${project.packaging}" * @required */ private String packaging; /** * The maven project for this artifact. * @parameter expression="${project}" * @required */ private MavenProject project; /** * The set of war dependencies that will be included in this project. * @parameter */ private Resource[] webResources; public void execute() throws MojoExecutionException { getLog().info("Executing the monitoring information plugin."); if( monitor ) { getLog().info("Building monitoring information."); if( !"jar".equals(packaging) && !"war".equals(packaging) ) { throw new MojoExecutionException("Mojo information can only be created for projects packaged as 'jar' or 'war'."); } MonitoringInfo monitoringInfo = new MonitoringInfo(); // find all of the directories to get resources from. If they are filtered, then ignore them. List<Resource> resourceSet = (List<Resource>)project.getResources(); for( Resource resource : resourceSet ) { monitoringInfo.getResourceList().add(copy(resource)); } // if this is a war, then we need to merge all of the monitoring-info.xml files into this file. if( "war".equals(packaging) ) { if( webResources != null ) { for( Resource resource : webResources ) { monitoringInfo.getWarResourceList().add(copy(resource)); } // get all of the directories that hold resources, both static and generated. Set<Artifact> artifactSet = (Set<Artifact>)project.getArtifacts(); for( Artifact artifact : artifactSet ) { // if this file is a jar, then try to load its monitoring-info.xml file and add it to this class. if( "war".equals(artifact.getType()) ) { mergeWarMonitoringInfo(monitoringInfo, artifact.getFile()); } } } } File metaInfDir = new File( project.getBuild().getOutputDirectory(), "META-INF"); metaInfDir.mkdirs(); getLog().info("Creating '"+metaInfDir.toString()+"'."); File monitoringFile = new File(metaInfDir, "monitoring-info.xml"); PrintWriter writer = null; XMLWriter xmlWriter = null; // write the artifact out. try { writer = new PrintWriter(monitoringFile, "UTF-8"); xmlWriter = new PrettyPrintXMLWriter(writer, " "); xmlWriter.startElement("monitoring-info"); // write the resource tags. for( Resource resource : monitoringInfo.getResourceList() ) { xmlWriter.startElement("resource"); writeResource(xmlWriter, resource); xmlWriter.endElement(); } for( Resource warResource : monitoringInfo.getWarResourceList() ) { xmlWriter.startElement("web-resource"); writeResource(xmlWriter, warResource); xmlWriter.endElement(); } xmlWriter.endElement(); writer.flush(); } catch( IOException ioe ) { throw new MojoExecutionException("Could not write out META-INF/monitoring-info.xml file.", ioe); } finally { if( writer != null ) { try { writer.close(); } catch( Exception ioe ) { getLog().warn("Could not close writer for META-INF/monitoring-info.xml file.", ioe); } } } } } private void writeResource( XMLWriter xmlWriter, Resource resource ) { xmlWriter.startElement("directory"); xmlWriter.writeText(resource.getDirectory()); xmlWriter.endElement(); xmlWriter.startElement("filtering"); xmlWriter.writeText(""+resource.isFiltering()); xmlWriter.endElement(); if( resource.getIncludes().size() > 0 ) { xmlWriter.startElement("includes"); for( String include : ((List<String>)resource.getIncludes()) ) { xmlWriter.startElement("include"); xmlWriter.writeText(include); xmlWriter.endElement(); } xmlWriter.endElement(); } if( resource.getExcludes().size() > 0 ) { xmlWriter.startElement("excludes"); for( String exclude : ((List<String>)resource.getExcludes()) ) { xmlWriter.startElement("exclude"); xmlWriter.writeText(exclude); xmlWriter.endElement(); } xmlWriter.endElement(); } } private class LoggingRule extends Rule { public void begin( String namespace, String name, Attributes attributes) throws Exception { getLog().warn("Unknown monitoring-info element encountered {"+namespace+"}"+name+"."); } } private void mergeWarMonitoringInfo( MonitoringInfo monitoringInfo, File file ) throws MojoExecutionException { JarFile artifactJar = null; JarEntry monitoringInfoEntry = null; InputStream in = null; try { getLog().info("Getting monitoring info from file "+file.toString()); artifactJar = new JarFile(file); monitoringInfoEntry = artifactJar.getJarEntry("WEB-INF/classes/META-INF/monitoring-info.xml"); if( monitoringInfoEntry != null ) { in = artifactJar.getInputStream( monitoringInfoEntry ); // digest the xml file and get all of the entries. Digester digester = new Digester(); digester.push(monitoringInfo); digester.addRuleSet(new MonitoringInfoRuleSet()); WithDefaultsRulesWrapper wrapper = new WithDefaultsRulesWrapper(digester.getRules()); wrapper.addDefault(new LoggingRule()); digester.setRules(wrapper); digester.parse(in); } else { getLog().info("Monitoring info file not found in "+file.toString()); } } catch( SAXException se ) { throw new MojoExecutionException("Could not parse a monitoring-info.xml file.", se); } catch( IOException ioe ) { throw new MojoExecutionException("Could not open jar file.", ioe); } finally { if( in != null ) { try { in.close(); } catch( IOException ioe ) { getLog().warn("Could not close a jar entry input stream.", ioe); } } try { artifactJar.close(); } catch( IOException ioe ) { getLog().warn("Could not close a jar.", ioe ); } } } private Resource copy( Resource resource ) { Resource copy = new Resource(); copy.setDirectory(resource.getDirectory()); copy.setTargetPath(resource.getTargetPath()); copy.setFiltering(resource.isFiltering()); copy.setModelEncoding(resource.getModelEncoding()); copy.setIncludes(copy(resource.getIncludes())); copy.setExcludes(copy(resource.getExcludes())); return copy; } private List copy( List list ) { List copy = new ArrayList(); if( list != null ) { copy.addAll(list); } return copy; } }