Put back the zip plugin from r798911

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@892208 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
antelder 2009-12-18 10:28:29 +00:00
parent 771fefc75f
commit 61cfc2c47b
13 changed files with 2338 additions and 0 deletions

View file

@ -0,0 +1,205 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View file

@ -0,0 +1,6 @@
${pom.name}
Copyright (c) 2005 - 2009 The Apache Software Foundation
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

View file

@ -0,0 +1,223 @@
User Documentation
__________________
This module is a Maven plugin which supports the creation of a zip format SCA contribution from
the contents of a Maven project. An SCA contribution can be deployed to the Tuscany SCA runtime
and run as an application.
One of the main uses for an SCA zip contribution is that the SCA zip contribution can contain
Java jar files within the zip and those jar files are available to the Java classloader of the
contribution. This enables the packaging of application Java classes along with any other Jar files
which they depend on in one contribution file. As a result the single zip file can hold everything
that's needed for the SCA application other than the Tuscany runtime itself - in one neat package.
The zip Maven plugin is used by adding a section into <build/> portion of the pom.xml of the Maven
project which relates to the maven zip plugin. It is also necessary for the packaging of the output
of the project to be declared as "zip". Then run Maven in the project.
This zip plugin builds the output of the project as an SCA zip archive and it includes any
jar files from dependencies declared by the project, where those dependency jar files are placed
into the zip archive in a folder with the name "lib".
An example pom.xml including the zip plugin statements:
...
<!-- output packaging format is "zip" -->
<packaging>zip</packaging>
...
<build>
...
<!-- section referencing the Tuscany zip plugin -->
<plugins>
...
<plugin>
<groupId>org.apache.tuscany.maven.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<extensions>true</extensions>
</plugin>
...
</plugins>
</build>
(It is probably a good idea to now give an example of a complete POM containing one this stuff so that
users get the full context - I've attached one here, but it isn't the best example)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>tuscany-sca</artifactId>
<groupId>org.apache.tuscany.sca</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<groupId>org.inglenook.test1</groupId>
<artifactId>mikestest</artifactId>
<packaging>zip</packaging>
<version>1.0-SNAPSHOT</version>
<name>quickstart</name>
<dependencies>
<!-- TUSCANY DEPENDENCIES -->
<dependency>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-sca-api</artifactId>
<version>${tuscany.version}</version>
<scope>provided</scope>
</dependency>
<!-- AN EXAMPLE APPLICATION DEPENDENCY TO BE INCLUDED IN ZIP -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<!-- JUNIT DEPENDENCY FOR TESTING -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<finalName>${artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<optimise>true</optimise>
<debug>true</debug>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tuscany.maven.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.apache.tuscany.maven.plugins</groupId>
<artifactId>maven-tuscany-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<tuscany.version>2.0-SNAPSHOT</tuscany.version>
</properties>
</project>
TODOs:
- make the "lib/" folder where the dependent jars go configurable
- make which dependencies get included configurable
(currently its those with compile or runtime scope)
---------------------------------
Building and releasing the plugin
---------------------------------
From the top maven-zip-plugin directory run maven:
mvn
or once all the dependencies have been downloaded and a succesful build run use:
mvn clean install -o
So as to avoid the Tuscany SCA project using SNAPSHOT dependencies any changes
to this maven-zip-plugin module should be released and the Tuscany SCA
project updated to use the newly released version.
To release this module:
mvn release:prepare
followed by:
mvn release:perform
That will automatically create an SVN tag from the release, update the version
numbers in the pom.xml files in the trunk and tag, and deploy the artifacts to the
staging repository defined by the <deploy.altRepository> in your Maven settings.xml.
While running it will prompt you for the names for the tag, release version etc.
In your maven settings.xml file you must have a server defined named "apache.releases",
and a profile named "release". For example:
<servers>
...
<server>
<id>apache.releases</id>
<username>antelder</username>
<privateKey>\ant\id_dsa</privateKey>
<passphrase>xxx</passphrase>
<directoryPermissions>775</directoryPermissions>
<filePermissions>664</filePermissions>
</server>
</servers>
<profiles>
...
<profile>
<id>release</id>
<properties>
<gpg.passphrase>...</gpg.passphrase>
<deploy.altRepository>apache.releases::default::scp://people.apache.org/home/antelder/public_html/tuscany/maven-zip-plugin-1.0</deploy.altRepository>
</properties>
</profile>
</profiles>
Call a vote to release the module, eg: http://apache.markmail.org/message/6jnlfxbx7uklt5nv
After a successfule vote copy the staging artifacts to the live repository, eg:
cp -p -v -R maven-zip-plugin-alpha1/org/apache/tuscany/maven/plugins/ /x1/www/people.apache.org/repo/m2-ibiblio-rsync-repository/org/apache/tuscany/maven/plugins
-----------------------------------------------------------------------------
This Tuscany module includes much code copied from the Maven WAR plugin 2.0.2
written by the Apache Maven team.
-----------------------------------------------------------------------------

View file

@ -0,0 +1,7 @@
Apache Tuscany Maven Zip Plugin Alpha1 Release Notes
====================================================
Initial release
Supports using a packaging of zip in a pom.xml to create a zip format SCA contribution

View file

@ -0,0 +1,261 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache</groupId>
<artifactId>apache</artifactId>
<version>4</version>
</parent>
<groupId>org.apache.tuscany.maven.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>Apache Tuscany Maven SCA ZIP Plugin</name>
<version>1.0-SNAPSHOT</version>
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/tuscany/maven-plugins/trunk/maven-sca-zip-plugin</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/tuscany/maven-plugins/trunk/maven-sca-zip-plugin</developerConnection>
<url>http://svn.apache.org/repos/asf/tuscany/</url>
</scm>
<distributionManagement>
<repository>
<id>apache.releases</id>
<name>Apache Release Distribution Repository</name>
<url>scp://people.apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository</url>
</repository>
<snapshotRepository>
<id>apache.snapshots</id>
<name>Apache Development Snapshot Repository</name>
<url>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
<uniqueVersion>false</uniqueVersion>
</snapshotRepository>
</distributionManagement>
<repositories>
<!-- Apache SNAPSHOT repository for unreleased artifacts -->
<repository>
<id>apache.snapshots</id>
<name>Apache SNAPSHOT Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<!-- Tuscany repository to hold artifacts that are not published in the public maven repos -->
<repository>
<id>tuscany.repo</id>
<name>Tuscany Maven 2.x Repository</name>
<url>http://svn.apache.org/repos/asf/tuscany/maven</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<!-- Apache repository for artifacts released by Apache TLP projects -->
<pluginRepository>
<id>apache</id>
<name>Apache Repository</name>
<url>http://people.apache.org/repo/m2-ibiblio-rsync-repository</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<!-- Apache SNAPSHOT repository for unreleased artifacts -->
<pluginRepository>
<id>apache.snapshots</id>
<name>Apache SNAPSHOT Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
<configuration>
<altDeploymentRepository>${deploy.altRepository}</altDeploymentRepository>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.0-alpha-4</version>
<executions>
<execution>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>deploy</id>
<build>
<defaultGoal>deploy</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.0.4</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-archiver</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>.</directory>
<targetPath>META-INF</targetPath>
<filtering>true</filtering>
<includes>
<include>LICENSE</include>
<include>NOTICE</include>
</includes>
</resource>
</resources>
<pluginManagement>
<plugins>
<!-- compiler plugin configuration -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- jar plugin configuration -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.1</version>
<configuration>
<archive>
<manifestEntries>
<Extension-Name>${project.artifactId}</Extension-Name>
<Specification-Title>${name}</Specification-Title>
<Specification-Vendor>The Apache Software Foundation</Specification-Vendor>
<Specification-Version>${version}</Specification-Version>
<Implementation-Title>${name}</Implementation-Title>
<Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
<Implementation-Vendor>The Apache Software Foundation</Implementation-Vendor>
<Implementation-Version>${version}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<tagBase>https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags</tagBase>
<useReleaseProfile>false</useReleaseProfile>
<preparationGoals>clean install</preparationGoals>
<goals>deploy</goals>
<arguments>-Prelease,deploy</arguments>
<autoVersionSubmodules>true</autoVersionSubmodules>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View file

@ -0,0 +1,896 @@
package org.apache.tuscany.maven.zip;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.archiver.MavenArchiveConfiguration;
import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.InterpolationFilterReader;
import org.codehaus.plexus.util.StringUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Based on code from the Maven WAR plugin 2.0.2 AbstractWarMojo
*/
public abstract class AbstractZipMojo
extends AbstractMojo
{
/**
* The maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* The directory containing generated classes.
*
* @parameter expression="${project.build.outputDirectory}"
* @required
* @readonly
*/
private File classesDirectory;
/**
* Whether a JAR file will be created for the classes in the webapp. Using this optional configuration
* parameter will make the generated classes to be archived into a jar file
* and the classes directory will then be excluded from the webapp.
*
* @parameter expression="${archiveClasses}" default-value="false"
*/
private boolean archiveClasses;
/**
* The Jar archiver needed for archiving classes directory into jar file.
*
* @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
* @required
*/
private JarArchiver jarArchiver;
/**
* The directory where the SCA ZIP contribution is built.
*
* @parameter expression="${project.build.directory}/${project.build.finalName}"
* @required
*/
private File zipDirectory;
/**
* Filters (property files) to include during the interpolation of the pom.xml.
*
* @parameter expression="${project.build.filters}"
*/
private List filters;
/**
* Directory to unpack dependent WARs into if needed
*
* @parameter expression="${project.build.directory}/war/work"
* @required
*/
private File workDirectory;
/**
* To look up Archiver/UnArchiver implementations
*
* @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
* @required
*/
protected ArchiverManager archiverManager;
private static final String META_INF = "META-INF";
private static final String[] DEFAULT_INCLUDES = {"**/**"};
/**
* The comma separated list of tokens to include in the SCA ZIP.
* Default is '**'.
*
* @parameter alias="includes"
*/
private String warSourceIncludes = "**";
/**
* The comma separated list of tokens to exclude from the WAR.
*
* @parameter alias="excludes"
*/
private String warSourceExcludes;
/**
* The comma separated list of tokens to include when doing
* a war overlay.
* Default is '**'
*
* @parameter
*/
private String dependentWarIncludes = "**";
/**
* The comma separated list of tokens to exclude when doing
* a war overlay.
*
* @parameter
*/
private String dependentWarExcludes;
/**
* The maven archive configuration to use.
*
* @parameter
*/
protected MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
private static final String[] EMPTY_STRING_ARRAY = {};
public MavenProject getProject()
{
return project;
}
public void setProject( MavenProject project )
{
this.project = project;
}
public File getClassesDirectory()
{
return classesDirectory;
}
public void setClassesDirectory( File classesDirectory )
{
this.classesDirectory = classesDirectory;
}
public File getZipDirectory()
{
return zipDirectory;
}
public void setScaZipDirectory( File scaZipDirectory )
{
this.zipDirectory = scaZipDirectory;
}
/**
* Returns a string array of the excludes to be used
* when assembling/copying the war.
*
* @return an array of tokens to exclude
*/
protected String[] getExcludes()
{
List excludeList = new ArrayList();
if ( StringUtils.isNotEmpty( warSourceExcludes ) )
{
excludeList.addAll( Arrays.asList( StringUtils.split( warSourceExcludes, "," ) ) );
}
return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
}
/**
* Returns a string array of the includes to be used
* when assembling/copying the war.
*
* @return an array of tokens to include
*/
protected String[] getIncludes()
{
return StringUtils.split( StringUtils.defaultString( warSourceIncludes ), "," );
}
/**
* Returns a string array of the excludes to be used
* when adding dependent wars as an overlay onto this war.
*
* @return an array of tokens to exclude
*/
protected String[] getDependentWarExcludes()
{
String[] excludes;
if ( StringUtils.isNotEmpty( dependentWarExcludes ) )
{
excludes = StringUtils.split( dependentWarExcludes, "," );
}
else
{
excludes = EMPTY_STRING_ARRAY;
}
return excludes;
}
/**
* Returns a string array of the includes to be used
* when adding dependent wars as an overlay onto this war.
*
* @return an array of tokens to include
*/
protected String[] getDependentWarIncludes()
{
return StringUtils.split( StringUtils.defaultString( dependentWarIncludes ), "," );
}
public void buildExplodedWebapp( File webappDirectory )
throws MojoExecutionException, MojoFailureException
{
getLog().info( "Exploding webapp..." );
webappDirectory.mkdirs();
try
{
buildWebapp( project, webappDirectory );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Could not explode webapp...", e );
}
}
private Map getBuildFilterProperties()
throws MojoExecutionException
{
Map filterProperties = new Properties();
// System properties
filterProperties.putAll( System.getProperties() );
// Project properties
filterProperties.putAll( project.getProperties() );
for ( Iterator i = filters.iterator(); i.hasNext(); )
{
String filtersfile = (String) i.next();
try
{
Properties properties = PropertyUtils.loadPropertyFile( new File( filtersfile ), true, true );
filterProperties.putAll( properties );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error loading property file '" + filtersfile + "'", e );
}
}
// can't putAll, as ReflectionProperties doesn't enumerate - so we make a composite map with the project variables as dominant
return new CompositeMap( new ReflectionProperties( project ), filterProperties );
}
/**
* Copies webapp webResources from the specified directory.
* <p/>
* Note that the <tt>webXml</tt> parameter could be null and may
* specify a file which is not named <tt>web.xml<tt>. If the file
* exists, it will be copied to the <tt>META-INF</tt> directory and
* renamed accordingly.
*
* @param resource the resource to copy
* @param webappDirectory the target directory
* @param filterProperties
* @throws java.io.IOException if an error occured while copying webResources
*/
public void copyResources( Resource resource, File webappDirectory, Map filterProperties )
throws IOException
{
if ( !resource.getDirectory().equals( webappDirectory.getPath() ) )
{
getLog().info( "Copy webapp webResources to " + webappDirectory.getAbsolutePath() );
if ( webappDirectory.exists() )
{
String[] fileNames = getWarFiles( resource );
String targetPath = (resource.getTargetPath() == null) ? "" : resource.getTargetPath();
File destination = new File(webappDirectory,targetPath);
for ( int i = 0; i < fileNames.length; i++ )
{
if ( resource.isFiltering() )
{
copyFilteredFile( new File( resource.getDirectory(), fileNames[i] ),
new File( destination, fileNames[i] ), null, getFilterWrappers(),
filterProperties );
}
else
{
copyFileIfModified( new File( resource.getDirectory(), fileNames[i] ),
new File( destination, fileNames[i] ) );
}
}
}
}
}
/**
* Generates the JAR.
*
* @todo Add license files in META-INF directory.
*/
public void createJarArchive( File libDirectory )
throws MojoExecutionException
{
String archiveName = project.getBuild().getFinalName() + ".jar";
File jarFile = new File( libDirectory, archiveName );
MavenArchiver archiver = new MavenArchiver();
archiver.setArchiver( jarArchiver );
archiver.setOutputFile( jarFile );
try
{
archiver.getArchiver().addDirectory( classesDirectory, getIncludes(), getExcludes() );
archiver.createArchive( project, archive );
}
catch ( Exception e )
{
// TODO: improve error handling
throw new MojoExecutionException( "Error assembling JAR", e );
}
}
/**
* Builds the webapp for the specified project.
* <p/>
* Classes, libraries and tld files are copied to
* the <tt>webappDirectory</tt> during this phase.
*
* @param project the maven project
* @param webappDirectory
* @throws java.io.IOException if an error occured while building the webapp
*/
public void buildWebapp( MavenProject project, File webappDirectory )
throws MojoExecutionException, IOException, MojoFailureException
{
getLog().info( "Assembling webapp " + project.getArtifactId() + " in " + webappDirectory );
File metainfDir = new File( webappDirectory, META_INF );
metainfDir.mkdirs();
File libDirectory = new File( webappDirectory, "/lib" );
File webappClassesDirectory = new File( webappDirectory, "/" );
if ( classesDirectory.exists() && !classesDirectory.equals( webappClassesDirectory ) )
{
if ( archiveClasses )
{
createJarArchive( libDirectory );
}
else
{
copyDirectoryStructureIfModified( classesDirectory, webappClassesDirectory );
}
}
Set artifacts = project.getArtifacts();
List duplicates = findDuplicates( artifacts );
List dependentWarDirectories = new ArrayList();
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
String targetFileName = getDefaultFinalName( artifact );
getLog().debug( "Processing: " + targetFileName );
if ( duplicates.contains( targetFileName ) )
{
getLog().debug( "Duplicate found: " + targetFileName );
targetFileName = artifact.getGroupId() + "-" + targetFileName;
getLog().debug( "Renamed to: " + targetFileName );
}
// TODO: utilise appropriate methods from project builder
ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
if ( !artifact.isOptional() && filter.include( artifact ) )
{
String type = artifact.getType();
if ( "jar".equals( type ) || "ejb".equals( type ) || "ejb-client".equals( type ) )
{
copyFileIfModified( artifact.getFile(), new File( libDirectory, targetFileName ) );
}
else
{
if ( "par".equals( type ) )
{
targetFileName = targetFileName.substring( 0, targetFileName.lastIndexOf( '.' ) ) + ".jar";
getLog().debug(
"Copying " + artifact.getFile() + " to " + new File( libDirectory, targetFileName ) );
copyFileIfModified( artifact.getFile(), new File( libDirectory, targetFileName ) );
}
else
{
if ( "war".equals( type ) )
{
dependentWarDirectories.add( unpackWarToTempDirectory( artifact ) );
}
else
{
getLog().debug( "Skipping artifact of type " + type + " for WEB-INF/lib" );
}
}
}
}
}
if ( dependentWarDirectories.size() > 0 )
{
getLog().info( "Overlaying " + dependentWarDirectories.size() + " war(s)." );
// overlay dependent wars
for ( Iterator iter = dependentWarDirectories.iterator(); iter.hasNext(); )
{
copyDependentWarContents( (File) iter.next(), webappDirectory );
}
}
}
/**
* Searches a set of artifacts for duplicate filenames and returns a list of duplicates.
*
* @param artifacts set of artifacts
* @return List of duplicated artifacts
*/
private List findDuplicates( Set artifacts )
{
List duplicates = new ArrayList();
List identifiers = new ArrayList();
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
String candidate = getDefaultFinalName( artifact );
if ( identifiers.contains( candidate ) )
{
duplicates.add( candidate );
}
else
{
identifiers.add( candidate );
}
}
return duplicates;
}
/**
* Unpacks war artifacts into a temporary directory inside <tt>workDirectory</tt>
* named with the name of the war.
*
* @param artifact War artifact to unpack.
* @return Directory containing the unpacked war.
* @throws MojoExecutionException
*/
private File unpackWarToTempDirectory( Artifact artifact )
throws MojoExecutionException
{
String name = artifact.getFile().getName();
File tempLocation = new File( workDirectory, name.substring( 0, name.length() - 4 ) );
boolean process = false;
if ( !tempLocation.exists() )
{
tempLocation.mkdirs();
process = true;
}
else if ( artifact.getFile().lastModified() > tempLocation.lastModified() )
{
process = true;
}
if ( process )
{
File file = artifact.getFile();
try
{
unpack( file, tempLocation );
}
catch ( NoSuchArchiverException e )
{
this.getLog().info( "Skip unpacking dependency file with unknown extension: " + file.getPath() );
}
}
return tempLocation;
}
/**
* 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, NoSuchArchiverException
{
String archiveExt = FileUtils.getExtension( file.getAbsolutePath() ).toLowerCase();
try
{
UnArchiver unArchiver = archiverManager.getUnArchiver( archiveExt );
unArchiver.setSourceFile( file );
unArchiver.setDestDirectory( location );
unArchiver.setOverwrite( true );
unArchiver.extract();
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error unpacking file: " + file + "to: " + location, e );
}
catch ( ArchiverException e )
{
throw new MojoExecutionException( "Error unpacking file: " + file + "to: " + location, e );
}
}
/**
* Recursively copies contents of <tt>srcDir</tt> into <tt>targetDir</tt>.
* This will not overwrite any existing files.
*
* @param srcDir Directory containing unpacked dependent war contents
* @param targetDir Directory to overlay srcDir into
*/
private void copyDependentWarContents( File srcDir, File targetDir )
throws MojoExecutionException
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( srcDir );
scanner.setExcludes( getDependentWarExcludes() );
scanner.addDefaultExcludes();
scanner.setIncludes( getDependentWarIncludes() );
scanner.scan();
String[] dirs = scanner.getIncludedDirectories();
for ( int j = 0; j < dirs.length; j++ )
{
new File( targetDir, dirs[j] ).mkdirs();
}
String[] files = scanner.getIncludedFiles();
for ( int j = 0; j < files.length; j++ )
{
File targetFile = new File( targetDir, files[j] );
try
{
targetFile.getParentFile().mkdirs();
copyFileIfModified( new File( srcDir, files[j] ), targetFile );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error copying file '" + files[j] + "' to '" + targetFile + "'", e );
}
}
}
/**
* Returns a list of filenames that should be copied
* over to the destination directory.
*
* @param sourceDir the directory to be scanned
* @return the array of filenames, relative to the sourceDir
*/
private String[] getWarFiles( File sourceDir )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( sourceDir );
scanner.setExcludes( getExcludes() );
scanner.addDefaultExcludes();
scanner.setIncludes( getIncludes() );
scanner.scan();
return scanner.getIncludedFiles();
}
/**
* Returns a list of filenames that should be copied
* over to the destination directory.
*
* @param resource the resource to be scanned
* @return the array of filenames, relative to the sourceDir
*/
private String[] getWarFiles( Resource resource )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( resource.getDirectory() );
if ( resource.getIncludes() != null && !resource.getIncludes().isEmpty() )
{
scanner.setIncludes( (String[]) resource.getIncludes().toArray( EMPTY_STRING_ARRAY ) );
}
else
{
scanner.setIncludes( DEFAULT_INCLUDES );
}
if ( resource.getExcludes() != null && !resource.getExcludes().isEmpty() )
{
scanner.setExcludes( (String[]) resource.getExcludes().toArray( EMPTY_STRING_ARRAY ) );
}
scanner.addDefaultExcludes();
scanner.scan();
return scanner.getIncludedFiles();
}
/**
* Copy file from source to destination only if source is newer than the target file.
* If <code>destinationDirectory</code> does not exist, it
* (and any parent directories) will be created. If a file <code>source</code> in
* <code>destinationDirectory</code> exists, it will be overwritten.
*
* @param source An existing <code>File</code> to copy.
* @param destinationDirectory A directory to copy <code>source</code> into.
* @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
* @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
* @throws java.io.IOException if <code>source</code> does not exist, the file in
* <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
* <p/>
* TO DO: Remove this method when Maven moves to plexus-utils version 1.4
*/
private static void copyFileToDirectoryIfModified( File source, File destinationDirectory )
throws IOException
{
// TO DO: Remove this method and use the method in WarFileUtils when Maven 2 changes
// to plexus-utils 1.2.
if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() )
{
throw new IllegalArgumentException( "Destination is not a directory" );
}
copyFileIfModified( source, new File( destinationDirectory, source.getName() ) );
}
private FilterWrapper[] getFilterWrappers()
{
return new FilterWrapper[]{
// support ${token}
new FilterWrapper()
{
public Reader getReader( Reader fileReader, Map filterProperties )
{
return new InterpolationFilterReader( fileReader, filterProperties, "${", "}" );
}
},
// support @token@
new FilterWrapper()
{
public Reader getReader( Reader fileReader, Map filterProperties )
{
return new InterpolationFilterReader( fileReader, filterProperties, "@", "@" );
}
}};
}
/**
* @param from
* @param to
* @param encoding
* @param wrappers
* @param filterProperties
* @throws IOException TO DO: Remove this method when Maven moves to plexus-utils version 1.4
*/
private static void copyFilteredFile( File from, File to, String encoding, FilterWrapper[] wrappers,
Map filterProperties )
throws IOException
{
// buffer so it isn't reading a byte at a time!
Reader fileReader = null;
Writer fileWriter = null;
try
{
// fix for MWAR-36, ensures that the parent dir are created first
to.getParentFile().mkdirs();
if ( encoding == null || encoding.length() < 1 )
{
fileReader = new BufferedReader( new FileReader( from ) );
fileWriter = new FileWriter( to );
}
else
{
FileInputStream instream = new FileInputStream( from );
FileOutputStream outstream = new FileOutputStream( to );
fileReader = new BufferedReader( new InputStreamReader( instream, encoding ) );
fileWriter = new OutputStreamWriter( outstream, encoding );
}
Reader reader = fileReader;
for ( int i = 0; i < wrappers.length; i++ )
{
FilterWrapper wrapper = wrappers[i];
reader = wrapper.getReader( reader, filterProperties );
}
IOUtil.copy( reader, fileWriter );
}
finally
{
IOUtil.close( fileReader );
IOUtil.close( fileWriter );
}
}
/**
* Copy file from source to destination only if source timestamp is later than the destination timestamp.
* The directories up to <code>destination</code> will be created if they don't already exist.
* <code>destination</code> will be overwritten if it already exists.
*
* @param source An existing non-directory <code>File</code> to copy bytes from.
* @param destination A non-directory <code>File</code> to write bytes to (possibly
* overwriting).
* @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
* written to, or an IO error occurs during copying.
* @throws java.io.FileNotFoundException if <code>destination</code> is a directory
* <p/>
* TO DO: Remove this method when Maven moves to plexus-utils version 1.4
*/
private static void copyFileIfModified( File source, File destination )
throws IOException
{
// TO DO: Remove this method and use the method in WarFileUtils when Maven 2 changes
// to plexus-utils 1.2.
if ( destination.lastModified() < source.lastModified() )
{
FileUtils.copyFile( source.getCanonicalFile(), destination );
// preserve timestamp
destination.setLastModified( source.lastModified() );
}
}
/**
* Copies a entire directory structure but only source files with timestamp later than the destinations'.
* <p/>
* Note:
* <ul>
* <li>It will include empty directories.
* <li>The <code>sourceDirectory</code> must exists.
* </ul>
*
* @param sourceDirectory
* @param destinationDirectory
* @throws IOException TO DO: Remove this method when Maven moves to plexus-utils version 1.4
*/
private static void copyDirectoryStructureIfModified( File sourceDirectory, File destinationDirectory )
throws IOException
{
if ( !sourceDirectory.exists() )
{
throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." );
}
File[] files = sourceDirectory.listFiles();
String sourcePath = sourceDirectory.getAbsolutePath();
for ( int i = 0; i < files.length; i++ )
{
File file = files[i];
String dest = file.getAbsolutePath();
dest = dest.substring( sourcePath.length() + 1 );
File destination = new File( destinationDirectory, dest );
if ( file.isFile() )
{
destination = destination.getParentFile();
copyFileToDirectoryIfModified( file, destination );
}
else if ( file.isDirectory() )
{
if ( !destination.exists() && !destination.mkdirs() )
{
throw new IOException(
"Could not create destination directory '" + destination.getAbsolutePath() + "'." );
}
copyDirectoryStructureIfModified( file, destination );
}
else
{
throw new IOException( "Unknown file type: " + file.getAbsolutePath() );
}
}
}
/**
* TO DO: Remove this interface when Maven moves to plexus-utils version 1.4
*/
private interface FilterWrapper
{
Reader getReader( Reader fileReader, Map filterProperties );
}
/**
* Converts the filename of an artifact to artifactId-version.type format.
*
* @param artifact
* @return converted filename of the artifact
*/
private String getDefaultFinalName( Artifact artifact )
{
String finalName = artifact.getArtifactId() + "-" + artifact.getVersion();
String classifier = artifact.getClassifier();
if ( ( classifier != null ) && ! ( "".equals( classifier.trim() ) ) )
{
finalName += "-" + classifier;
}
finalName = finalName + "." + artifact.getArtifactHandler().getExtension();
return finalName;
}
}

View file

@ -0,0 +1,61 @@
package org.apache.tuscany.maven.zip;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 java.util.AbstractMap;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* @version $Id: CompositeMap.java 480784 2006-11-30 00:07:45Z jvanzyl $
* @todo merge with resources/assembly plugin
*/
public class CompositeMap
extends AbstractMap
{
private Map recessive;
private Map dominant;
public CompositeMap( Map dominant, Map recessive )
{
this.dominant = Collections.unmodifiableMap( dominant );
this.recessive = Collections.unmodifiableMap( recessive );
}
public synchronized Object get( Object key )
{
Object value = dominant.get( key );
if ( value == null )
{
value = recessive.get( key );
}
return value;
}
public Set entrySet()
{
throw new UnsupportedOperationException( "Cannot enumerate properties in a composite map" );
}
}

View file

@ -0,0 +1,150 @@
package org.apache.tuscany.maven.zip;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.codehaus.plexus.util.IOUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
/**
* @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a>
* @version $Id: PropertyUtils.java 480784 2006-11-30 00:07:45Z jvanzyl $
* @todo this is duplicated from the resources plugin - migrate to plexus-utils
*/
public final class PropertyUtils
{
private PropertyUtils()
{
// prevent instantiation
}
/**
* Reads a property file, resolving all internal variables.
*
* @param propfile The property file to load
* @param fail wheter to throw an exception when the file cannot be loaded or to return null
* @param useSystemProps wheter to incorporate System.getProperties settings into the returned Properties object.
* @return the loaded and fully resolved Properties object
*/
public static Properties loadPropertyFile( File propfile, boolean fail, boolean useSystemProps )
throws IOException
{
Properties props = new Properties();
if ( useSystemProps )
{
props = new Properties( System.getProperties() );
}
if ( propfile.exists() )
{
FileInputStream inStream = new FileInputStream( propfile );
try
{
props.load( inStream );
}
finally
{
IOUtil.close( inStream );
}
}
else if ( fail )
{
throw new FileNotFoundException( propfile.toString() );
}
for ( Enumeration n = props.propertyNames(); n.hasMoreElements(); )
{
String k = (String) n.nextElement();
props.setProperty( k, PropertyUtils.getPropertyValue( k, props ) );
}
return props;
}
/**
* Retrieves a property value, replacing values like ${token}
* using the Properties to look them up.
* <p/>
* It will leave unresolved properties alone, trying for System
* properties, and implements reparsing (in the case that
* the value of a property contains a key), and will
* not loop endlessly on a pair like
* test = ${test}.
*/
private static String getPropertyValue( String k, Properties p )
{
// This can also be done using InterpolationFilterReader,
// but it requires reparsing the file over and over until
// it doesn't change.
String v = p.getProperty( k );
String ret = "";
int idx, idx2;
while ( ( idx = v.indexOf( "${" ) ) >= 0 )
{
// append prefix to result
ret += v.substring( 0, idx );
// strip prefix from original
v = v.substring( idx + 2 );
// if no matching } then bail
if ( ( idx2 = v.indexOf( '}' ) ) < 0 )
{
break;
}
// strip out the key and resolve it
// resolve the key/value for the ${statement}
String nk = v.substring( 0, idx2 );
v = v.substring( idx2 + 1 );
String nv = p.getProperty( nk );
// try global environment..
if ( nv == null )
{
nv = System.getProperty( nk );
}
// if the key cannot be resolved,
// leave it alone ( and don't parse again )
// else prefix the original string with the
// resolved property ( so it can be parsed further )
// taking recursion into account.
if ( nv == null || nv.equals( k ) )
{
ret += "${" + nk + "}";
}
else
{
v = nv + v;
}
}
return ret + v;
}
}

View file

@ -0,0 +1,60 @@
package org.apache.tuscany.maven.zip;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.project.MavenProject;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
import java.util.AbstractMap;
import java.util.Set;
/**
* @version $Id: ReflectionProperties.java 480784 2006-11-30 00:07:45Z jvanzyl $
* @todo merge with resources/assembly plugin
*/
public class ReflectionProperties
extends AbstractMap
{
private MavenProject project;
public ReflectionProperties( MavenProject project )
{
this.project = project;
}
public synchronized Object get( Object key )
{
Object value = null;
try
{
value = ReflectionValueExtractor.evaluate( String.valueOf( key ), project );
}
catch ( Exception e )
{
//TODO: remove the try-catch block when ReflectionValueExtractor.evaluate() throws no more exceptions
}
return value;
}
public Set entrySet()
{
throw new UnsupportedOperationException( "Cannot enumerate properties in a project" );
}
}

View file

@ -0,0 +1,192 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.tuscany.maven.zip;
import org.codehaus.plexus.archiver.ArchiveEntry;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.zip.ZipOutputStream;
import java.io.File;
import java.io.IOException;
/**
* An extension of &lt;jar&gt; to create a WAR archive.
* Contains special treatment for files that should end up in the
* <code>WEB-INF/lib</code>, <code>WEB-INF/classes</code> or
* <code>WEB-INF</code> directories of the Web Application Archive.</p>
* <p>(The War task is a shortcut for specifying the particular layout of a WAR file.
* The same thing can be accomplished by using the <i>prefix</i> and <i>fullpath</i>
* attributes of zipfilesets in a Zip or Jar task.)</p>
* <p>The extended zipfileset element from the zip task
* (with attributes <i>prefix</i>, <i>fullpath</i>, and <i>src</i>)
* is available in the War task.</p>
*
* @see JarArchiver
*/
public class ZipArchiver
extends JarArchiver
{
/**
* our web.xml deployment descriptor
*/
private File deploymentDescriptor;
/**
* flag set if finding the webxml is to be expected.
*/
private boolean ignoreWebxml = true;
/**
* flag set if the descriptor is added
*/
private boolean descriptorAdded;
public void setIgnoreWebxml( boolean ignore ) {
ignoreWebxml = ignore;
}
public ZipArchiver()
{
super();
archiveType = "scazip";
}
/**
* set the deployment descriptor to use (WEB-INF/web.xml);
* required unless <tt>update=true</tt>
*/
public void setWebxml( File descr )
throws ArchiverException
{
deploymentDescriptor = descr;
if ( !deploymentDescriptor.exists() )
{
throw new ArchiverException( "Deployment descriptor: "
+ deploymentDescriptor
+ " does not exist." );
}
addFile( descr, "WEB-INF/web.xml" );
}
/**
* add a file under WEB-INF/lib/
*/
public void addLib( File fileName )
throws ArchiverException
{
addDirectory( fileName.getParentFile(), "WEB-INF/lib/", new String[]{fileName.getName()}, null );
}
/**
* add files under WEB-INF/lib/
*/
public void addLibs( File directoryName, String[] includes, String[] excludes )
throws ArchiverException
{
addDirectory( directoryName, "WEB-INF/lib/", includes, excludes );
}
/**
* add a file under WEB-INF/lib/
*/
public void addClass( File fileName )
throws ArchiverException
{
addDirectory( fileName.getParentFile(), "WEB-INF/classes/", new String[]{fileName.getName()}, null );
}
/**
* add files under WEB-INF/classes
*/
public void addClasses( File directoryName, String[] includes, String[] excludes )
throws ArchiverException
{
addDirectory( directoryName, "WEB-INF/classes/", includes, excludes );
}
/**
* files to add under WEB-INF;
*/
public void addWebinf( File directoryName, String[] includes, String[] excludes )
throws ArchiverException
{
addDirectory( directoryName, "WEB-INF/", includes, excludes );
}
/**
* override of parent; validates configuration
* before initializing the output stream.
*/
protected void initZipOutputStream( ZipOutputStream zOut )
throws IOException, ArchiverException
{
super.initZipOutputStream( zOut );
}
/**
* Overridden from ZipArchiver class to deal with web.xml
*/
protected void zipFile( ArchiveEntry entry, ZipOutputStream zOut, String vPath, int mode )
throws IOException, ArchiverException
{
// If the file being added is WEB-INF/web.xml, we warn if it's
// not the one specified in the "webxml" attribute - or if
// it's being added twice, meaning the same file is specified
// by the "webxml" attribute and in a <fileset> element.
if ( vPath.equalsIgnoreCase( "WEB-INF/web.xml" ) )
{
if ( descriptorAdded || ( ignoreWebxml
&& ( deploymentDescriptor == null
|| !deploymentDescriptor.getCanonicalPath().equals( entry.getFile().getCanonicalPath() ) ) ) )
{
getLogger().warn( "Warning: selected " + archiveType
+ " files include a WEB-INF/web.xml which will be ignored "
+ "\n(webxml attribute is missing from "
+ archiveType + " task, or ignoreWebxml attribute is specified as 'true')" );
}
else
{
super.zipFile( entry, zOut, vPath );
descriptorAdded = true;
}
}
else
{
super.zipFile( entry, zOut, vPath );
}
}
/**
* Make sure we don't think we already have a web.xml next time this task
* gets executed.
*/
protected void cleanUp()
{
descriptorAdded = false;
ignoreWebxml = true;
super.cleanUp();
}
}

View file

@ -0,0 +1,41 @@
package org.apache.tuscany.maven.zip;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
/**
* Generate the exploded SCA ZIP contribution
*
* @goal exploded
* @phase package
* @requiresDependencyResolution runtime
*/
public class ZipExplodedMojo
extends AbstractZipMojo
{
public void execute()
throws MojoExecutionException, MojoFailureException
{
buildExplodedWebapp( getZipDirectory() );
}
}

View file

@ -0,0 +1,195 @@
package org.apache.tuscany.maven.zip;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 java.io.File;
import java.io.IOException;
import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.jar.ManifestException;
/**
* Build an SCA ZIP contribution.
*
* Based on code from the Maven WAR plugin 2.0.2 by Emmanuel Venisse
*
* @goal zip
* @phase package
* @requiresDependencyResolution runtime
*/
public class ZipMojo
extends AbstractZipMojo
{
/**
* The directory for the generated contribution.
*
* @parameter expression="${project.build.directory}"
* @required
*/
private String outputDirectory;
/**
* The name of the generated contribution.
*
* @parameter expression="${project.build.finalName}"
* @required
*/
private String contributionName;
/**
* Classifier to add to the artifact generated. If given, the artifact will be an attachment instead.
*
* @parameter
*/
private String classifier;
/**
* The Jar archiver.
*
*/
private ZipArchiver Archiver = new ZipArchiver();
/**
* @component
*/
private MavenProjectHelper projectHelper;
/**
* Whether this is the main artifact being built. Set to <code>false</code> if you don't want to install or
* deploy it to the local repository instead of the default one in an execution.
*
* @parameter expression="${primaryArtifact}" default-value="true"
*/
private boolean primaryArtifact;
// ----------------------------------------------------------------------
// Implementation
// ----------------------------------------------------------------------
/**
* Overload this to produce a test-war, for example.
*/
protected String getClassifier()
{
return classifier;
}
protected static File getFile( File basedir, String finalName, String classifier )
{
if ( classifier == null )
{
classifier = "";
}
else if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" ) )
{
classifier = "-" + classifier;
}
return new File( basedir, finalName + classifier + ".zip" );
}
/**
* Executes the Mojo on the current project.
*
* @throws MojoExecutionException if an error occured while building the SCA ZIP contribution
*/
public void execute()
throws MojoExecutionException, MojoFailureException
{
File File = getFile( new File( outputDirectory ), contributionName, classifier );
try
{
performPackaging( File );
}
catch ( DependencyResolutionRequiredException e )
{
throw new MojoExecutionException( "Error assembling SCA ZIP: " + e.getMessage(), e );
}
catch ( ManifestException e )
{
throw new MojoExecutionException( "Error assembling SCA ZIP", e );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error assembling SCA ZIP", e );
}
catch ( ArchiverException e )
{
throw new MojoExecutionException( "Error assembling SCA ZIP: " + e.getMessage(), e );
}
}
/**
* Generates the SCA ZIP contribution according to the <tt>mode</tt> attribute.
*
* @param File the target war file
* @throws IOException
* @throws ArchiverException
* @throws ManifestException
* @throws DependencyResolutionRequiredException
*
*/
private void performPackaging( File File )
throws IOException, ArchiverException, ManifestException, DependencyResolutionRequiredException,
MojoExecutionException, MojoFailureException
{
buildExplodedWebapp( getZipDirectory() );
//generate war file
getLog().info( "Generating SCA ZIP contribution " + File.getAbsolutePath() );
MavenArchiver archiver = new MavenArchiver();
archiver.setArchiver( Archiver );
archiver.setOutputFile( File );
Archiver.addDirectory( getZipDirectory(), getIncludes(), getExcludes() );
// create archive
archiver.createArchive( getProject(), archive );
String classifier = this.classifier;
if ( classifier != null )
{
projectHelper.attachArtifact( getProject(), "", classifier, File );
}
else
{
Artifact artifact = getProject().getArtifact();
if ( primaryArtifact )
{
artifact.setFile( File );
}
else if ( artifact.getFile() == null || artifact.getFile().isDirectory() )
{
artifact.setFile( File );
}
}
}
}

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
-->
<component-set>
<components>
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>zip</role-hint>
<implementation>
org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping
</implementation>
<configuration>
<phases>
<process-resources>
org.apache.maven.plugins:maven-resources-plugin:resources
</process-resources>
<compile>
org.apache.maven.plugins:maven-compiler-plugin:compile
</compile>
<package>org.apache.tuscany.maven.plugins:maven-zip-plugin:zip</package>
</phases>
</configuration>
</component>
</components>
</component-set>