package org.codehaus.mojo.jarjar;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.Plugin;
import org.apache.maven.plugin.PluginExecutionRequest;
import org.apache.maven.plugin.PluginExecutionResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/* ====================================================================
* Copyright 2001-2004 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.
* ====================================================================
*/
/**
* @goal java
*
* @phase process-classes
*
* @description Bundles dependencies into compiled classes and renames packages.
*
* @parameter name="outputDirectory"
* type="String"
* required="true"
* validator=""
* expression="#project.build.outputDirectory"
* description=""
*
* @parameter name="classpathIncludes"
* type="String"
* required="false"
* validator=""
* expression="#classpathIncludes"
* description="The comma-delimited list of included classpath elements in the format groupId:artifactId"
*
* @parameter name="classpathExcludes"
* type="String"
* required="false"
* validator=""
* expression="#classpathExcludes"
* description="The comma-delimited list of excluded classpath elements in the format groupId:artifactId"
*
* @parameter name="classpathElements"
* type="java.util.List"
* required="true"
* validator=""
* expression="#project.runtimeClasspathElements"
* description="The project's runtime classpath elements."
*
* @parameter
* name="rules"
* type="java.lang.String"
* required="false"
* validator=""
* expression="#rules"
* description="The comma-delimited rule mapping where format is 'searchPattern=replacePattern"
*
* @parameter
* name="zaps"
* type="java.lang.String"
* required="false"
* validator=""
* expression="#zaps"
* description="Comma-delimited list of zap patterns."
*
* @parameter
* name="kills"
* type="java.lang.String"
* required="false"
* validator=""
* expression="#kills"
* description="Comma-delimited list of kill patterns. Not sure what this is for currently."
*
* @parameter
* name="ruleFile"
* type="java.lang.String"
* required="false"
* validator=""
* expression="#basedir/#ruleFile"
* description="File path (relative to project basedir) that contains all
* rules, zaps, and kills to be used"
*
* @author jdcasey
* @version $Id$
*/
public class JarJarMojo
implements Plugin
{
public void execute( PluginExecutionRequest request, PluginExecutionResponse response ) throws Exception
{
String outputDirectory = (String)request.getParameter("outputDirectory");
List classpathElements = (List)request.getParameter("classpathElements");
String classpathIncludes = (String)request.getParameter("classpathIncludes");
List cpIncludeList = null;
if(classpathIncludes != null)
{
cpIncludeList = parseCommaDelimitedList(classpathIncludes);
}
else
{
cpIncludeList = Collections.EMPTY_LIST;
}
String classpathExcludes = (String)request.getParameter("classpathExcludes");
List cpExcludeList = null;
if(classpathExcludes != null)
{
cpExcludeList = parseCommaDelimitedList(classpathExcludes);
}
else
{
cpExcludeList = Collections.EMPTY_LIST;
}
createJarJarStructs(outputDirectory, classpathElements, cpIncludeList, cpExcludeList);
String rulePath = (String)request.getParameter("ruleFile");
if(rulePath != null)
{
File ruleFile = new File(rulePath);
}
else
{
String rules = (String)request.getParameter("rules");
Map ruleMap = null;
if(rules != null)
{
ruleMap = parseCommaDelimitedMap(rules);
}
else
{
ruleMap = Collections.EMPTY_MAP;
}
String zaps = (String)request.getParameter("zaps");
List zapList = null;
if(zaps != null)
{
zapList = parseCommaDelimitedList(zaps);
}
else
{
zapList = Collections.EMPTY_LIST;
}
String kills = (String)request.getParameter("kills");
List killList = null;
if(kills != null)
{
killList = parseCommaDelimitedList(kills);
}
else
{
killList = Collections.EMPTY_LIST;
}
}
}
private List createJarJarStructs( String outputDirectory, List classpathElements, List includes, List excludes )
throws IOException
{
List toExtract = new ArrayList();
for ( Iterator it = classpathElements.iterator(); it.hasNext(); )
{
Artifact cpArtifact = (Artifact) it.next();
String id = cpArtifact.getGroupId() + ":" + cpArtifact.getArtifactId();
// How do we compute classpath entries to include?
// 1. If entry is in includes, ADD
// 2. If includes are empty, and entry is not in excludes, ADD.
// 3. If both includes and excludes are empty, ADD.
if(includes.contains(id))
{
toExtract.add(cpArtifact);
}
else if(includes.isEmpty() && (excludes.isEmpty() || !excludes.contains(id)))
{
toExtract.add(cpArtifact);
}
}
List structs = new ArrayList();
for ( Iterator it = toExtract.iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
JarFile jarFile = new JarFile(artifact.getFile());
for(Enumeration entries = jarFile.entries(); entries.hasMoreElements(); )
{
JarEntry entry = (JarEntry)entries.nextElement();
File outFile = new File(outputDirectory, entry.getName());
outFile.mkdirs();
}
}
return structs;
}
private List parseCommaDelimitedList(String input)
{
StringTokenizer tokenizer = new StringTokenizer(",");
List result = new ArrayList();
while(tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if(token != null)
{
token = token.trim();
}
result.add(token);
}
return result;
}
private Map parseCommaDelimitedMap(String input)
{
StringTokenizer tokenizer = new StringTokenizer(",");
Map result = new TreeMap();
while(tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if(token != null)
{
token = token.trim();
}
Pattern mappingPattern = Pattern.compile("([^=]+)=(.+)");
Matcher matcher = mappingPattern.matcher(token);
if(matcher.matches())
{
String key = matcher.group(1);
String value = matcher.group(2);
result.put(key, value);
}
}
return result;
}
}