added maven-alfresco-lifecycle 1.0.0 super pom using maven calm, refactored repositories urls and dependencies

git-svn-id: http://maven-alfresco-archetypes.googlecode.com/svn/trunk@209 04253f4f-3451-0410-a141-5562f1e59037
This commit is contained in:
mindthegab
2009-11-05 22:00:36 +00:00
parent ac80da2ebf
commit f0e85330eb
42 changed files with 5412 additions and 523 deletions

View File

@@ -18,11 +18,9 @@
-->
<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>
<groupId>com.sourcesense.alfresco</groupId>
<artifactId>maven-alfresco-amp-archetype</artifactId>
<packaging>maven-archetype</packaging>
<name>Maven Alfresco Amp Archetype</name>
<version>1.0.5-SNAPSHOT</version>
<description>
This archetype aims to provide a standardized approach to development, release and deployment of Alfresco AMPs (as opposed to Alfresco
extensions, released as a different artifact ). Using standard m2 lifecycle commands (mvn compile package deploy) and generally available
@@ -30,18 +28,11 @@
minutes to have a compatible AMP module built and its lifecycle supported by Maven, in a fully transparent way also with open source available
AMPs.
</description>
<properties>
<svn.url>${svn.base.url}/trunk/maven-alfresco-archetypes/${artifactId}</svn.url>
<site.url>https://repository.sourcesense.com/maven2-sites/maven-alfresco-archetypes/${pom.artifactId}</site.url>
</properties>
<scm>
<developerConnection>scm:svn:https://maven-alfresco-archetypes.googlecode.com/svn/trunk/maven-alfresco-archetypes/maven-alfresco-amp-archetype</developerConnection>
<url>https://maven-alfresco-archetypes.googlecode.com/svn/trunk/maven-alfresco-archetypes/maven-alfresco-amp-archetype</url>
</scm>
<url>${project.artifactId}</url>
<parent>
<groupId>com.sourcesense.alfresco</groupId>
<artifactId>maven-alfresco-archetypes</artifactId>
<version>1.0.5-SNAPSHOT</version>
<version>1.9.0-SNAPSHOT</version>
</parent>
<build>
<extensions>
@@ -51,29 +42,5 @@
<version>2.0-alpha-3</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-7</version>
<configuration>
<!-- useEditMode>true</useEditMode>-->
<!-- dryRun>true</dryRun-->
<preparationGoals>clean package</preparationGoals>
<goals>deploy site:site site:deploy</goals>
<tagBase>${svn.tags.url}</tagBase>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2</url>
</repository>
<site>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2-sites/${pom.artifactId}</url>
</site>
</distributionManagement>
</project>

View File

@@ -23,7 +23,7 @@ module.id=${pom.groupId}.${pom.artifactId}
#module.aliases=myModule-123, my-module
module.title=${pom.name}
module.description=${pom.description}
module.version=${buildNumber}
module.version=${noSnapshotVersion}.${buildNumber}
# The following optional properties can be used to prevent the module from being added
# to inappropriate versions of the WAR file.

View File

@@ -1,83 +1,97 @@
<?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">
<!--
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>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<packaging>amp</packaging>
<name>Maven Alfresco AMP Packaging Sample</name>
<!-- An Alfresco version number must be of the form 1.2.3.4. Using 1.0-SNAPSHOT as the AMP version
will create an exception. See http://wiki.alfresco.com/wiki/Developing_an_Alfresco_Module:
"The version number must be made up of numeric values separated by dots. For example '2.1.56' is a valid version number, '2.3.4a' is not. "
In order to be able to use Maven snapshots we cannot use the <version/> below as the AMP module
version. Instead we use the buildnumber-maven-plugin. This requires a scm connection.
-->
<!--
An Alfresco version number must be of the form 1.2.3.4. Using
1.0-SNAPSHOT as the AMP version will create an exception. See
http://wiki.alfresco.com/wiki/Developing_an_Alfresco_Module: "The
version number must be made up of numeric values separated by dots.
For example '2.1.56' is a valid version number, '2.3.4a' is not. " In
order to be able to use Maven snapshots we cannot use the <version/>
below as the AMP module version. Instead we use the
buildnumber-maven-plugin. This requires a scm connection.
-->
<version>${version}</version>
<description>Test AMP project</description>
<repositories>
<repository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/maven2</url>
<id>ss-public-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public</url>
</repository>
<repository>
<id>ss-public-snapshots-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public-snapshots</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/maven2</url>
<url>http://repository.sourcesense.com/nexus/content/groups/public</url>
</pluginRepository>
<pluginRepository>
<id>ss-public-snapshots-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public-snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<properties>
<!--Default for which src/main/properties/<env>/application.properties is loaded. NB:
used only for the 'test' profile (e.g. '-P test' on the mvn commandline)
jetty run deployment, does not impact AMP behavior which is typically environment independent
<!--
Default for which src/main/properties/<env>/application.properties is
loaded. NB: used only for the 'test' profile (e.g. '-P test' on the
mvn commandline) jetty run deployment, does not impact AMP behavior
which is typically environment independent
-->
<env>local</env>
<!-- Webapp used to test/develop locally the AMP -->
<webapp.name>${artifactId}-webapp</webapp.name>
<!--
|
| By default the src/test/properties/local/application.properties uses the property "alfresco.data.location" to specify where
| alf_data gets created.
| For local jetty:run deployment default creation dir is under project root folder (as location is specified relatively to run
| dir). Please add alf_data_jetty in svn/cvs ignores in order not to commit that. You can also specified a different (out of the
| sproject) folder
| by editing the following properties.
| DB is also configurable here. Of course keep in sync these two values otherwise you'll get integrity errors.
|
| Empty log dir creates file alfresco.log in appserver default dir. You can also specify a meaningful log directory for the server
| (add a trailing slash, e.g. '/var/log/alfresco/' )
|
| Jetty embedded run logs by default in target/alfresco.log
<!--
| | By default the src/test/properties/local/application.properties
uses the property "alfresco.data.location" to specify where |
alf_data gets created. | For local jetty:run deployment default
creation dir is under project root folder (as location is specified
relatively to run | dir). Please add alf_data_jetty in svn/cvs
ignores in order not to commit that. You can also specified a
different (out of the | sproject) folder | by editing the following
properties. | DB is also configurable here. Of course keep in sync
these two values otherwise you'll get integrity errors. | | Empty log
dir creates file alfresco.log in appserver default dir. You can also
specify a meaningful log directory for the server | (add a trailing
slash, e.g. '/var/log/alfresco/' ) | | Jetty embedded run logs by
default in target/alfresco.log
-->
<alfresco.data.location>./alf_data_jetty</alfresco.data.location>
<alfresco.db.name>alf_jetty</alfresco.db.name>
<alfresco.db.username>alfresco</alfresco.db.username>
<alfresco.db.password>alfresco</alfresco.db.password>
<alfresco.db.password>alfresco</alfresco.db.password>
<webapp.log.level>error</webapp.log.level>
<webapp.log.dir></webapp.log.dir>
<!-- End of testing webapp specific properties -->
<!-- Module specific build time properties -->
<module.log.level>debug</module.log.level>
</properties>
<!--
<!--
need to list these as a provided so that Maven doesn't download them
and include them in the AMP, they are provided by Alfresco
-->
@@ -95,24 +109,24 @@
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!-- Example Jar dependency: will be properly packed into the AMP /lib directory
<dependency>
<groupId>rome</groupId>
<artifactId>opensearch</artifactId>
<version>0.1</version>
</dependency>
<!--
Example Jar dependency: will be properly packed into the AMP /lib
directory <dependency> <groupId>rome</groupId>
<artifactId>opensearch</artifactId> <version>0.1</version>
</dependency>
-->
<!-- Example AMP dependency: will be properly overlayed in the WAR produced by the integration-test phase in profile 'webapp'
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>recordsmanagement</artifactId>
<version>2.1.0</version>
<type>amp</type>
</dependency>
<!--
Example AMP dependency: will be properly overlayed in the WAR
produced by the integration-test phase in profile 'webapp'
<dependency> <groupId>org.alfresco</groupId>
<artifactId>recordsmanagement</artifactId> <version>2.1.0</version>
<type>amp</type> </dependency>
-->
<!--
By default archetype assumes mysql for test webapp. Change
src/test/properties/<env>/application.properties FIXME: support in
memory db for cleaner and safer test runs
-->
<!-- By default archetype assumes mysql for test webapp. Change src/test/properties/<env>/application.properties
FIXME: support in memory db for cleaner and safer test runs
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@@ -120,32 +134,48 @@
</dependency>
<!-- Don't add here amp dependencies as it will break amp packaging -->
</dependencies>
<!-- The scm is required for the buildnumber-maven-plugin which is required for AMP version numbering -->
<!--
The scm is required for the buildnumber-maven-plugin which is required
for AMP version numbering
-->
<scm>
<connection>scm:svn:http://domain.com/svn/trunk/</connection>
<developerConnection>scm:svn:https://${maven.username}@domain.com/svn/trunk/</developerConnection>
<url>http://domain.com/svn/trunk/</url>
<connection>scm:svn:http://domain.com/svn/trunk/</connection>
<developerConnection>scm:svn:https://${maven.username}@domain.com/svn/trunk/</developerConnection>
<url>http://domain.com/svn/trunk/</url>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<revisionOnScmFailure>1</revisionOnScmFailure>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<artifactId>maven-nosnapshot-plugin</artifactId>
<groupId>com.sourcesense.maven</groupId>
<version>0.0.5-SNAPSHOT</version>
<executions>
<execution>
<id>default</id>
<phase>initialize</phase>
<goals>
<goal>strip</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<revisionOnScmFailure>1</revisionOnScmFailure>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
@@ -156,29 +186,31 @@
<plugin>
<groupId>org.alfresco.maven.plugin</groupId>
<artifactId>maven-amp-plugin</artifactId>
<version>2.0.0</version>
<version>3.0.1-SNAPSHOT</version>
<extensions>true</extensions>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<overlays>
<!-- This sample adds records management module in the finally built AMP
<overlay>
<groupId>org.org.alfresco</groupId>
<!--
This sample adds records management module in the finally built
AMP <overlay> <groupId>org.org.alfresco</groupId>
<artifactId>recordsmanagement</artifactId>
<version>2.1.0</version>
<type>amp</type>
</overlay>
<version>2.1.0</version> <type>amp</type> </overlay>
-->
<!-- The current AMP is always last in order to overwrite other modules' modules.properties
<overlay></overlay>
<!--
The current AMP is always last in order to overwrite other
modules' modules.properties <overlay></overlay>
-->
</overlays>
</configuration>
</plugin>
</plugins>
<!-- Copies and filters resources in build folder so maven-amp-plugin can pick them up -->
<!--
Copies and filters resources in build folder so maven-amp-plugin can
pick them up
-->
<resources>
<resource>
<filtering>true</filtering>
@@ -187,8 +219,11 @@
<exclude>**README-*</exclude>
</excludes>
</resource>
<!-- Copies and filters AMP config in the proper package 'alfresco/module/${groupId}.${artifactId}' so to enforce
full module naming single sourcing from POM properties -->
<!--
Copies and filters AMP config in the proper package
'alfresco/module/${groupId}.${artifactId}' so to enforce full module
naming single sourcing from POM properties
-->
<resource>
<filtering>true</filtering>
<directory>src/main/config</directory>
@@ -200,11 +235,16 @@
</resources>
</build>
<profiles>
<!-- Profile used to trigger war creation and integration within Jetty embedded -->
<!--
Profile used to trigger war creation and integration within Jetty
embedded
-->
<profile>
<id>webapp</id>
<build>
<filters><filter>src/test/properties/${env}/application.properties</filter></filters>
<filters>
<filter>src/test/properties/${env}/application.properties</filter>
</filters>
<defaultGoal>jetty:run-exploded</defaultGoal>
<plugins>
<plugin>
@@ -225,8 +265,11 @@
</execution>
</executions>
<dependencies>
<!-- This is required to be re-defined explicitly at plugin level as otherwise the 'amp' extension
unArchiver won't be available to the maven-dependency-plugin -->
<!--
This is required to be re-defined explicitly at plugin level as
otherwise the 'amp' extension unArchiver won't be available to
the maven-dependency-plugin
-->
<dependency>
<groupId>org.alfresco.maven.plugin</groupId>
<artifactId>maven-amp-plugin</artifactId>
@@ -252,7 +295,10 @@
</executions>
<configuration>
<primaryArtifact>false</primaryArtifact>
<!-- Don't remove the following line otherwise WAR and AMP builds will be done in the same folder, with unexpected results -->
<!--
Don't remove the following line otherwise WAR and AMP builds
will be done in the same folder, with unexpected results
-->
<webappDirectory>${build.directory}/${webapp.name}</webappDirectory>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
@@ -280,12 +326,15 @@
</webResources>
</configuration>
<dependencies>
<!-- This is required to be re-defined explicitly at plugin level as otherwise the 'amp' extension
unArchiver won't be available to the maven-war-plugin -->
<!--
This is required to be re-defined explicitly at plugin level as
otherwise the 'amp' extension unArchiver won't be available to
the maven-war-plugin
-->
<dependency>
<groupId>org.alfresco.maven.plugin</groupId>
<artifactId>maven-amp-plugin</artifactId>
<version>2.0.0</version>
<version>3.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
@@ -315,8 +364,11 @@
</executions>
</plugin>
</plugins>
<!-- When invoking 'mvn integration-test', the following alf configs are added to the test war in order to be able to run it seamlessly.
NB: the application.properties file is filtered with alfresco.db.name and alf.data.location POM properties as default configuration
<!--
When invoking 'mvn integration-test', the following alf configs are
added to the test war in order to be able to run it seamlessly. NB:
the application.properties file is filtered with alfresco.db.name
and alf.data.location POM properties as default configuration
-->
<testResources>
<testResource>
@@ -329,9 +381,11 @@
<directory>src/test/properties/${env}</directory>
<targetPath>alfresco/extension</targetPath>
</testResource>
<!-- src/main/config/ is copied into ==> target/test-classes/alfresco/module/${groupId}.${artifactId} to
be picked up by the maven-war plugin
Best practice tacken from recordsmanagement.amp, is enforced troughout the whole archetype.
<!--
src/main/config/ is copied into ==>
target/test-classes/alfresco/module/${groupId}.${artifactId} to be
picked up by the maven-war plugin Best practice tacken from
recordsmanagement.amp, is enforced troughout the whole archetype.
This convention is also used for module.properties filtering.
-->
<testResource>
@@ -344,13 +398,17 @@
</testResource>
</testResources>
</build>
<!-- Here you can add test dependencies you want to have included in the the WAR (not in the AMP, built in the main profile)
|
| Typical use case: add here additional AMPs that you want to test compatibility of with the current module
|
<!--
Here you can add test dependencies you want to have included in the
the WAR (not in the AMP, built in the main profile) | | Typical use
case: add here additional AMPs that you want to test compatibility
of with the current module |
-->
<dependencies>
<!-- This is the alfresco version you're testing the AMP against. Don't remove if you want jetty to be able to deploy a WAR :) -->
<!--
This is the alfresco version you're testing the AMP against. Don't
remove if you want jetty to be able to deploy a WAR :)
-->
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco</artifactId>

View File

@@ -18,16 +18,14 @@
-->
<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>
<groupId>com.sourcesense.alfresco</groupId>
<artifactId>maven-alfresco-extension-archetype</artifactId>
<version>1.1.5-SNAPSHOT</version>
<packaging>maven-archetype</packaging>
<name>Maven alfresco Extension archetype</name>
<url>${site.url}</url>
<url>${project.artifactId}</url>
<parent>
<groupId>com.sourcesense.alfresco</groupId>
<artifactId>maven-alfresco-archetypes</artifactId>
<version>1.0.5-SNAPSHOT</version>
<version>1.9.0-SNAPSHOT</version>
</parent>
<description>
This archetype developed aims to provide a standardized approach to development, release and deployment of Alfresco extensions (as opposed to
@@ -39,14 +37,6 @@
least, m2 build is more likely to be maintained and improved (especially in the likely case Alfresco moves to maven2). For more details on the
m2 apprach please refer instead to README Section (or directly and to README-m2.txt of the generated project).
</description>
<properties>
<svn.url>${svn.base.url}/trunk/maven-alfresco-archetypes/${artifactId}</svn.url>
<site.url>https://repository.sourcesense.com/maven2-sites/maven-alfresco-archetypes/${pom.artifactId}</site.url>
</properties>
<scm>
<developerConnection>scm:svn:https://maven-alfresco-archetypes.googlecode.com/svn/trunk/maven-alfresco-archetypes/maven-alfresco-extension-archetype</developerConnection>
<url>https://maven-alfresco-archetypes.googlecode.com/svn/trunk/maven-alfresco-archetypes/maven-alfresco-extension-archetype</url>
</scm>
<build>
<extensions>
<extension>
@@ -57,31 +47,6 @@
<!-- Unreleased version of webdav wagon plugin which fixes a boring stacktrace logging from this provider.
FIXME: Improve the fix and submit the patch
-->
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-7</version>
<configuration>
<!-- useEditMode>true</useEditMode>-->
<!-- dryRun>true</dryRun-->
<preparationGoals>clean package</preparationGoals>
<goals>deploy site:site site:deploy</goals>
<tagBase>${svn.tags.url}</tagBase>
</configuration>
</plugin>
</plugins>
</extensions>
</build>
<distributionManagement>
<repository>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2</url>
</repository>
<site>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2-sites/${pom.artifactId}</url>
</site>
</distributionManagement>
</project>

View File

@@ -38,12 +38,6 @@
| -Dwebapp.name=<extensionName> - name of the WAR artifact to be built (default: ${artifactId}-{version}.jar )
| -Denterprise - Includes LDAP configuration as defined in application.properties
-->
<repositories>
<repository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/maven2</url>
</repository>
</repositories>
<!-- Default properties -->
<properties>
<!-- src/main/properties/<env>/application.properties is loaded -->
@@ -95,26 +89,28 @@
| Alfresco Community dependencies are generally available in ss-public repo.
| FIXME: Alfresco enterprise dependencies are only available on SS repo ATM. Alfresco *needs* to deliver their artifacts on (at least) partner repos
|-->
<repositories>
<repository>
<id>ss-public-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public</url>
</repository>
<repository>
<id>ss-public-snapshots-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public-snapshots</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>codehaus snapshot repository</id>
<url>http://snapshots.repository.codehaus.org/</url>
<releases>
<enabled>true</enabled>
</releases>
<id>ss-public</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public</url>
</pluginRepository>
<pluginRepository>
<id>Maven Snapshots</id>
<url>http://snapshots.maven.codehaus.org/maven2/</url>
<snapshots></snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
<pluginRepository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/maven2</url>
</pluginRepository>
<id>ss-public-snapshots-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public-snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<!-- Uncomment SCM definitions in order to have mvn release:perform to actually tag the code
<scm>
@@ -449,14 +445,6 @@
| Enable this repo in case of non publicly redistributable artifacts (Sourcesense private repositories via webdav)
|
-->
<repository>
<id>ss-private</id>
<url>dav:https://dev.sourcesense.com/repos/dev/maven2</url>
</repository>
<site>
<id>ss-site-private</id>
<url>dav:https://dev.sourcesense.com/cargo/maven2-sites</url>
</site>
</distributionManagement>
<!--

View File

@@ -0,0 +1,24 @@
<document>
<properties>
<title>Maven AMP plugin</title>
</properties>
<body>
<release version="3.0.0" date="2009-02-20" description="Alfresco 3.0 Reday Public stable release">
</release>
<release version="2.0.0" date="2008-07-06" description="Refactored Public release">
<action dev="mindthegab" type="add">
Now consistent maven plugin properties usage and support for AMP overlays and full AMP lifecycle
</action>
<action dev="mindthegab" type="add">
Added UnArchiver to mimic MMT behavior. Not needed anymore as AMPs gets properly unpacked into a WAR artifact.
</action>
<action dev="mindthegab" type="add">
Added plugin site documentation
</action>
<action dev="mindthegab" type="add">
Deployed on maven repository: http://repository.sourcesense.com/maven2/org/alfresco/maven/plugins
</action>
</release>
</body>
</document>

View File

@@ -0,0 +1,765 @@
package org.alfresco.maven.plugin.amp;
/*
* 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.alfresco.maven.plugin.amp.overlay.OverlayManager;
import org.alfresco.maven.plugin.amp.packaging.AmpPackagingContext;
import org.alfresco.maven.plugin.amp.packaging.AmpPackagingTask;
import org.alfresco.maven.plugin.amp.packaging.AmpPostPackagingTask;
import org.alfresco.maven.plugin.amp.packaging.AmpProjectPackagingTask;
import org.alfresco.maven.plugin.amp.packaging.OverlayPackagingTask;
import org.alfresco.maven.plugin.amp.packaging.SaveAmpStructurePostPackagingTask;
import org.alfresco.maven.plugin.amp.util.AmpStructure;
import org.alfresco.maven.plugin.amp.util.AmpStructureSerializer;
import org.alfresco.maven.plugin.amp.util.CompositeMap;
import org.alfresco.maven.plugin.amp.util.PropertyUtils;
import org.alfresco.maven.plugin.amp.util.ReflectionProperties;
import org.apache.maven.archiver.MavenArchiveConfiguration;
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.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public abstract class AbstractAmpMojo extends AbstractMojo
{
/**
* Returns a string array of the classes and resources to be excluded from the jar excludes to be used
* when assembling/copying the AMP.
*
* @return an array of tokens to exclude
*/
protected String[] getExcludes()
{
List excludeList = new ArrayList();
if ( StringUtils.isNotEmpty( mAmpJarExcludes ) )
{
excludeList.addAll( Arrays.asList( StringUtils.split( mAmpJarExcludes, "," ) ) );
}
return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
}
/**
* Returns a string array of the classes and resources to be included from the jar assembling/copying the war.
*
* @return an array of tokens to include
*/
protected String[] getIncludes()
{
return StringUtils.split( StringUtils.defaultString( mAmpJarIncludes ), "," );
}
/**
* Returns a string array of the resources to be included in the AMP web/ folder.
*
* @return an array of tokens to include
*/
protected String[] getWebIncludes()
{
return StringUtils.split( StringUtils.defaultString( mAmpWebIncludes ), "," );
}
/**
* Returns a string array of the resources to be excluded in the AMP web/ folder.
*
* @return an array of tokens to exclude
*/
protected String[] getWebExcludes()
{
List excludeList = new ArrayList();
if ( StringUtils.isNotEmpty( mAmpWebExcludes ) )
{
excludeList.addAll( Arrays.asList( StringUtils.split( mAmpWebExcludes, "," ) ) );
}
return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
}
/**
* Returns a string array of the excludes to be used
* when adding dependent AMPs as an overlay onto this AMP.
*
* @return an array of tokens to exclude
*/
protected String[] getDependentAmpExcludes()
{
String[] excludes;
if ( StringUtils.isNotEmpty( dependentAmpExcludes ) )
{
excludes = StringUtils.split( dependentAmpExcludes, "," );
}
else
{
excludes = EMPTY_STRING_ARRAY;
}
return excludes;
}
/**
* Returns a string array of the includes to be used
* when adding dependent AMP as an overlay onto this AMP.
*
* @return an array of tokens to include
*/
protected String[] getDependentAmpIncludes()
{
return StringUtils.split( StringUtils.defaultString( dependentAmpIncludes ), "," );
}
public void buildExplodedAmp( File webappDirectory )
throws MojoExecutionException, MojoFailureException
{
webappDirectory.mkdirs();
try
{
buildAmp( mProject, webappDirectory );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Could not build AMP", e );
}
}
/**
* Builds the webapp for the specified project with the new packaging task
* thingy
* <p/>
* Classes, libraries and tld files are copied to
* the <tt>webappDirectory</tt> during this phase.
*
* @param project the maven project
* @param webappDirectory the target directory
* @throws MojoExecutionException if an error occured while packaging the webapp
* @throws MojoFailureException if an unexpected error occured while packaging the webapp
* @throws IOException if an error occured while copying the files
*/
public void buildAmp( MavenProject project, File webappDirectory )
throws MojoExecutionException, MojoFailureException, IOException
{
AmpStructure cache;
if ( mUseCache && mCacheFile.exists() )
{
cache = new AmpStructure( webappStructureSerialier.fromXml( mCacheFile ) );
}
else
{
cache = new AmpStructure( null );
}
final long startTime = System.currentTimeMillis();
getLog().info( "Assembling AMP [" + project.getArtifactId() + "] in [" + webappDirectory + "]" );
final OverlayManager overlayManager =
new OverlayManager( mOverlays, project, dependentAmpIncludes, dependentAmpExcludes );
final List packagingTasks = getPackagingTasks( overlayManager );
final AmpPackagingContext context = new DefaultAmpPackagingContext( webappDirectory, cache, overlayManager );
final Iterator it = packagingTasks.iterator();
while ( it.hasNext() )
{
AmpPackagingTask ampPackagingTask = (AmpPackagingTask) it.next();
ampPackagingTask.performPackaging( context );
}
// Post packaging
final List postPackagingTasks = getPostPackagingTasks();
final Iterator it2 = postPackagingTasks.iterator();
while ( it2.hasNext() )
{
AmpPostPackagingTask task = (AmpPostPackagingTask) it2.next();
task.performPostPackaging( context );
}
getLog().info( "AMP assembled in[" + ( System.currentTimeMillis() - startTime ) + " msecs]" );
}
/**
* Returns a <tt>List</tt> of the {@link org.alfresco.maven.plugin.amp.packaging.AmpPackagingTask}
* instances to invoke to perform the packaging.
*
* @param overlayManager the overlay manager
* @return the list of packaging tasks
* @throws MojoExecutionException if the packaging tasks could not be built
*/
private List getPackagingTasks( OverlayManager overlayManager )
throws MojoExecutionException
{
final List packagingTasks = new ArrayList();
final List resolvedOverlays = overlayManager.getOverlays();
final Iterator it = resolvedOverlays.iterator();
while ( it.hasNext() )
{
Overlay overlay = (Overlay) it.next();
if ( overlay.isCurrentProject() )
{
packagingTasks.add( new AmpProjectPackagingTask( mAmpResources, mModuleProperties) );
}
else
{
packagingTasks.add( new OverlayPackagingTask( overlay ) );
}
}
return packagingTasks;
}
/**
* Returns a <tt>List</tt> of the {@link org.alfresco.maven.plugin.amp.packaging.AmpPostPackagingTask}
* instances to invoke to perform the post-packaging.
*
* @return the list of post packaging tasks
*/
private List getPostPackagingTasks()
{
final List postPackagingTasks = new ArrayList();
if ( mUseCache )
{
postPackagingTasks.add( new SaveAmpStructurePostPackagingTask( mCacheFile ) );
}
// TODO add lib scanning to detect duplicates
return postPackagingTasks;
}
/**
* The maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject mProject;
/**
* The directory containing generated classes.
*
* @parameter expression="${project.build.outputDirectory}"
* @required
* @readonly
*/
private File mClassesDirectory;
/**
* The Jar archiver needed for archiving classes directory into jar file under WEB-INF/lib.
*
* @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
* @required
*/
private JarArchiver mJarArchiver;
/**
* The directory where the webapp is built.
*
* @parameter expression="${project.build.directory}/${project.build.finalName}"
* @required
*/
private File mAmpDirectory;
/**
* Single directory for extra files to include in the AMP.
*
* @parameter expression="${project.build.outputDirectory}"
* @required
*/
private File mAmpConfigDirectory;
/**
* Single directory for extra files to include in the AMP.
*
* @parameter expression="${basedir}/src/main/webapp"
* @required
*/
private File mAmpWebDirectory;
/**
* The list of webResources we want to transfer.
*
* @parameter
*/
private Resource[] mAmpResources;
/**
* Filters (property files) to include during the interpolation of the pom.xml.
*
* @parameter expression="${project.build.filters}"
*/
private List filters;
/**
* The path to the web.xml file to use.
*
* @parameter expression="${maven.amp.moduleProperties}" default-value="${project.basedir}/module.properties"
*/
private File mModuleProperties;
/**
* Directory to unpack dependent AMPs into if needed
*
* @parameter expression="${project.build.directory}/amp/work"
* @required
*/
private File mWorkDirectory;
/**
* The file name mapping to use to copy libraries and tlds. If no file mapping is
* set (default) the file is copied with its standard name.
*
* @parameter
* @since 2.0.3
*/
private String mOutputFileNameMapping;
/**
* The file containing the webapp structure cache.
*
* @parameter expression="${project.build.directory}/amp/work/amp-cache.xml"
* @required
* @since 2.1
*/
private File mCacheFile;
/**
* Whether the cache should be used to save the status of the webapp
* accross multiple runs.
*
* @parameter expression="${useCache}" default-value="true"
* @since 2.1
*/
private boolean mUseCache = true;
/**
* To look up Archiver/UnArchiver implementations
*
* @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
* @required
*/
protected ArchiverManager mArchiverManager;
private static final String META_INF = "META-INF";
public static final String DEFAULT_FILE_NAME_MAPPING_CLASSIFIER =
"${artifactId}-${version}-${classifier}.${extension}";
public static final String DEFAULT_FILE_NAME_MAPPING = "${artifactId}-${version}.${extension}";
/**
* The comma separated list of tokens to include in the AMP internal JAR. Default **.
* Default is '**'.
*
* @parameter alias="includes"
*/
private String mAmpJarIncludes = "**";
/**
* The comma separated list of tokens to exclude from the AMP created JAR file. By default module configuration is left outside jars.
*
* @parameter alias="excludes" default-value="alfresco/module/**"
*/
private String mAmpJarExcludes;
/**
* The comma separated list of tokens to include in the AMP internal JAR. Default **.
* Default is '**'.
*
* @parameter alias="webIncludes" default-value="**"
*/
private String mAmpWebIncludes;
/**
* The comma separated list of tokens to exclude from the AMP created JAR file. By default module configuration is left outside jars.
*
* @parameter alias="webExcludes"
*/
private String mAmpWebExcludes;
/**
* The comma separated list of tokens to include when doing
* a AMP overlay.
* Default is '**'
*
* @parameter
*/
private String dependentAmpIncludes = "**/**";
/**
* The comma separated list of tokens to exclude when doing
* a AMP overlay.
*
* @parameter
*/
private String dependentAmpExcludes = "META-INF/**";
/**
* The overlays to apply.
*
* @parameter
* @since 2.1
*/
private List mOverlays = new ArrayList();
/**
* The maven archive configuration to use.
*
* @parameter
*/
protected MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
private static final String[] EMPTY_STRING_ARRAY = {};
private final AmpStructureSerializer webappStructureSerialier = new AmpStructureSerializer();
// AMP packaging implementation
private class DefaultAmpPackagingContext
implements AmpPackagingContext
{
private final AmpStructure webappStructure;
private final File mAmpDirectory;
private final OverlayManager overlayManager;
public DefaultAmpPackagingContext( File webappDirectory, final AmpStructure webappStructure,
final OverlayManager overlayManager )
{
this.mAmpDirectory = webappDirectory;
this.webappStructure = webappStructure;
this.overlayManager = overlayManager;
// This is kinda stupid but if we loop over the current overlays and we request the path structure
// it will register it. This will avoid wrong warning messages in a later phase
final Iterator it = overlayManager.getOverlayIds().iterator();
while ( it.hasNext() )
{
String overlayId = (String) it.next();
webappStructure.getStructure( overlayId );
}
}
public MavenProject getProject()
{
return mProject;
}
public File getAmpDirectory()
{
return mAmpDirectory;
}
public File getClassesDirectory()
{
return mClassesDirectory;
}
public Log getLog()
{
return AbstractAmpMojo.this.getLog();
}
public String getOutputFileNameMapping()
{
return mOutputFileNameMapping;
}
public File getAmpWebDirectory()
{
return mAmpWebDirectory;
}
public String[] getAmpJarIncludes()
{
return getIncludes();
}
public String[] getAmpJarExcludes()
{
return getExcludes();
}
public File getOverlaysWorkDirectory()
{
return mWorkDirectory;
}
public ArchiverManager getArchiverManager()
{
return mArchiverManager;
}
public MavenArchiveConfiguration getArchive()
{
return archive;
}
public JarArchiver getJarArchiver()
{
return mJarArchiver;
}
public List getFilters()
{
return filters;
}
public Map getFilterProperties()
throws MojoExecutionException
{
Map filterProperties = new Properties();
// System properties
filterProperties.putAll( System.getProperties() );
// Project properties
filterProperties.putAll( mProject.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( mProject ), filterProperties );
}
public AmpStructure getAmpStructure()
{
return webappStructure;
}
public List getOwnerIds()
{
return overlayManager.getOverlayIds();
}
/**
* @see org.alfresco.maven.plugin.amp.packaging.AmpPackagingContext#getAmpConfigDirectory()
*/
public File getAmpConfigDirectory()
{
return mAmpConfigDirectory;
}
public String[] getAmpWebExcludes() {
return getWebExcludes();
}
public String[] getAmpWebIncludes() {
return getWebIncludes();
}
}
public MavenProject getProject()
{
return mProject;
}
public void setProject( MavenProject project )
{
this.mProject = project;
}
public File getClassesDirectory()
{
return mClassesDirectory;
}
public void setClassesDirectory( File classesDirectory )
{
this.mClassesDirectory = classesDirectory;
}
public File getAmpDirectory()
{
return mAmpDirectory;
}
public void setAmpDirectory( File webappDirectory )
{
this.mAmpDirectory = webappDirectory;
}
public File getAmpSourceDirectory()
{
return mAmpWebDirectory;
}
public void setAmpSourceDirectory( File ampSourceDirectory )
{
this.mAmpWebDirectory = ampSourceDirectory;
}
public File getWebXml()
{
return mModuleProperties;
}
public void setWebXml( File webXml )
{
this.mModuleProperties = webXml;
}
public String getOutputFileNameMapping()
{
return mOutputFileNameMapping;
}
public void setOutputFileNameMapping( String outputFileNameMapping )
{
this.mOutputFileNameMapping = outputFileNameMapping;
}
public List getOverlays()
{
return mOverlays;
}
public void setOverlays( List overlays )
{
this.mOverlays = overlays;
}
public void addOverlay( Overlay overlay )
{
mOverlays.add( overlay );
}
public JarArchiver getJarArchiver()
{
return mJarArchiver;
}
public void setJarArchiver( JarArchiver jarArchiver )
{
this.mJarArchiver = jarArchiver;
}
public Resource[] getAmpResources()
{
return mAmpResources;
}
public void setAmpResources( Resource[] webResources )
{
this.mAmpResources = webResources;
}
public List getFilters()
{
return filters;
}
public void setFilters( List filters )
{
this.filters = filters;
}
public File getWorkDirectory()
{
return mWorkDirectory;
}
public void setWorkDirectory( File workDirectory )
{
this.mWorkDirectory = workDirectory;
}
public File getCacheFile()
{
return mCacheFile;
}
public void setCacheFile( File cacheFile )
{
this.mCacheFile = cacheFile;
}
public void setAmpSourceIncludes( String ampSourceIncludes )
{
this.mAmpJarIncludes = ampSourceIncludes;
}
public String getAmpJarExcludes()
{
return mAmpJarExcludes;
}
public void setAmpJarExcludes( String ampJarExcludes )
{
this.mAmpJarExcludes = ampJarExcludes;
}
public boolean isUseCache()
{
return mUseCache;
}
public void setUseCache( boolean useCache )
{
this.mUseCache = useCache;
}
}

View File

@@ -0,0 +1,42 @@
package org.alfresco.maven.plugin.amp;
/*
* 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 webapp
*
* @goal explodedAmp
* @phase package
* @requiresDependencyResolution runtime
*/
public class AmpExplodedMojo extends AbstractAmpMojo
{
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( "Exploding AMP" );
this.buildExplodedAmp( this.getAmpDirectory() );
}
}

View File

@@ -0,0 +1,348 @@
package org.alfresco.maven.plugin.amp;
/*
* 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.alfresco.plexus.archiver.AmpArchiver;
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;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
import java.io.File;
import java.io.IOException;
/**
* Build a amp/webapp.
* <p>
* Note this is a modification of Emmanuel Venisse's (evenisse@apache.org) WAR
* Mojo and has been adapted to build an Alfresco AMP.
* @version $Id:$
* @goal amp
* @phase package
* @requiresDependencyResolution runtime
*/
public class AmpMojo extends AbstractAmpMojo
{
/* ====================================================================== */
// constructors
/* ====================================================================== */
/**
* default constructor
*/
public AmpMojo()
{
this.setAmpArchiver(null);
this.setAmpName(null);
this.setOutputDirectory(null);
}
/* ====================================================================== */
// properties
/* ====================================================================== */
/**
* 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 mPrimaryArtifact;
/**
* get the the internal value for the <code>ampArchiver</code> property.
* <p>
* The <code>ampArchiver</code> property
* @return Returns the internal value for the ampArchiver property.
*/
protected AmpArchiver getAmpArchiver()
{
return this.mAmpArchiver;
}
/**
* set the internal value for the <code>ampArchiver</code> property
* @param pAmpArchiver The <code>ampArchiver</code> to set.
*/
protected void setAmpArchiver(AmpArchiver pAmpArchiver)
{
this.mAmpArchiver = pAmpArchiver;
}
/**
* get the the internal value for the <code>ampName</code> property.
* <p>
* The <code>ampName</code> property
* @return Returns the internal value for the ampName property.
*/
protected String getAmpName()
{
return this.mAmpName;
}
/**
* set the internal value for the <code>ampName</code> property
* @param pAmpName The <code>ampName</code> to set.
*/
protected void setAmpName(String pAmpName)
{
this.mAmpName = pAmpName;
}
/**
* get the the internal value for the <code>outputDirectory</code> property.
* <p>
* The <code>outputDirectory</code> property
* @return Returns the internal value for the outputDirectory property.
*/
protected String getOutputDirectory()
{
return this.mOutputDirectory;
}
/**
* set the internal value for the <code>outputDirectory</code> property
* @param pOutputDirectory The <code>outputDirectory</code> to set.
*/
protected void setOutputDirectory(String pOutputDirectory)
{
this.mOutputDirectory = pOutputDirectory;
}
/**
* get the the internal value for the <code>primaryArtifact</code> property.
* <p>
* The <code>primaryArtifact</code> property
* @return Returns the internal value for the primaryArtifact property.
*/
protected boolean isPrimaryArtifact()
{
return this.mPrimaryArtifact;
}
/**
* set the internal value for the <code>primaryArtifact</code> property
* @param pPrimaryArtifact The <code>primaryArtifact</code> to set.
*/
protected void setPrimaryArtifact(boolean pPrimaryArtifact)
{
this.mPrimaryArtifact = pPrimaryArtifact;
}
/**
* get the the internal value for the <code>projectHelper</code> property.
* <p>
* The <code>projectHelper</code> property
* @return Returns the internal value for the projectHelper property.
*/
protected MavenProjectHelper getProjectHelper()
{
return this.mProjectHelper;
}
/**
* set the internal value for the <code>projectHelper</code> property
* @param pProjectHelper The <code>projectHelper</code> to set.
*/
protected void setProjectHelper(MavenProjectHelper pProjectHelper)
{
this.mProjectHelper = pProjectHelper;
}
/**
* Overload this to produce a test-war, for example.
*/
protected String getClassifier()
{
return mClassifier;
}
/**
* set the internal value for the <code>classifier</code> property
* @param pClassifier The <code>classifier</code> to set.
*/
protected void setClassifier(String pClassifier)
{
this.mClassifier = pClassifier;
}
/* ====================================================================== */
// public methods
/* ====================================================================== */
/**
* Executes the WarMojo on the current project.
*
* @throws MojoExecutionException if an error occured while building the webapp
*/
public void execute()
throws MojoExecutionException,
MojoFailureException
{
File vAmpFile = AmpMojo.getAmpFile(new File( getOutputDirectory() ), getAmpName(), getClassifier());
try
{
this.performPackaging(vAmpFile);
}
catch (Exception eAssemblyFailure)
{
/* behavior is the same for the following exceptions:
* DependencyResolutionRequiredException
* ManifestException
* IOException
* ArchiverException
*/
throw new MojoExecutionException( "Error assembling AMP: " + eAssemblyFailure.getMessage(), eAssemblyFailure );
}
}
/* ====================================================================== */
// protected methods
/* ====================================================================== */
/**
* composes the full file name for the AMP and gets a file handle for that file
* TODO: what happens when nulls are passed in
* TODO: what does a null response mean?
* @param pBaseDir Base directory for AMP
* @param pFileName Final Name of AMP
* @param pClassifier TODO: fill this in
*/
protected static File getAmpFile( File pBasedir, String pFinalName, String pClassifier )
{
String vClassifier = pClassifier;
if (vClassifier == null)
{
vClassifier = "";
}
else if (vClassifier.trim().length() > 0 && !vClassifier.startsWith( "-" ) )
{
vClassifier = "-" + vClassifier;
}
return new File(pBasedir, pFinalName + vClassifier + ".amp" );
}
/**
* Generates the webapp according to the <tt>mode</tt> attribute.
*
* @param pAmpFile the target AMP file
* @throws IOException
* @throws ArchiverException
* @throws ManifestException
* @throws DependencyResolutionRequiredException
*
*/
protected void performPackaging(File pAmpFile)
throws IOException,
ArchiverException,
ManifestException,
DependencyResolutionRequiredException,
MojoExecutionException, MojoFailureException
{
getLog().info( "Packaging Alfresco AMP (" + this.getAmpName() + ")" );
this.buildExplodedAmp(this.getAmpDirectory());
/* create and setup an archiver */
MavenArchiver vArchiver = new MavenArchiver();
vArchiver.setArchiver(this.getAmpArchiver());
vArchiver.setOutputFile(pAmpFile);
/* setup amp Archiver */
this.getAmpArchiver().addDirectory(this.getAmpDirectory(), this.getIncludes(), this.getExcludes());
// create archive
vArchiver.createArchive(this.getProject(), archive );
String vClassifier = this.getClassifier();
if ( vClassifier != null )
{
this.getProjectHelper().attachArtifact( this.getProject(), "amp", vClassifier, pAmpFile );
}
else
{
Artifact vArtifact = this.getProject().getArtifact();
if ( this.isPrimaryArtifact() )
{
vArtifact.setFile(pAmpFile);
}
else if(vArtifact.getFile() == null || vArtifact.getFile().isDirectory() )
{
vArtifact.setFile(pAmpFile);
}
}
}
/* ====================================================================== */
// member fields
/* ====================================================================== */
/**
* The directory for the generated AMP.
*
* @parameter expression="${project.build.directory}"
* @required
*/
private String mOutputDirectory;
/**
* The name of the generated AMP.
*
* @parameter expression="${project.build.finalName}"
* @required
*/
private String mAmpName;
/**
* Classifier to add to the artifact generated. If given, the artifact will be an attachment instead.
*
* @parameter
*/
private String mClassifier;
/**
* The AMP archiver.
* @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#amp}"
* @required
*/
private AmpArchiver mAmpArchiver;
/**
* @component
*/
private MavenProjectHelper mProjectHelper;
}

View File

@@ -0,0 +1,309 @@
package org.alfresco.maven.plugin.amp;
/*
* 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.artifact.Artifact;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* An overlay is a skeleton war added to another war project in order to inject a
* functionnality, resources or any other shared component.
* <p/>
* Note that a particlar war dependency can be added multiple times as an overlay
* with different includes/excludes filter; this allows building a fine grained
* overwriting policy.
* <p/>
* The current project can also be described as an overlay and could not be specified
* twice. An overlay with no groupId and no artifactId is detected as defining the
* current project.
*
* @author Stephane Nicoll
*/
public class Overlay
{
public static final String[] DEFAULT_INCLUDES = new String[]{"**/**"};
public static final String[] DEFAULT_EXCLUDES = new String[]{"META-INF/MANIFEST.MF"};
private static Overlay currentProjectInstance;
private String id;
private String groupId;
private String artifactId;
private String classifier = null;
private String[] includes = DEFAULT_INCLUDES;
private String[] excludes = DEFAULT_EXCLUDES;
private boolean filtered = false;
private boolean skip = false;
private Artifact artifact;
private String targetPath;
/** default overlay type is war */
private String type = "amp";
public Overlay()
{
super();
}
public Overlay( String groupId, String artifactId )
{
this();
this.groupId = groupId;
this.artifactId = artifactId;
}
/**
* Specify whether this overlay represents the current project or not.
*
* @return true if the overlay represents the current project, false otherwise
*/
public boolean isCurrentProject()
{
return ( groupId == null && artifactId == null );
}
/**
* Creates an overlay of the current project.
*
* @return the current project as an overlay
*/
public static Overlay currentProjectInstance()
{
if ( currentProjectInstance == null )
{
currentProjectInstance = new Overlay();
currentProjectInstance.setId( "currentBuild" );
}
return currentProjectInstance;
}
// Getters and Setters
public String getId()
{
if ( id == null )
{
final StringBuffer sb = new StringBuffer();
sb.append( getGroupId() ).append( ":" ).append( getArtifactId() );
if ( getClassifier() != null )
{
sb.append( ":" ).append( getClassifier() );
}
id = sb.toString();
}
return id;
}
public void setId( String id )
{
this.id = id;
}
public String getGroupId()
{
return groupId;
}
public void setGroupId( String groupId )
{
this.groupId = groupId;
}
public String getArtifactId()
{
return artifactId;
}
public void setArtifactId( String artifactId )
{
this.artifactId = artifactId;
}
public String getClassifier()
{
return classifier;
}
public void setClassifier( String classifier )
{
this.classifier = classifier;
}
public String[] getIncludes()
{
return includes;
}
public void setIncludes( String includes )
{
this.includes = parse( includes );
}
public void setIncludes( String[] includes )
{
this.includes = includes;
}
public String[] getExcludes()
{
return excludes;
}
public void setExcludes( String excludes )
{
this.excludes = parse( excludes );
}
public void setExcludes( String[] excludes )
{
this.excludes = excludes;
}
public boolean isFiltered()
{
return filtered;
}
public void setFiltered( boolean filtered )
{
this.filtered = filtered;
}
public boolean shouldSkip()
{
return skip;
}
public void setSkip( boolean skip )
{
this.skip = skip;
}
public Artifact getArtifact()
{
return artifact;
}
public void setArtifact( Artifact artifact )
{
this.artifact = artifact;
}
public String getTargetPath()
{
return targetPath;
}
public void setTargetPath( String targetPath )
{
this.targetPath = targetPath;
}
public String getType()
{
return type;
}
public void setType( String type )
{
this.type = type;
}
public String toString()
{
return " id " + getId();
}
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || getClass() != o.getClass() )
{
return false;
}
Overlay overlay = (Overlay) o;
if ( excludes != null ? !Arrays.equals( excludes, overlay.excludes ) : overlay.excludes != null )
{
return false;
}
if ( getId() != null ? !getId().equals( overlay.getId() ) : overlay.getId() != null )
{
return false;
}
if ( includes != null ? !Arrays.equals( includes, overlay.includes ) : overlay.includes != null )
{
return false;
}
return true;
}
public int hashCode()
{
int result;
result = ( getId() != null ? getId().hashCode() : 0 );
result = 31 * result + ( includes != null ? includes.hashCode() : 0 );
result = 31 * result + ( excludes != null ? excludes.hashCode() : 0 );
return result;
}
private String[] parse( String s )
{
final List result = new ArrayList();
if ( s == null )
{
return (String[]) result.toArray( new String[result.size()] );
}
else
{
String[] tokens = s.split( "," );
for ( int i = 0; i < tokens.length; i++ )
{
String token = tokens[i];
result.add( token.trim() );
}
return (String[]) result.toArray( new String[result.size()] );
}
}
}

View File

@@ -0,0 +1,62 @@
package org.alfresco.maven.plugin.amp.overlay;
/*
* 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.artifact.Artifact;
import org.alfresco.maven.plugin.amp.Overlay;
/**
* A default overlay implementation based on an {@link Artifact}.
*
* @author Stephane Nicoll
*/
public class DefaultOverlay
extends Overlay
{
/**
* Creates an overlay for the specified artifact.
*
* @param a the artifact
*/
public DefaultOverlay( Artifact a )
{
super();
setGroupId( a.getGroupId() );
setArtifactId( a.getArtifactId() );
setClassifier( a.getClassifier() );
setArtifact( a );
setType( a.getType() );
}
/**
* Creates an overlay for the specified artifact.
*
* @param a the artifact
* @param includes the includes to use
* @param excludes the excludes to use
*/
public DefaultOverlay( Artifact a, String includes, String excludes )
{
this( a );
setIncludes( includes );
setExcludes( excludes );
}
}

View File

@@ -0,0 +1,44 @@
package org.alfresco.maven.plugin.amp.overlay;
import org.apache.maven.plugin.MojoExecutionException;
/*
* 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.
*/
/**
* Thrown if the overlay configuration is invalid.
*
* @author Stephane Nicoll
*/
public class InvalidOverlayConfigurationException
extends MojoExecutionException
{
private static final long serialVersionUID = 1L;
public InvalidOverlayConfigurationException( String string )
{
super( string );
}
public InvalidOverlayConfigurationException( String string, Throwable throwable )
{
super( string, throwable );
}
}

View File

@@ -0,0 +1,257 @@
package org.alfresco.maven.plugin.amp.overlay;
/*
* 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.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.alfresco.maven.plugin.amp.Overlay;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.StringUtils;
/**
* Manages the overlays.
*
*
* @author Stephane Nicoll
*/
public class OverlayManager
{
private final List overlays;
private final MavenProject project;
private final List artifactsOverlays;
/**
* Creates a manager with the specified overlays.
* <p/>
* Note that the list is potentially updated by the
* manager so a new list is created based on the overlays.
*
* @param overlays the overlays
* @param project the maven project
* @param defaultIncludes the default includes to use
* @param defaultExcludes the default excludes to use
* @throws InvalidOverlayConfigurationException
* if the config is invalid
*/
public OverlayManager( List overlays, MavenProject project, String defaultIncludes, String defaultExcludes )
throws InvalidOverlayConfigurationException
{
this.overlays = new ArrayList();
if ( overlays != null )
{
this.overlays.addAll( overlays );
}
this.project = project;
this.artifactsOverlays = getOverlaysAsArtifacts();
// Initialize
initialize( defaultIncludes, defaultExcludes );
}
/**
* Returns the resolved overlays.
*
* @return the overlays
*/
public List getOverlays()
{
return overlays;
}
/**
* Returns the id of the resolved overlays.
*
* @return the overlay ids
*/
public List getOverlayIds()
{
final Iterator it = overlays.iterator();
final List result = new ArrayList();
while ( it.hasNext() )
{
Overlay overlay = (Overlay) it.next();
result.add( overlay.getId() );
}
return result;
}
/**
* Intializes the manager and validates the overlays configuration.
*
* @param defaultIncludes the default includes to use
* @param defaultExcludes the default excludes to use
* @throws InvalidOverlayConfigurationException
* if the configuration is invalid
*/
void initialize( String defaultIncludes, String defaultExcludes )
throws InvalidOverlayConfigurationException
{
// Build the list of configured artifacts and makes sure that each overlay
// refer to a valid artifact
final List configuredWarArtifacts = new ArrayList();
final ListIterator it = overlays.listIterator();
while ( it.hasNext() )
{
Overlay overlay = (Overlay) it.next();
if ( overlay == null )
{
throw new InvalidOverlayConfigurationException( "overlay could not be null." );
}
// If it's the current project, return the project instance
if ( overlay.isCurrentProject() )
{
overlay = Overlay.currentProjectInstance();
it.set( overlay );
}
// default includes/excludes - only if the overlay uses the default settings
if ( Overlay.DEFAULT_INCLUDES.equals( overlay.getIncludes() ) &&
Overlay.DEFAULT_EXCLUDES.equals( overlay.getExcludes() ) )
{
overlay.setIncludes( defaultIncludes );
overlay.setExcludes( defaultExcludes );
}
final Artifact artifact = getAssociatedArtifact( overlay );
if ( artifact != null )
{
configuredWarArtifacts.add( artifact );
overlay.setArtifact( artifact );
}
}
// Build the list of missing overlays
final Iterator it2 = artifactsOverlays.iterator();
while ( it2.hasNext() )
{
Artifact artifact = (Artifact) it2.next();
if ( !configuredWarArtifacts.contains( artifact ) )
{
// Add a default overlay for the given artifact which will be applied after
// the ones that have been configured
overlays.add( new DefaultOverlay( artifact, defaultIncludes, defaultExcludes ) );
}
}
// Final validation, make sure that the current project is in there. Otherwise add it first
final Iterator it3 = overlays.iterator();
while ( it3.hasNext() )
{
Overlay overlay = (Overlay) it3.next();
if ( overlay.equals( Overlay.currentProjectInstance() ) )
{
return;
}
}
overlays.add( 0, Overlay.currentProjectInstance() );
}
/**
* Returns the Artifact associated to the specified overlay.
* <p/>
* If the overlay defines the current project, <tt>null</tt> is
* returned. If no artifact could not be found for the overlay
* a InvalidOverlayConfigurationException is thrown.
*
* @param overlay an overlay
* @return the artifact associated to the overlay
* @throws org.apache.maven.plugin.war.overlay.InvalidOverlayConfigurationException
* if the overlay does not have an associated artifact
*/
Artifact getAssociatedArtifact( final Overlay overlay )
throws InvalidOverlayConfigurationException
{
if ( overlay.isCurrentProject() )
{
return null;
}
for ( Iterator iterator = artifactsOverlays.iterator(); iterator.hasNext(); )
{
// Handle classifier dependencies properly (clash management)
Artifact artifact = (Artifact) iterator.next();
if ( compareOverlayWithArtifact(overlay, artifact) )
{
return artifact;
}
}
// maybe its a project dependencies zip or an other type
Set projectArtifacts = this.project.getDependencyArtifacts();
if (projectArtifacts != null)
{
for( Iterator iterator = projectArtifacts.iterator();iterator.hasNext();)
{
Artifact artifact = (Artifact) iterator.next();
if ( compareOverlayWithArtifact(overlay, artifact) )
{
return artifact;
}
}
}
throw new InvalidOverlayConfigurationException(
"overlay[" + overlay + "] is not a dependency of the project." );
}
private boolean compareOverlayWithArtifact(Overlay overlay, Artifact artifact)
{
return ( StringUtils.equals( overlay.getGroupId(), artifact.getGroupId() )
&& StringUtils.equals( overlay.getArtifactId(), artifact.getArtifactId() )
&& StringUtils.equals( overlay.getType(), artifact.getType() ) && ( overlay.getClassifier() == null || ( StringUtils
.equals( overlay.getClassifier(), artifact.getClassifier() ) ) ) );
}
/**
* Returns a list of war {@link org.apache.maven.artifact.Artifact} describing
* the overlays of the current project.
*
* @return the overlays as artifacts objects
*/
private List getOverlaysAsArtifacts()
{
ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
final Set artifacts = project.getArtifacts();
final Iterator it = artifacts.iterator();
final List result = new ArrayList();
while ( it.hasNext() )
{
Artifact artifact = (Artifact) it.next();
if ( !artifact.isOptional() && filter.include( artifact ) && ( "amp".equals( artifact.getType() ) ) )
{
result.add( artifact );
}
}
return result;
}
}

View File

@@ -0,0 +1,409 @@
package org.alfresco.maven.plugin.amp.packaging;
/*
* 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.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.alfresco.maven.plugin.amp.AbstractAmpMojo;
import org.alfresco.maven.plugin.amp.util.MappingUtils;
import org.alfresco.maven.plugin.amp.util.PathSet;
import org.alfresco.maven.plugin.amp.util.AmpStructure;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
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 java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
/**
* @author Stephane Nicoll
*/
public abstract class AbstractAmpPackagingTask
implements AmpPackagingTask
{
public static final String[] DEFAULT_INCLUDES = {"**/**"};
public static final String META_INF_PATH = "META-INF";
/**
* Copies the files if possible with an optional target prefix.
* <p/>
* Copy uses a first-win strategy: files that have already been copied by previous
* tasks are ignored. This method makes sure to update the list of protected files
* which gives the list of files that have already been copied.
* <p/>
* If the structure of the source directory is not the same as the root of the
* webapp, use the <tt>targetPrefix</tt> parameter to specify in which particular
* directory the files should be copied. Use <tt>null</tt> to copy the files with
* the same structure
*
* @param sourceId the source id
* @param context the context to use
* @param sourceBaseDir the base directory from which the <tt>sourceFilesSet</tt> will be copied
* @param sourceFilesSet the files to be copied
* @param targetPrefix the prefix to add to the target file name
* @throws IOException if an error occured while copying the files
*/
protected void copyFiles( String sourceId, AmpPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet,
String targetPrefix )
throws IOException
{
for ( Iterator iter = sourceFilesSet.iterator(); iter.hasNext(); )
{
final String fileToCopyName = (String) iter.next();
final File sourceFile = new File( sourceBaseDir, fileToCopyName );
String destinationFileName;
if ( targetPrefix == null )
{
destinationFileName = fileToCopyName;
}
else
{
destinationFileName = targetPrefix + fileToCopyName;
}
copyFile( sourceId, context, sourceFile, destinationFileName );
}
}
/**
* Copies the files if possible as is.
* <p/>
* Copy uses a first-win strategy: files that have already been copied by previous
* tasks are ignored. This method makes sure to update the list of protected files
* which gives the list of files that have already been copied.
*
* @param sourceId the source id
* @param context the context to use
* @param sourceBaseDir the base directory from which the <tt>sourceFilesSet</tt> will be copied
* @param sourceFilesSet the files to be copied
* @throws IOException if an error occured while copying the files
*/
protected void copyFiles( String sourceId, AmpPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet )
throws IOException
{
copyFiles( sourceId, context, sourceBaseDir, sourceFilesSet, null );
}
/**
* Copy the specified file if the target location has not yet already been used.
* <p/>
* The <tt>targetFileName</tt> is the relative path according to the root of
* the generated web application.
*
* @param sourceId the source id
* @param context the context to use
* @param file the file to copy
* @param targetFilename the relative path according to the root of the webapp
* @throws IOException if an error occured while copying
*/
protected void copyFile( String sourceId, final AmpPackagingContext context, final File file,
String targetFilename )
throws IOException
{
final File targetFile = new File( context.getAmpDirectory(), targetFilename );
context.getAmpStructure().registerFile( sourceId, targetFilename, new AmpStructure.RegistrationCallback()
{
public void registered( String ownerId, String targetFilename )
throws IOException
{
copyFile( context, file, targetFile, targetFilename, false );
}
public void alreadyRegistered( String ownerId, String targetFilename )
throws IOException
{
copyFile( context, file, targetFile, targetFilename, true );
}
public void refused( String ownerId, String targetFilename, String actualOwnerId )
throws IOException
{
context.getLog().debug( " - " + targetFilename + " wasn't copied because it has " +
"already been packaged for overlay[" + actualOwnerId + "]." );
}
public void superseded( String ownerId, String targetFilename, String deprecatedOwnerId )
throws IOException
{
context.getLog().info( "File[" + targetFilename + "] belonged to overlay[" + deprecatedOwnerId +
"] so it will be overwritten." );
copyFile( context, file, targetFile, targetFilename, false );
}
public void supersededUnknownOwner( String ownerId, String targetFilename, String unknownOwnerId )
throws IOException
{
context.getLog().warn( "File[" + targetFilename + "] belonged to overlay[" + unknownOwnerId +
"] which does not exist anymore in the current project. It is recommended to invoke " +
"clean if the dependencies of the project changed." );
copyFile( context, file, targetFile, targetFilename, false );
}
} );
}
/**
* Copy the specified file if the target location has not yet already been
* used and filter its content with the configureed filter properties.
* <p/>
* The <tt>targetFileName</tt> is the relative path according to the root of
* the generated web application.
*
* @param sourceId the source id
* @param context the context to use
* @param file the file to copy
* @param targetFilename the relative path according to the root of the webapp
* @return true if the file has been copied, false otherwise
* @throws IOException if an error occured while copying
* @throws MojoExecutionException if an error occured while retrieving the filter properties
*/
protected boolean copyFilteredFile( String sourceId, AmpPackagingContext context, File file, String targetFilename )
throws IOException, MojoExecutionException
{
if ( context.getAmpStructure().registerFile( sourceId, targetFilename ) )
{
final File targetFile = new File( context.getAmpDirectory(), targetFilename );
// 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
targetFile.getParentFile().mkdirs();
fileReader = new BufferedReader( new FileReader( file ) );
fileWriter = new FileWriter( targetFile );
Reader reader = fileReader;
for ( int i = 0; i < getFilterWrappers().length; i++ )
{
FilterWrapper wrapper = getFilterWrappers()[i];
reader = wrapper.getReader( reader, context.getFilterProperties() );
}
IOUtil.copy( reader, fileWriter );
}
finally
{
IOUtil.close( fileReader );
IOUtil.close( fileWriter );
}
// Add the file to the protected list
context.getLog().debug( " + " + targetFilename + " has been copied." );
return true;
}
else
{
context.getLog().debug( " - " + targetFilename + " wasn't copied because it has already been packaged." );
return false;
}
}
/**
* Unpacks the specified file to the specified directory.
*
* @param context the packaging context
* @param file the file to unpack
* @param unpackDirectory the directory to use for th unpacked file
* @throws MojoExecutionException if an error occured while unpacking the file
*/
protected void doUnpack( AmpPackagingContext context, File file, File unpackDirectory )
throws MojoExecutionException
{
String archiveExt = FileUtils.getExtension( file.getAbsolutePath() ).toLowerCase();
// Uncompressing an AMP into another AMP does not require any
// special treatment so we just use a zip unarchiver
if ("amp".equals(archiveExt))
{
archiveExt = "zip";
}
try
{
UnArchiver unArchiver = context.getArchiverManager().getUnArchiver( archiveExt );
unArchiver.setSourceFile( file );
unArchiver.setDestDirectory( unpackDirectory );
unArchiver.setOverwrite( true );
unArchiver.extract();
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error unpacking file[" + file.getAbsolutePath() + "]" + "to[" +
unpackDirectory.getAbsolutePath() + "]", e );
}
catch ( ArchiverException e )
{
throw new MojoExecutionException( "Error unpacking file[" + file.getAbsolutePath() + "]" + "to[" +
unpackDirectory.getAbsolutePath() + "]", e );
}
catch ( NoSuchArchiverException e )
{
context.getLog().warn( "Skip unpacking dependency file[" + file.getAbsolutePath() +
" with unknown extension[" + archiveExt + "]" );
}
}
/**
* Copy file from source to destination. The directories up to <code>destination</code>
* will be created if they don't already exist. if the <code>onlyIfModified</code> flag
* is <tt>false</tt>, <code>destination</code> will be overwritten if it already exists. If the
* flag is <tt>true</tt> destination will be overwritten if it's not up to date.
* <p/>
*
* @param context the packaging context
* @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).
* @param targetFilename the relative path of the file from the webapp root directory
* @param onlyIfModified if true, copy the file only if the source has changed, always copy otherwise
* @return true if the file has been copied/updated, false otherwise
* @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot
* be written to, or an IO error occurs during copying
*/
protected boolean copyFile( AmpPackagingContext context, File source, File destination, String targetFilename,
boolean onlyIfModified )
throws IOException
{
if ( onlyIfModified && destination.lastModified() >= source.lastModified() )
{
context.getLog().debug( " * " + targetFilename + " is up to date." );
return false;
}
else
{
FileUtils.copyFile( source.getCanonicalFile(), destination );
// preserve timestamp
destination.setLastModified( source.lastModified() );
context.getLog().debug( " + " + targetFilename + " has been copied." );
return true;
}
}
/**
* Returns the file to copy. If the includes are <tt>null</tt> or empty, the
* default includes are used.
*
* @param baseDir the base directory to start from
* @param includes the includes
* @param excludes the excludes
* @return the files to copy
*/
protected PathSet getFilesToIncludes( File baseDir, String[] includes, String[] excludes )
{
final DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( baseDir );
if ( excludes != null )
{
scanner.setExcludes( excludes );
}
scanner.addDefaultExcludes();
if ( includes != null && includes.length > 0 )
{
scanner.setIncludes( includes );
}
else
{
scanner.setIncludes( DEFAULT_INCLUDES );
}
scanner.scan();
return new PathSet( scanner.getIncludedFiles() );
}
/**
* Returns the final name of the specified artifact.
* <p/>
* If the <tt>outputFileNameMapping</tt> is set, it is used, otherwise
* the standard naming scheme is used.
*
* @param context the packaging context
* @param artifact the artifact
* @return the converted filename of the artifact
*/
protected String getArtifactFinalName( AmpPackagingContext context, Artifact artifact )
{
if ( context.getOutputFileNameMapping() != null )
{
return MappingUtils.evaluateFileNameMapping( context.getOutputFileNameMapping(), artifact );
}
String classifier = artifact.getClassifier();
if ( ( classifier != null ) && !( "".equals( classifier.trim() ) ) )
{
return MappingUtils.evaluateFileNameMapping( AbstractAmpMojo.DEFAULT_FILE_NAME_MAPPING_CLASSIFIER,
artifact );
}
else
{
return MappingUtils.evaluateFileNameMapping( AbstractAmpMojo.DEFAULT_FILE_NAME_MAPPING, artifact );
}
}
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, "@", "@" );
}
}};
}
private interface FilterWrapper
{
Reader getReader( Reader fileReader, Map filterProperties );
}
}

View File

@@ -0,0 +1,189 @@
package org.alfresco.maven.plugin.amp.packaging;
/*
* 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.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.alfresco.maven.plugin.amp.util.AmpStructure;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import java.io.File;
import java.util.List;
import java.util.Map;
/**
* The packaging context of the AMP
*
* @author Stephane Nicoll - Modified version for AMP
*
*/
public interface AmpPackagingContext
{
/**
* Returns the maven project.
*
* @return the project
*/
MavenProject getProject();
/**
* Returns the webapp directory. Packaging tasks should use this
* directory to generate the webapp.
*
* @return the webapp directory
*/
File getAmpDirectory();
/**
* Returns the AMP classes + resources folder
*
* @return the webapp source directory
*/
File getAmpConfigDirectory();
/**
* Returns the AMP web directory.
*
* @return the webapp source directory
*/
File getAmpWebDirectory();
/**
* Returns the webapp source includes.
*
* @return the webapp source includes
*/
String[] getAmpJarIncludes();
/**
* Returns the webapp source excludes.
*
* @return the webapp source excludes
*/
String[] getAmpJarExcludes();
/**
* Returns the AMP web/ includes.
*
* @return the AMP web/ includes
*/
String[] getAmpWebIncludes();
/**
* Returns the AMP web/ excludes.
*
* @return the AMP web/ excludes
*/
String[] getAmpWebExcludes();
/**
* Returns the directory holding generated classes to be packed in the jar - By default is the same of the AMP configuration
*
* @return the classes directory
*/
File getClassesDirectory();
/**
* Returns the logger to use to output logging event.
*
* @return the logger
*/
Log getLog();
/**
* Returns the directory to unpack dependent WARs into if needed.
*
* @return the overlays work directory
*/
File getOverlaysWorkDirectory();
/**
* Returns the archiver manager to use.
*
* @return the archiver manager
*/
ArchiverManager getArchiverManager();
/**
* The maven archive configuration to use.
*
* @return the maven archive configuration
*/
MavenArchiveConfiguration getArchive();
/**
* Returns the Jar archiver needed for archiving classes directory into
* jar file under WEB-INF/lib.
*
* @return the jar archiver to user
*/
JarArchiver getJarArchiver();
/**
* Returns the output file name mapping to use, if any. Returns <tt>null</tt>
* if no file name mapping is set.
*
* @return the output file name mapping or <tt>null</tt>
*/
String getOutputFileNameMapping();
/**
* Returns the list of filter files to use.
*
* @return a list of filter files
*/
List getFilters();
/**
* Returns the filter properties to use to filter resources.
* <p/>
* TODO: this needs to be refactored to use the resource plugin somehow.
*
* @return a map of filter properties
* @throws MojoExecutionException if an error occured while reading a filter file
*/
Map getFilterProperties()
throws MojoExecutionException;
/**
* Returns the {@link AmpStructure}.
*
* @return the webapp structure
*/
AmpStructure getAmpStructure();
/**
* Returns the list of registered overlays for this session. This list might
* differ from the one returned by the cache; in this case, it means that the
* project's configuration has changed. The plugin will handle thos cases nicely
* but it would be better in general to invoke the clean goal.
*
* @return the list of registered overlays, including the current project
*/
List getOwnerIds();
}

View File

@@ -0,0 +1,47 @@
package org.alfresco.maven.plugin.amp.packaging;
/*
* 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;
/**
* The base packaging task.
*
* @author Stephane Nicoll
*/
public interface AmpPackagingTask
{
/**
* Performs the packaging for the specified task.
* <p/>
* The task is responsible to update the packaging context, namely
* with the files that have been copied.
*
* @param context the packaging context
* @throws MojoExecutionException if an error occured
* @throws MojoFailureException if the project configuration is invalid
*/
void performPackaging( AmpPackagingContext context )
throws MojoExecutionException, MojoFailureException;
}

View File

@@ -0,0 +1,27 @@
package org.alfresco.maven.plugin.amp.packaging;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
/**
* Defines tasks that should be performed after the packaging.
*
* @author Stephane Nicoll
*/
public interface AmpPostPackagingTask
{
/**
* Executes the post packaging task.
* <p/>
* The packaging context hold all information regarding the webapp that
* has been packaged.
*
* @param context the packaging context
* @throws MojoExecutionException if an error occured
* @throws MojoFailureException if a falure occured
*/
void performPostPackaging( AmpPackagingContext context )
throws MojoExecutionException, MojoFailureException;
}

View File

@@ -0,0 +1,326 @@
package org.alfresco.maven.plugin.amp.packaging;
import org.alfresco.maven.plugin.amp.Overlay;
import org.alfresco.maven.plugin.amp.util.PathSet;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.StringUtils;
import java.io.File;
import java.io.IOException;
/**
* Handles the project own resources, that is:
* <ul
* <li>The list of web resources, if any</li>
* <li>The content of the webapp directory if it exists</li>
* <li>The custom deployment descriptor(s), if any</li>
* <li>The content of the classes directory if it exists</li>
* <li>The dependencies of the project</li>
* </ul>
*
* @author Stephane Nicoll
*/
public class AmpProjectPackagingTask
extends AbstractAmpPackagingTask
{
private static final String MODULE_PROPERTIES = "module.properties";
private static final String WEB_PATH = "web/";
private static final String CONFIG_PATH = "config/";
private Resource[] webResources = new Resource[0];
private final File moduleProperties;
private final String id;
public AmpProjectPackagingTask( Resource[] webResource, File moduleProperties)
{
if ( webResources != null )
{
this.webResources = webResources;
}
this.moduleProperties = moduleProperties;
this.id = Overlay.currentProjectInstance().getId();
}
public void performPackaging( AmpPackagingContext context )
throws MojoExecutionException, MojoFailureException
{
context.getLog().info( "Processing amp project" );
File metainfDir = new File( context.getAmpDirectory(), META_INF_PATH );
metainfDir.mkdirs();
handleArtifacts( context );
handleWebResources( context );
handleClassesDirectory( context );
handeAmpConfigDirectory( context );
handeWebAppSourceDirectory( context );
// Notice: this will work only in case we are copying only this AMP or this AMP is
// set as last overlay of the maven-amp-plugin
handleDeploymentDescriptors(context);
}
/**
* Handles the web resources.
*
* @param context the packaging context
* @throws MojoExecutionException if a resource could not be copied
*/
protected void handleWebResources( AmpPackagingContext context )
throws MojoExecutionException
{
for ( int i = 0; i < webResources.length; i++ )
{
Resource resource = webResources[i];
if ( !( new File( resource.getDirectory() ) ).isAbsolute() )
{
resource.setDirectory( context.getProject().getBasedir() + File.separator + resource.getDirectory() );
}
// Make sure that the resource directory is not the same as the webappDirectory
if ( !resource.getDirectory().equals( context.getAmpDirectory().getPath() ) )
{
try
{
copyResources( context, resource );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Could not copy resource[" + resource.getDirectory() + "]", e );
}
}
}
}
/**
* Handles the webapp sources.
*
* @param context the packaging context
* @throws MojoExecutionException if the sources could not be copied
*/
protected void handeWebAppSourceDirectory( AmpPackagingContext context )
throws MojoExecutionException
{
if ( !context.getAmpWebDirectory().exists() )
{
context.getLog().debug( "AMP sources directory does not exist - skipping." );
}
else
if ( !context.getAmpWebDirectory().getAbsolutePath().equals( context.getAmpDirectory().getPath() ) )
{
final PathSet sources = getFilesToIncludes( context.getAmpWebDirectory(),
context.getAmpWebIncludes(),
context.getAmpWebExcludes() );
try
{
context.getLog().info("Copying AMP web data into " + WEB_PATH);
copyFiles( id, context, context.getAmpWebDirectory(), sources, WEB_PATH );
}
catch ( IOException e )
{
throw new MojoExecutionException(
"Could not copy AMP sources[" + context.getAmpDirectory().getAbsolutePath() + "]", e );
}
}
}
/**
* Handles the webapp sources.
*
* @param context the packaging context
* @throws MojoExecutionException if the sources could not be copied
*/
protected void handeAmpConfigDirectory( AmpPackagingContext context )
throws MojoExecutionException
{
if ( !context.getAmpConfigDirectory().exists() )
{
context.getLog().debug( "AMP config directory does not exist - skipping." );
}
else
{
if ( !context.getAmpConfigDirectory().getAbsolutePath().equals( context.getAmpDirectory().getPath() ) )
{
final PathSet sources = getFilesToIncludes( context.getAmpConfigDirectory(),
new String[0],
new String[] {"**/*.class"} );
try
{
context.getLog().info("packaging AMP config items into " + CONFIG_PATH);
copyFiles( id, context, context.getAmpConfigDirectory(), sources, CONFIG_PATH );
}
catch ( IOException e )
{
throw new MojoExecutionException(
"Could not copy AMP config [" + context.getAmpDirectory().getAbsolutePath() + "]", e );
}
}
}
}
/**
* Handles the webapp artifacts.
*
* @param context the packaging context
* @throws MojoExecutionException if the artifacts could not be packaged
*/
protected void handleArtifacts( AmpPackagingContext context )
throws MojoExecutionException
{
ArtifactsPackagingTask task = new ArtifactsPackagingTask( context.getProject().getArtifacts() );
task.performPackaging( context );
}
/**
* Handles the webapp classes.
*
* @param context the packaging context
* @throws MojoExecutionException if the classes could not be packaged
*/
protected void handleClassesDirectory( AmpPackagingContext context )
throws MojoExecutionException
{
ClassesPackagingTask task = new ClassesPackagingTask();
task.performPackaging( context );
}
/**
* Handles the deployment descriptors, if specified. Note that the behavior
* here is slightly different since the customized entry always win, even if
* an overlay has already packaged a web.xml previously.
*
* @param context the packaging context
* @param webinfDir the web-inf directory
* @param metainfDir the meta-inf directory
* @throws MojoFailureException if the web.xml is specified but does not exist
* @throws MojoExecutionException if an error occured while copying the descriptors
*/
protected void handleDeploymentDescriptors( AmpPackagingContext context)
throws MojoFailureException, MojoExecutionException
{
try
{
if ( moduleProperties != null && StringUtils.isNotEmpty( moduleProperties.getName() ) )
{
if ( !moduleProperties.exists() )
{
throw new MojoFailureException( "The specified module.properties file '" + moduleProperties + "' does not exist" );
}
if(new File(context.getAmpDirectory().getPath() + "/module.properties").exists())
{
context.getLog().warn("A module.properties was already present, possibly due to previous overlay. Unexpected results may happen, check your target dir");
}
//rename to module.properties
context.getLog().info("copying " + moduleProperties + " into " + MODULE_PROPERTIES);
copyFilteredFile(id, context, moduleProperties, MODULE_PROPERTIES);
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Failed to copy deployment descriptor", e );
}
}
/**
* Copies webapp webResources from the specified directory.
*
* @param context the war packaging context to use
* @param resource the resource to copy
* @throws IOException if an error occured while copying the resources
* @throws MojoExecutionException if an error occured while retrieving the filter properties
*/
public void copyResources( AmpPackagingContext context, Resource resource )
throws IOException, MojoExecutionException
{
if ( !context.getAmpDirectory().exists() )
{
context.getLog().warn( "Not copying AMP ampResources[" + resource.getDirectory() +
"]: amp directory[" + context.getAmpDirectory().getAbsolutePath() + "] does not exist!" );
}
context.getLog().info( "Copy AMP ampResources[" + resource.getDirectory() + "] to[" +
context.getAmpDirectory().getAbsolutePath() + "]" );
String[] fileNames = getFilesToCopy( resource );
for ( int i = 0; i < fileNames.length; i++ )
{
String targetFileName = fileNames[i];
if ( resource.getTargetPath() != null )
{
//TODO make sure this thing is 100% safe
targetFileName = resource.getTargetPath() + File.separator + targetFileName;
}
if ( resource.isFiltering() )
{
copyFilteredFile( id, context, new File( resource.getDirectory(), fileNames[i] ), targetFileName );
}
else
{
copyFile( id, context, new File( resource.getDirectory(), fileNames[i] ), targetFileName );
}
}
}
/**
* 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[] getFilesToCopy( Resource resource )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( resource.getDirectory() );
if ( resource.getIncludes() != null && !resource.getIncludes().isEmpty() )
{
scanner.setIncludes(
(String[]) resource.getIncludes().toArray( new String[resource.getIncludes().size()] ) );
}
else
{
scanner.setIncludes( DEFAULT_INCLUDES );
}
if ( resource.getExcludes() != null && !resource.getExcludes().isEmpty() )
{
scanner.setExcludes(
(String[]) resource.getExcludes().toArray( new String[resource.getExcludes().size()] ) );
}
scanner.addDefaultExcludes();
scanner.scan();
return scanner.getIncludedFiles();
}
}

View File

@@ -0,0 +1,135 @@
package org.alfresco.maven.plugin.amp.packaging;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.MojoExecutionException;
import org.alfresco.maven.plugin.amp.Overlay;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Handles the artifacts that needs to be packaged in the web application.
*
* @author Stephane Nicoll
*/
public class ArtifactsPackagingTask
extends AbstractAmpPackagingTask
{
public static final String LIB_PATH = "lib/";
private final Set artifacts;
private final String id;
public ArtifactsPackagingTask( Set artifacts )
{
this.artifacts = artifacts;
this.id = Overlay.currentProjectInstance().getId();
}
public void performPackaging( AmpPackagingContext context )
throws MojoExecutionException
{
final ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
final List duplicates = findDuplicates( context, artifacts );
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
String targetFileName = getArtifactFinalName( context, artifact );
context.getLog().debug( "Processing: " + targetFileName );
if ( duplicates.contains( targetFileName ) )
{
context.getLog().debug( "Duplicate found: " + targetFileName );
targetFileName = artifact.getGroupId() + "-" + targetFileName;
context.getLog().debug( "Renamed to: " + targetFileName );
}
if ( !artifact.isOptional() && filter.include( artifact ) )
{
try
{
String type = artifact.getType();
if ( "tld".equals( type ) )
{
// copyFile( id, context, artifact.getFile(), TLD_PATH + targetFileName );
}
else if ( "aar".equals( type ) )
{
//copyFile( id, context, artifact.getFile(), SERVICES_PATH + targetFileName );
}
else if ( "jar".equals( type ) || "ejb".equals( type ) || "ejb-client".equals( type ) ||
"test-jar".equals( type ) )
{
copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName );
context.getLog().debug("addng " + artifact.getId() + " to AMP in " + LIB_PATH );
}
else if ( "par".equals( type ) )
{
targetFileName = targetFileName.substring( 0, targetFileName.lastIndexOf( '.' ) ) + ".jar";
copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName );
}
else if ( "war".equals( type ) )
{
// Nothing to do here, it is an overlay and it's already handled
}
else if ("zip".equals( type ))
{
// Nothing to do here, it is an overlay and it's already handled
}
else if ("amp".equals( type ))
{
context.getLog().debug("skipping " + artifact.getId() + " in artifacts packaging phase. Will be processed in overlay");
}
else
{
context.getLog().debug(
"Artifact of type[" + type + "] is not supported, ignoring[" + artifact + "]" );
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Failed to copy file for artifact[" + artifact + "]", e );
}
}
}
}
/**
* Searches a set of artifacts for duplicate filenames and returns a list
* of duplicates.
*
* @param context the packaging context
* @param artifacts set of artifacts
* @return List of duplicated artifacts as bundling file names
*/
private List findDuplicates( AmpPackagingContext context, Set artifacts )
{
List duplicates = new ArrayList();
List identifiers = new ArrayList();
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
String candidate = getArtifactFinalName( context, artifact );
if ( identifiers.contains( candidate ) )
{
duplicates.add( candidate );
}
else
{
identifiers.add( candidate );
}
}
return duplicates;
}
}

View File

@@ -0,0 +1,84 @@
package org.alfresco.maven.plugin.amp.packaging;
import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.MojoExecutionException;
import org.alfresco.maven.plugin.amp.Overlay;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.jar.ManifestException;
import java.io.File;
import java.io.IOException;
/**
* Handles the classes directory that needs to be packaged in the web application.
* <p/>
* Based on the {@link AmpPackagingContext#archiveClasses()} flag the resources
* either copied into to <tt>WEB-INF/classes</tt> directory or archived in a jar
* within the <tt>WEB-INF/lib</tt> directory.
*
* @author Stephane Nicoll
*/
public class ClassesPackagingTask
extends AbstractAmpPackagingTask
{
private static final String LIB_PATH = "lib/";
public void performPackaging( AmpPackagingContext context )
throws MojoExecutionException
{
/* AMP Files do not have a classes folder */
generateJarArchive( context );
}
protected void generateJarArchive( AmpPackagingContext context )
throws MojoExecutionException
{
//TODO use ArtifactFactory and resolve the final name the usual way instead
final String archiveName = context.getProject().getBuild().getFinalName() + ".jar";
final String targetFilename = LIB_PATH + archiveName;
if ( context.getAmpStructure().registerFile( Overlay.currentProjectInstance().getId(), targetFilename ) )
{
final File libDirectory = new File( context.getAmpDirectory(), LIB_PATH );
final File jarFile = new File( libDirectory, archiveName );
try
{
final MavenArchiver archiver = new MavenArchiver();
archiver.setArchiver( context.getJarArchiver() );
archiver.setOutputFile( jarFile );
archiver.getArchiver().addDirectory( context.getClassesDirectory(), context.getAmpJarIncludes(),
context.getAmpJarExcludes());
context.getLog().debug("Archiving AMP classes JAR with default excludes: " + context.getAmpJarExcludes());
archiver.createArchive( context.getProject(), context.getArchive() );
}
catch ( ArchiverException e )
{
throw new MojoExecutionException( "Could not create classes archive", e );
}
catch ( ManifestException e )
{
throw new MojoExecutionException( "Could not create classes archive", e );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Could not create classes archive", e );
}
catch ( DependencyResolutionRequiredException e )
{
throw new MojoExecutionException( "Could not create classes archive", e );
}
}
else
{
context.getLog().warn(
"Could not generate archive classes file[" + targetFilename + "] has already been copied." );
}
}
}

View File

@@ -0,0 +1,150 @@
package org.alfresco.maven.plugin.amp.packaging;
/*
* 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.alfresco.maven.plugin.amp.Overlay;
import org.alfresco.maven.plugin.amp.util.PathSet;
import org.codehaus.plexus.util.FileUtils;
import java.io.File;
import java.io.IOException;
/**
* Handles an overlay.
*
* @author Stephane Nicoll
*/
public class OverlayPackagingTask
extends AbstractAmpPackagingTask
{
private final Overlay overlay;
public OverlayPackagingTask( Overlay overlay )
{
if ( overlay == null )
{
throw new NullPointerException( "overlay could not be null." );
}
if ( overlay.equals( Overlay.currentProjectInstance() ) )
{
throw new IllegalStateException( "Could not handle the current project with this task." );
}
this.overlay = overlay;
}
public void performPackaging( AmpPackagingContext context )
throws MojoExecutionException
{
System.out.print( "OverlayPackagingTask performPackaging overlay.getTargetPath() " + overlay.getTargetPath());
if ( overlay.shouldSkip() )
{
context.getLog().info( "Skipping overlay[" + overlay + "]" );
}
else
{
try
{
context.getLog().info( "Processing overlay[" + overlay + "]" );
// Step1: Extract if necessary
final File tmpDir = unpackOverlay( context, overlay );
// Step2: setup
final PathSet includes = getFilesToIncludes( tmpDir, overlay.getIncludes(), overlay.getExcludes() );
// Copy
if ( null == overlay.getTargetPath() )
{
copyFiles( overlay.getId(), context, tmpDir, includes );
}
else
{
// overlay.getTargetPath() must ended with /
// if not we add it
String targetPath = overlay.getTargetPath();
if (!targetPath.endsWith( "/" ))
{
targetPath = targetPath + "/";
}
copyFiles( overlay.getId(), context, tmpDir, includes, targetPath );
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Failed to copy file for overlay[" + overlay + "]", e );
}
}
}
/**
* Unpacks the specified overlay.
* <p/>
* Makes sure to skip the unpack process if the overlay has
* already been unpacked.
*
* @param context the packaging context
* @param overlay the overlay
* @return the directory containing the unpacked overlay
* @throws MojoExecutionException if an error occured while unpacking the overlay
*/
protected File unpackOverlay( AmpPackagingContext context, Overlay overlay )
throws MojoExecutionException
{
final File tmpDir = getOverlayTempDirectory( context, overlay );
// TODO: not sure it's good, we should reuse the markers of the dependency plugin
if ( FileUtils.sizeOfDirectory( tmpDir ) == 0 ||
overlay.getArtifact().getFile().lastModified() > tmpDir.lastModified() )
{
context.getLog().info( "Unpacking overlay[" + overlay + "]" );
doUnpack( context, overlay.getArtifact().getFile(), tmpDir );
}
else
{
context.getLog().debug( "Overlay[" + overlay + "] was already unpacked" );
}
return tmpDir;
}
/**
* Returns the directory to use to unpack the specified overlay.
*
* @param context the packaging context
* @param overlay the overlay
* @return the temp directory for the overlay
*/
protected File getOverlayTempDirectory( AmpPackagingContext context, Overlay overlay )
{
final File groupIdDir = new File( context.getOverlaysWorkDirectory(), overlay.getGroupId() );
if ( !groupIdDir.exists() )
{
groupIdDir.mkdir();
}
final File result = new File( groupIdDir, overlay.getArtifactId() );
if ( !result.exists() )
{
result.mkdirs();
}
return result;
}
}

View File

@@ -0,0 +1,50 @@
package org.alfresco.maven.plugin.amp.packaging;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.alfresco.maven.plugin.amp.util.AmpStructureSerializer;
import java.io.File;
import java.io.IOException;
/**
* Saves the webapp structure cache.
*
* @author Stephane Nicoll
*/
public class SaveAmpStructurePostPackagingTask
implements AmpPostPackagingTask
{
private final File targetFile;
private final AmpStructureSerializer serialier;
public SaveAmpStructurePostPackagingTask( File targetFile )
{
this.targetFile = targetFile;
this.serialier = new AmpStructureSerializer();
}
public void performPostPackaging( AmpPackagingContext context )
throws MojoExecutionException, MojoFailureException
{
if ( targetFile == null )
{
context.getLog().debug( "Cache usage is disabled, not saving webapp structure." );
}
else
{
try
{
serialier.toXml( context.getAmpStructure(), targetFile );
context.getLog().debug( "Cache saved successfully." );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Could not save webapp structure", e );
}
}
}
}

View File

@@ -0,0 +1,312 @@
package org.alfresco.maven.plugin.amp.util;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Represents the structure of a web application composed of multiple
* overlays. Each overlay is registered within this structure with the
* set of files it holds.
* <p/>
* Note that this structure is persisted to disk at each invocation to
* store wich owner holds which path (file).
*
* @author Stephane Nicoll
*/
public class AmpStructure
{
private Map registeredFiles;
private transient PathSet allFiles = new PathSet();
private transient AmpStructure cache;
/**
* Creates a new empty instance.
*/
public AmpStructure()
{
this.registeredFiles = new HashMap();
this.cache = null;
}
/**
* Creates a new instance with the specified cache.
*
* @param cache the cache
*/
public AmpStructure( AmpStructure cache )
{
this.registeredFiles = new HashMap();
if ( cache == null )
{
this.cache = new AmpStructure();
}
else
{
this.cache = cache;
}
}
/**
* Specify if the specified <tt>path</tt> is registered or not.
*
* @param path the relative path from the webapp root directory
* @return true if the path is registered, false otherwise
*/
public boolean isRegistered( String path )
{
return getFullStructure().contains( path );
}
/**
* Registers the specified path for the specified owner. Returns <tt>true</tt>
* if the path is not already registered, <tt>false</tt> otherwise.
*
* @param id the owner of the path
* @param path the relative path from the webapp root directory
* @return true if the file was registered successfully
*/
public boolean registerFile( String id, String path )
{
if ( !isRegistered( path ) )
{
doRegister( id, path );
return true;
}
else
{
return false;
}
}
/**
* Registers the specified path for the specified owner. Invokes
* the <tt>callback</tt> with the result of the registration.
*
* @param id the owner of the path
* @param path the relative path from the webapp root directory
* @param callback the callback to invoke with the result of the registration
* @throws IOException if the callback invocation throws an IOException
*/
public void registerFile( String id, String path, RegistrationCallback callback )
throws IOException
{
// If the file is already in the current structure, rejects it with the current owner
if ( isRegistered( path ) )
{
callback.refused( id, path, getOwner( path ) );
}
else
{
doRegister( id, path );
// This is a new file
if ( cache.getOwner( path ) == null )
{
callback.registered( id, path );
} // The file already belonged to this owner
else if ( cache.getOwner( path ).equals( id ) )
{
callback.alreadyRegistered( id, path );
} // The file belongs to another owner and it's known currently
else if ( getOwners().contains( cache.getOwner( path ) ) )
{
callback.superseded( id, path, cache.getOwner( path ) );
} // The file belongs to another owner and it's unknown
else
{
callback.supersededUnknownOwner( id, path, cache.getOwner( path ) );
}
}
}
/**
* Returns the owner of the specified <tt>path</tt>. If the file is not
* registered, returns <tt>null</tt>
*
* @param path the relative path from the webapp root directory
* @return the owner or <tt>null</tt>.
*/
public String getOwner( String path )
{
if ( !isRegistered( path ) )
{
return null;
}
else
{
final Iterator it = registeredFiles.keySet().iterator();
while ( it.hasNext() )
{
final String owner = (String) it.next();
final PathSet structure = getStructure( owner );
if ( structure.contains( path ) )
{
return owner;
}
}
throw new IllegalStateException(
"Should not happen, path[" + path + "] is flagged as being registered but was not found." );
}
}
/**
* Returns the owners. Note that this the returned {@link Set} may be
* inconsistent since it represents a persistent cache accross multiple
* invocations.
* <p/>
* For instance, if an overlay was removed in this execution, it will be
* still be there till the cache is cleaned. This happens when the clean
* mojo is invoked.
*
* @return the list of owners
*/
public Set getOwners()
{
return registeredFiles.keySet();
}
/**
* Returns all paths that have been registered so far.
*
* @return all registered path
*/
public PathSet getFullStructure()
{
return allFiles;
}
/**
* Returns the list of registered files for the specified owner.
*
* @param id the owner
* @return the list of files registered for that owner
*/
public PathSet getStructure( String id )
{
PathSet pathSet = (PathSet) registeredFiles.get( id );
if ( pathSet == null )
{
pathSet = new PathSet();
registeredFiles.put( id, pathSet );
}
return pathSet;
}
private void doRegister( String id, String path )
{
getFullStructure().add( path );
getStructure( id ).add( path );
}
private Object readResolve()
{
// the full structure should be resolved so let's rebuild it
this.allFiles = new PathSet();
final Iterator it = registeredFiles.values().iterator();
while ( it.hasNext() )
{
PathSet pathSet = (PathSet) it.next();
this.allFiles.addAll( pathSet );
}
return this;
}
/**
* Callback interfce to handle events related to filepath registration in
* the webapp.
*/
public interface RegistrationCallback
{
/**
* Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
* has been registered successfully.
* <p/>
* This means that the <tt>targetFilename</tt> was unknown and has been
* registered successfully.
*
* @param ownerId the ownerId
* @param targetFilename the relative path according to the root of the webapp
* @throws IOException if an error occured while handling this event
*/
void registered( String ownerId, String targetFilename )
throws IOException;
/**
* Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
* has already been registered.
* <p/>
* This means that the <tt>targetFilename</tt> was known and belongs to the
* specified owner.
*
* @param ownerId the ownerId
* @param targetFilename the relative path according to the root of the webapp
* @throws IOException if an error occured while handling this event
*/
void alreadyRegistered( String ownerId, String targetFilename )
throws IOException;
/**
* Called if the registration of the <tt>targetFilename</tt> for the
* specified <tt>ownerId</tt> has been refused since the path already
* belongs to the <tt>actualOwnerId</tt>.
* <p/>
* This means that the <tt>targetFilename</tt> was known and does not
* belong to the specified owner.
*
* @param ownerId the ownerId
* @param targetFilename the relative path according to the root of the webapp
* @param actualOwnerId the actual owner
* @throws IOException if an error occured while handling this event
*/
void refused( String ownerId, String targetFilename, String actualOwnerId )
throws IOException;
/**
* Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
* has been registered successfully by superseding a <tt>deprecatedOwnerId</tt>,
* that is the previous owner of the file.
* <p/>
* This means that the <tt>targetFilename</tt> was known but for another
* owner. This usually happens after a project's configuration change. As a
* result, the file has been registered successfully to the new owner.
*
* @param ownerId the ownerId
* @param targetFilename the relative path according to the root of the webapp
* @param deprecatedOwnerId the previous owner that does not exist anymore
* @throws IOException if an error occured while handling this event
*/
void superseded( String ownerId, String targetFilename, String deprecatedOwnerId )
throws IOException;
/**
* Called if the <tt>targetFilename</tt> for the specified <tt>ownerId</tt>
* has been registered successfully by superseding a <tt>unknownOwnerId</tt>,
* that is an owner that does not exist anymore in the current project.
* <p/>
* This means that the <tt>targetFilename</tt> was known but for an owner that
* does not exist anymore. Hence the file has been registered successfully to
* the new owner.
*
* @param ownerId the ownerId
* @param targetFilename the relative path according to the root of the webapp
* @param unknownOwnerId the previous owner that does not exist anymore
* @throws IOException if an error occured while handling this event
*/
void supersededUnknownOwner( String ownerId, String targetFilename, String unknownOwnerId )
throws IOException;
}
}

View File

@@ -0,0 +1,93 @@
package org.alfresco.maven.plugin.amp.util;
import com.thoughtworks.xstream.XStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* Serializes {@link AmpStructure} back and forth.
*
* @author Stephane Nicoll
*/
public class AmpStructureSerializer
{
private final XStream xStream;
/**
* Creates a new instance of the serializer.
*/
public AmpStructureSerializer()
{
this.xStream = new XStream();
// Register aliases
xStream.alias( "webapp-structure", AmpStructure.class );
xStream.alias( "path-set", PathSet.class );
}
/**
* Reads the {@link AmpStructure} from the specified file.
*
* @param file the file containing the webapp structure
* @return the webapp structure
* @throws IOException if an error occured while reading the structure
*/
public AmpStructure fromXml( File file )
throws IOException
{
FileReader reader = null;
try
{
reader = new FileReader( file );
return (AmpStructure) xStream.fromXML( reader );
}
finally
{
if ( reader != null )
{
reader.close();
}
}
}
/**
* Saves the {@link AmpStructure} to the specified file.
*
* @param webappStructure the structure to save
* @param targetFile the file to use to save the structure
* @throws IOException if an error occured while saving the webapp structure
*/
public void toXml( AmpStructure webappStructure, File targetFile )
throws IOException
{
FileWriter writer = null;
try
{
if ( !targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs() )
{
throw new IOException(
"Could not create parent[" + targetFile.getParentFile().getAbsolutePath() + "]" );
}
if ( !targetFile.exists() && !targetFile.createNewFile() )
{
throw new IOException( "Could not create file[" + targetFile.getAbsolutePath() + "]" );
}
writer = new FileWriter( targetFile );
xStream.toXML( webappStructure, writer );
}
finally
{
if ( writer != null )
{
writer.close();
}
}
}
}

View File

@@ -0,0 +1,61 @@
package org.alfresco.maven.plugin.amp.util;
/*
* 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 565036 2007-08-12 10:26:14Z snicoll $
* @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,95 @@
package org.alfresco.maven.plugin.amp.util;
/*
* 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.artifact.Artifact;
import org.codehaus.plexus.util.interpolation.ObjectBasedValueSource;
import org.codehaus.plexus.util.interpolation.RegexBasedInterpolator;
import org.codehaus.plexus.util.interpolation.ValueSource;
import java.util.Properties;
/**
* Utilities used to evaluate expression.
* <p/>
* TODO: this comes from the assembly plugin; refactor when it's shared.
* <p/>
* The expression might use any fied of the {@link Artifact} interface. Some
* examples might be:
* <ul>
* <li>${artifactId}-${version}.${extension}</li>
* <li>${artifactId}.${extension}</li>
* </ul>
*
* @author Stephane Nicoll
*/
public class MappingUtils
{
/**
* Evaluates the specified expression for the given artifact.
*
* @param expression the expression to evaluate
* @param artifact the artifact to use as value object for tokens
* @return expression the evaluated expression
*/
public static String evaluateFileNameMapping( String expression, Artifact artifact )
{
String value = expression;
// FIXME: This is BAD! Accessors SHOULD NOT change the behavior of the object.
artifact.isSnapshot();
RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
interpolator.addValueSource( new ObjectBasedValueSource( artifact ) );
interpolator.addValueSource( new ObjectBasedValueSource( artifact.getArtifactHandler() ) );
Properties classifierMask = new Properties();
classifierMask.setProperty( "classifier", "" );
interpolator.addValueSource( new PropertiesInterpolationValueSource( classifierMask ) );
value = interpolator.interpolate( value, "__artifact" );
return value;
}
static class PropertiesInterpolationValueSource
implements ValueSource
{
private final Properties properties;
public PropertiesInterpolationValueSource( Properties properties )
{
this.properties = properties;
}
public Object getValue( String key )
{
return properties.getProperty( key );
}
}
}

View File

@@ -0,0 +1,284 @@
package org.alfresco.maven.plugin.amp.util;
/*
* 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.DirectoryScanner;
import org.codehaus.plexus.util.StringUtils;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Set of file's paths.
* <p/>
* The class extends functionality of a "normal" set of strings by a process of
* the paths normalization. All paths are converted to unix form (slashes) and
* they don't start with starting /.
*
* @author Piotr Tabor
*/
public class PathSet
{
/**
* Set of normalized paths
*/
private Set/* <String> */pathsSet = new LinkedHashSet();
/**
* The method normalizes the path.
* <p/>
* <ul>
* <li>changes directory separator to unix's separator(/)</li>
* <li>deletes all trailing slashes</li>
* </ul>
*
* @param path to normalization
* @return normalized path
*/
protected String normalizeFilePath( String path )
{
return normalizeFilePathStatic( path );
}
/*-------------------- Business interface ------------------------------*/
/**
* Creates an empty paths set
*/
public PathSet()
{
/*Empty default constructor*/
}
/**
* Creates paths set and normalizate and adds all 'paths'.
* The source 'paths' will not be changed
*
* @param paths to be added
*/
public PathSet( Collection/*String>*/ paths )
{
addAll( paths );
}
/**
* Creates paths set and normalizate and adds all 'paths'.
* The source 'paths' will not be changed
*
* @param paths to be added
*/
public PathSet( String[] paths )
{
addAll( paths );
}
/**
* Normalizes and adds given path to the set.
*
* @param path to be added
*/
public void add( String path )
{
pathsSet.add( normalizeFilePath( path ) );
}
/**
* Normalizes and adds given paths (collection of strings)
* to the set. The source collection will not be changed
*
* @param paths - collection of strings to be added
* @param prefix added to all given paths
*/
public void addAll( Collection/*<String>*/ paths, String prefix )
{
for ( Iterator iter = paths.iterator(); iter.hasNext(); )
{
add( prefix + iter.next() );
}
}
/**
* Normalizes and adds given paths to the set.
* The source collection will not be changed
*
* @param paths to be added
* @param prefix added to all given paths
*/
public void addAll( String[] paths, String prefix )
{
for ( int i = 0; i < paths.length; i++ )
{
add( prefix + paths[i] );
}
}
/**
* Adds given paths to the set.
* The source collection will not be changed
*
* @param paths to be added
* @param prefix added to all given paths
*/
public void addAll( PathSet paths, String prefix )
{
for ( Iterator iter = paths.iterator(); iter.hasNext(); )
{
add( prefix + iter.next() );
}
}
/**
* Normalizes and adds given paths (collection of strings)
* to the set. The source collection will not be changed
*
* @param paths - collection of strings to be added
*/
public void addAll( Collection/*<String>*/ paths )
{
addAll( paths, "" );
}
/**
* Normalizes and adds given paths to the set.
* The source collection will not be changed
*
* @param paths to be added
*/
public void addAll( String[] paths )
{
addAll( paths, "" );
}
/**
* Adds given paths to the set.
* The source collection will not be changed
*
* @param paths to be added
*/
public void addAll( PathSet paths )
{
addAll( paths, "" );
}
/**
* Checks if the set constains given path. The path is normalized
* before check.
*
* @param path we are looking for in the set.
* @return information if the set constains the path.
*/
public boolean contains( String path )
{
return pathsSet.contains( normalizeFilePath( path ) );
}
/**
* Returns iterator of normalized paths (strings)
*
* @return iterator of normalized paths (strings)
*/
public Iterator iterator()
{
return pathsSet.iterator();
}
/**
* Adds given prefix to all paths in the set.
* <p/>
* The prefix should be ended by '/'. The generated paths are normalized.
*
* @param prefix to be added to all items
*/
public void addPrefix( String prefix )
{
final Set/*<String>*/ newSet = new HashSet();
for ( Iterator iter = pathsSet.iterator(); iter.hasNext(); )
{
String path = (String) iter.next();
newSet.add( normalizeFilePath( prefix + path ) );
}
pathsSet = newSet;
}
/**
* Returns count of the paths in the set
*
* @return count of the paths in the set
*/
public int size()
{
return pathsSet.size();
}
/**
* Adds to the set all files in the given directory
*
* @param directory that will be searched for file's paths to add
* @param prefix to be added to all found files
*/
public void addAllFilesInDirectory( File directory, String prefix )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( directory );
scanner.scan();
addAll( scanner.getIncludedFiles(), prefix );
}
/*-------------------- Universal static mathods ------------------------*/
/**
* The method normalizes the path.
* <p/>
* <ul>
* <li>changes directory separator to unix's separator(/)</li>
* <li>deletes all trailing slashes</li>
* </ul>
*
* @param path to normalization
* @return normalized path
*/
public static String normalizeFilePathStatic( String path )
{
return trimTrailingSlashes( StringUtils.replace( path, '\\', '/' ) );
}
/**
* The method deletes all trailing slashes from the given string
*
* @param str a string
* @return trimed string
*/
public static String trimTrailingSlashes( String str )
{
int i;
for ( i = 0; i < str.length() && str.charAt( i ) == '/'; i++ )
/* just calculate i */
{
}
return str.substring( i );
}
}

View File

@@ -0,0 +1,155 @@
package org.alfresco.maven.plugin.amp.util;
/*
* 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 565036 2007-08-12 10:26:14Z snicoll $
* @todo this is duplicated from the resources plugin - migrate to plexus-util
*/
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
* @throws IOException if an error failed while loading the properties
*/
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}.
*
* @param k the token
* @param p the properties containing the filter values
* @return the value
*/
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.alfresco.maven.plugin.amp.util;
/*
* 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 565036 2007-08-12 10:26:14Z snicoll $
* @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,114 @@
package org.alfresco.plexus.archiver;
import java.io.File;
import java.io.IOException;
import org.codehaus.plexus.archiver.*;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.zip.ZipOutputStream;
public class AmpArchiver extends JarArchiver
{
public AmpArchiver()
{
super.archiveType = "amp";
}
public void setModuleProperties(File descr)
throws ArchiverException
{
// deploymentDescriptor = descr;
// if(!deploymentDescriptor.exists())
// {
// throw new ArchiverException("Deployment descriptor: " + deploymentDescriptor + " does not exist.");
// } else
// {
// addFile(descr, "config/AMP-INF/module.properties");
// return;
// }
}
public void addLib(File fileName)
throws ArchiverException
{
addDirectory(fileName.getParentFile(), "lib/", new String[] {
fileName.getName()
}, null);
}
public void addLibs(File directoryName, String includes[], String excludes[])
throws ArchiverException
{
addDirectory(directoryName, "lib/", includes, excludes);
}
public void addClass(File fileName)
throws ArchiverException
{
addDirectory(fileName.getParentFile(), "classes/", new String[] {
fileName.getName()
}, null);
}
public void addClasses(File directoryName, String includes[], String excludes[])
throws ArchiverException
{
addDirectory(directoryName, "classes/", includes, excludes);
}
protected void initZipOutputStream(ZipOutputStream zOut)
throws IOException, ArchiverException
{
// if(deploymentDescriptor == null && !isInUpdateMode())
// {
// throw new ArchiverException("module properies attribute is required");
// }
// else
// {
super.initZipOutputStream(zOut);
return;
// }
}
protected void zipFile(ArchiveEntry entry, ZipOutputStream zOut, String vPath, int mode)
throws IOException, ArchiverException
{
if(vPath.equalsIgnoreCase("config/AMP-INF/module.properties"))
{
if(deploymentDescriptor == null || !deploymentDescriptor.getCanonicalPath().equals(entry.getFile().getCanonicalPath()) || descriptorAdded)
{
getLogger().warn("Warning: selected " + super.archiveType + " files include a config/AMP-INF/module.properites which will be ignored " + "(please use webxml attribute to " + super.archiveType + " task)");
}
else
{
super.zipFile(entry, zOut, vPath);
descriptorAdded = true;
}
}
else
{
super.zipFile(entry, zOut, vPath);
}
}
protected void cleanUp()
{
descriptorAdded = false;
super.cleanUp();
}
private File deploymentDescriptor;
private boolean descriptorAdded;
/**
* @see org.codehaus.plexus.archiver.AbstractArchiver#addDirectory(java.io.File, java.lang.String, java.lang.String[], java.lang.String[])
*/
public void addDirectory(File pArg0, String pArg1, String[] pArg2, String[] pArg3)
throws ArchiverException
{
/* */
getLogger().info("adding directory [ '"+pArg0+"' '"+pArg1+"']");
super.addDirectory(pArg0, pArg1, pArg2, pArg3);
}
}

View File

@@ -0,0 +1,279 @@
package org.alfresco.plexus.archiver;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipException;
import org.codehaus.plexus.archiver.ArchiveFilterException;
import org.codehaus.plexus.archiver.ArchiveFinalizer;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.util.FilterSupport;
import org.codehaus.plexus.archiver.zip.AbstractZipUnArchiver;
import org.codehaus.plexus.archiver.zip.ZipEntry;
import org.codehaus.plexus.archiver.zip.ZipFile;
import org.codehaus.plexus.util.FileUtils;
public class AmpUnArchiver extends AbstractZipUnArchiver {
private static final String NATIVE_ENCODING = "native-encoding";
private String encoding = "UTF8";
private FilterSupport filterSupport;
private List finalizers;
private static String fileSeparator = System.getProperty("file.separator");
public void setArchiveFilters( List filters )
{
filterSupport = new FilterSupport( filters, getLogger() );
}
/**
* Sets the encoding to assume for file names and comments.
* <p/>
* <p>Set to <code>native-encoding</code> if you want your
* platform's native encoding, defaults to UTF8.</p>
*/
public void setEncoding( String encoding )
{
if ( NATIVE_ENCODING.equals( encoding ) )
{
encoding = null;
}
this.encoding = encoding;
}
private static Map<String,String> ampMapping = new HashMap<String,String>();
@Override
protected void execute()
throws ArchiverException, IOException
{
getLogger().info( "Expanding: " + getSourceFile() + " into " + getDestDirectory() );
ZipFile zf = null;
try
{
zf = new ZipFile( getSourceFile(), encoding );
Enumeration e = zf.getEntries();
String moduleId = getModuleId(zf);
// Based on the current AMP name creates the appropriate mapping to alfresco/module/<ampname>
createAmpMapping(moduleId);
while ( e.hasMoreElements() )
{
ZipEntry ze = (ZipEntry) e.nextElement();
if (!ze.getName().startsWith("META-INF"))
{
String fileInAmp = getAmpMapping(ze.getName());
extractFileIfIncluded( getSourceFile(), getDestDirectory(), zf.getInputStream( ze ), fileInAmp, new Date( ze.getTime() ), ze.isDirectory() );
}
}
runArchiveFinalizers();
getLogger().debug( "expand complete" );
}
catch ( IOException ioe )
{
throw new ArchiverException( "Error while expanding " + getSourceFile().getAbsolutePath(), ioe );
}
finally
{
if ( zf != null )
{
try
{
zf.close();
}
catch ( IOException e )
{
//ignore
}
}
}
}
private String getModuleId(ZipFile zf) throws IOException, ZipException, ArchiverException {
ZipEntry modulePropertiesEntry = zf.getEntry("module.properties");
Properties moduleProperties = new Properties();
moduleProperties.load(zf.getInputStream(modulePropertiesEntry));
String moduleId = moduleProperties.getProperty("module.id");
if(moduleId == null || "".equals(moduleId))
throw new ArchiverException("module.id property not found in module.properties");
return moduleId;
}
private String getAmpMapping(String name) {
if(name.startsWith("web/") && !name.startsWith("web/licenses"))
{
return name.substring(4);
}
for (Map.Entry<String, String> mapElelement : ampMapping.entrySet()) {
if(name.startsWith(mapElelement.getKey()))
{
String relativePath = "";
if((name.startsWith("config/")))
{
relativePath = name.substring(7);
}
else if((name.startsWith("lib/")))
{
relativePath = name.substring(4);
}
else
relativePath = FileUtils.removePath(name);
return mapElelement.getValue() + relativePath;
}
}
return "";
}
private void createAmpMapping(String moduleId) {
File zipFile = getSourceFile();
String ampName = zipFile.getName();
ampName = FileUtils.removeExtension(FileUtils.removePath(ampName));
ampName = ampName.substring(0, ampName.lastIndexOf('-'));
ampMapping.put("module.properties", "WEB-INF"+ fileSeparator +"classes" + fileSeparator +"alfresco" + fileSeparator +"module" + fileSeparator + moduleId + fileSeparator);
ampMapping.put("config", "WEB-INF"+fileSeparator+"classes"+ fileSeparator);
ampMapping.put("lib", "WEB-INF" + fileSeparator + "lib" +fileSeparator);
ampMapping.put("web"+ fileSeparator +"licenses", "WEB-INF" +fileSeparator);
}
private void extractFileIfIncluded( File sourceFile, File destDirectory, InputStream inputStream, String name,
Date time, boolean isDirectory )
throws IOException, ArchiverException
{
try
{
if ( filterSupport == null || filterSupport.include( inputStream, name ) )
{
extractFile( sourceFile, destDirectory, inputStream, name, time, isDirectory );
}
}
catch ( ArchiveFilterException e )
{
throw new ArchiverException( "Error verifying \'" + name + "\' for inclusion: " + e.getMessage(), e );
}
}
protected void extractFile( File srcF, File dir, InputStream compressedInputStream, String entryName,
Date entryDate, boolean isDirectory )
throws IOException
{
File f = null;
if (entryName != null && !"".equals(entryName))
f = FileUtils.resolveFile( dir, entryName );
else
return;
try
{
if ( !isOverwrite() && f.exists() && f.lastModified() >= entryDate.getTime() )
{
getLogger().debug( "Skipping " + f + " as it is up-to-date" );
return;
}
getLogger().debug( "expanding " + entryName + " to " + f );
// create intermediary directories - sometimes zip don't add them
File dirF = f.getParentFile();
if ( dirF != null )
{
dirF.mkdirs();
}
if ( isDirectory )
{
f.mkdirs();
}
else
{
byte[] buffer = new byte[1024];
int length;
FileOutputStream fos = null;
try
{
fos = new FileOutputStream( f );
while ( ( length = compressedInputStream.read( buffer ) ) >= 0 )
{
fos.write( buffer, 0, length );
}
fos.close();
fos = null;
}
finally
{
if ( fos != null )
{
try
{
fos.close();
}
catch ( IOException e )
{
// ignore
}
}
}
}
f.setLastModified( entryDate.getTime() );
}
catch ( FileNotFoundException ex )
{
getLogger().warn( "Unable to expand to file " + f.getPath() );
}
}
public void setArchiveFinalizers( List archiveFinalizers )
{
this.finalizers = archiveFinalizers;
}
protected void runArchiveFinalizers()
throws ArchiverException
{
if ( finalizers != null )
{
for ( Iterator it = finalizers.iterator(); it.hasNext(); )
{
ArchiveFinalizer finalizer = (ArchiveFinalizer) it.next();
finalizer.finalizeArchiveExtraction( this );
}
}
}
}

View File

@@ -0,0 +1,17 @@
<lifecycles>
<lifecycle>
<id>amp</id>
<phases>
<phase>
<id>package</id>
<executions>
<execution>
<goals>
<goal>amp</goal>
</goals>
</execution>
</executions>
</phase>
</phases>
</lifecycle>
</lifecycles>

View File

@@ -0,0 +1,53 @@
<component-set>
<components>
<component>
<role>org.apache.maven.artifact.handler.ArtifactHandler</role>
<role-hint>amp</role-hint>
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
<configuration>
<extension>amp</extension>
<type>zip</type>
<packaging>zip</packaging>
<language>java</language>
<addedToClasspath>true</addedToClasspath>
<includesDependencies>true</includesDependencies>
</configuration>
</component>
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>amp</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>
<process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
<test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
<package>org.alfresco.maven.plugin:maven-amp-plugin:amp</package>
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
</phases>
</configuration>
</component>
<component>
<role>org.codehaus.plexus.archiver.Archiver</role>
<role-hint>amp</role-hint>
<implementation>org.alfresco.plexus.archiver.AmpArchiver</implementation>
<instantiation-strategy>per-lookup</instantiation-strategy>
</component>
<!-- A amp requires an MMT like behaviour when unpacked in a war. The default assumption archiver role-hint = file-extension is used in
the maven-war-plugin, so we use role-hint=amp here to make unpacking seamless.
Not used byt the maven-amp-plugin which uses a plain zip unpacker
-->
<component>
<role>org.codehaus.plexus.archiver.UnArchiver</role>
<role-hint>amp</role-hint>
<implementation>org.alfresco.plexus.archiver.AmpUnArchiver</implementation>
</component>
</components>
</component-set>

View File

@@ -0,0 +1,37 @@
-----
Maven AMP Plugin Plexus Components
-----
AMP Lifecycle Mapping
This plugin provides support for <packaging>amp</packaging> type of projects. \
Lifecycle of an Alfresco modules is mapped in the file:
{{ ${site_tags_url}/${site_pom_artifactId}-${site_pom_version}/src/main/resources/META-INF/plexus/components.xml }}
This build produces an Alfresco compatible AMP as main build product. It supports (being derived from maven-war-plugin)
overlay of modules and transitive AMP dependency packing.
An AMP depending on one ore more AMP will package those AMP in the final product of the build:
overlays can be configured same as in {{ http://maven.apache.org/plugins/maven-war-plugin/overlays.html }}.
A plain zip UnArchiver is used for this overlay.
AMP -> WAR Unarchiver
The default UnArchiver (role-hint="amp") used by the default maven infrastructure for .amp files is a custom UnArchiver
which behaves as the MMT, unarchiving AMPs in the proper places as dictated by {{{http://wiki.alfresco.com/wiki/AMP_Files} Alfresco AMP convention}} .
This little component allows any plugin to manage .amp dependencies in case the maven-amp-plugin is declared with <extensions>true</extensions> in
the current POM, basically supporting AMPs in Maven with no need for custom external tools like MMT.
See {{ ${site_tags_url}/${site_pom_artifactId}-${site_pom_version}/src/main/resources/META-INF/plexus/components.xml }}
AMP Artifact Handler
Instructs maven which type of Archive is the AMP, providing info about its inclusion in the classpath or the fact that already contains
its dependencies.

View File

@@ -0,0 +1,55 @@
-----
Maven AMP Plugin
-----
Welcome to the Maven Alfresco AMP plugin home
You've reached the ({{ ${site_pom_url} }}) Maven Alfresco Extension archetype home page (version: ${site_pom_version})
Description
${site_pom_description}
References
Deployed at: {{ http://repository.sourcesense.com/maven2/org/alfresco/maven/plugin }}
Maven usage:
------------------------------------------
<dependency>
<groupId>${site_pom_groupId}</groupId>
<artifactId>${site_pom_artifactId}</artifactId>
<version>${site_pom_version}</version>
<!-- Used to have AMP lifecycle available -->
<extensions>true</extensions>
</dependency>
-------------------------------------------
using repository (either in POM or settings.xml) :
------------------------------------------
<repository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/maven2</url>
</repository>
-------------------------------------------
Quick usage
Create a project using the maven-alfresco-amp-archetype (see {{ http://repository.sourcesense.com/maven2-sites/maven-alfresco-amp-archetype }} ).

View File

@@ -0,0 +1,38 @@
<project>
<skin>
<groupId>org.apache.maven.skins</groupId>
<artifactId>maven-stylus-skin</artifactId>
<version>1.0</version>
</skin>
<poweredBy>
<logo name="Maven" href="http://maven.apache.org" img="http://maven.apache.org/images/logos/maven-feather.png"/>
<logo name="Alfresco - Open source ECM" img="http://alfresco.com/assets/images/icons/powered_by_alfresco.gif" href="http://www.sourcesense.com" />
</poweredBy>
<publishDate position="navigation-bottom" format="MM-dd-yy"/>
<bannerLeft>
<name>Maven AMP Plugin - v. ${project.version}</name>
<href>${site_site_url}</href>
</bannerLeft>
<body>
<links>
<item name="Maven" href="http://maven.apache.org/"/>
<item name="Apache" href="http://www.apache.org/"/>
</links>
<menu name="Plugin info">
<item name="Goals" href="plugin-info.html"/>
<item name="Components" href="components.html"/>
</menu>
<menu name="Used by">
<item name="Maven Alfresco AMP Archetype" href="http://repository.sourcesense.com/maven2-sites/maven-alfresco-amp-archetype"/>
</menu>
<menu name="See also">
<item name="Maven Alfresco Extension Archetype" href="http://repository.sourcesense.com/maven2-sites/maven-alfresco-extension-archetype"/>
</menu>
<menu ref="reports"/>
</body>
</project>

View File

@@ -3,198 +3,27 @@
<groupId>com.sourcesense.alfresco</groupId>
<artifactId>maven-alfresco-archetypes</artifactId>
<packaging>pom</packaging>
<version>1.0.5-SNAPSHOT</version>
<version>1.9.0-SNAPSHOT</version>
<name>Maven Alfresco Archetypes base project</name>
<description>
This project is meant to gather all commons configurations and settings between the two maven-alfresco-*-archetypes, i.e.
maven-alfresco-extension-archetype and maven-alfresco-amp-archetype
This project is meant to gather all commons configurations and settings between the two maven-alfresco-*-archetypes, i.e. maven-alfresco-extension-archetype and maven-alfresco-amp-archetype
</description>
<url>${site.url}</url>
<issueManagement>
<system>Google Code</system>
<url>http://code.google.com/p/maven-alfresco-archetypes/issues/list</url>
</issueManagement>
<organization>
<name>Sourcesense</name>
<url>http://www.sourcesense.com</url>
</organization>
<url>${project.artifactId}</url>
<parent>
<groupId>org.alfresco</groupId>
<artifactId>maven-alfresco-lifecycle</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modules>
<module>maven-alfresco-amp-archetype</module>
<module>maven-alfresco-extension-archetype</module>
</modules>
<properties>
<svn.base.url>https://maven-alfresco-archetypes.googlecode.com/svn</svn.base.url>
<svn.url>${svn.base.url}/trunk/${artifactId}</svn.url>
<svn.tags.url>${svn.base.url}/tags</svn.tags.url>
<site.url>https://repository.sourcesense.com/maven2-sites/${pom.artifactId}</site.url>
<!-- These redundancies are due to filtering issues of Maven. See here http://maven.apache.org/plugins/maven-site-plugin/usage.html -->
<site_pom_description>${pom.description}</site_pom_description>
<site_pom_url>${pom.organization.url}</site_pom_url>
<site_pom_groupId>${pom.groupId}</site_pom_groupId>
<site_pom_artifactId>${pom.artifactId}</site_pom_artifactId>
<site_pom_version>${pom.version}</site_pom_version>
<site_tags_url>${svn.tags.url}</site_tags_url>
<site_site_url>${site.url}</site_site_url>
</properties>
<scm>
<developerConnection>scm:svn:https://maven-alfresco-archetypes.googlecode.com/svn/trunk/maven-alfresco-archetypes</developerConnection>
<url>https://maven-alfresco-archetypes.googlecode.com/svn/trunk/maven-alfresco-archetypes</url>
</scm>
<repositories>
<repository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/maven2</url>
</repository>
<!-- Enable in case of apache snapshot deps -->
<repository>
<id>snapshots.apache</id>
<url>http://people.apache.org/repo/m2-snapshot-repository</url>
<snapshots>
<enabled />
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories>
<developers>
<developer>
<id>g.columbro</id>
<name>Gabriele Columbro</name>
<email>g.columbro@sourcesense.com</email>
<roles>
<role>Alfresco Architect</role>
<role>Developer</role>
</roles>
<organization>Sourcesense</organization>
<organizationUrl>http://www.sourcesense.com</organizationUrl>
</developer>
</developers>
<mailingLists>
<mailingList>
<name>Sourcesense Alfresco Dev Mailing list</name>
<subscribe>alfresco-dev-subscribe@lists.sourcesense.com</subscribe>
<unsubscribe>alfresco-dev-unsubscribe@lists.sourcesense.com</unsubscribe>
<post>alfresco-dev@lists.sourcesense.com</post>
<!-- We need an archive!!! -->
<!--<archive>http://mail-archives.wakaleo.com/modmbox/dev/</archive>-->
</mailingList>
</mailingLists>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-webdav</artifactId>
<version>1.0-beta-3</version>
</extension>
</extensions>
<plugins>
<plugin>
<artifactId>maven-archetype-plugin</artifactId>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>announcement-generate</goal>
</goals>
<id>announcement-generate</id>
</execution>
<execution>
<goals>
<goal>announcement-mail</goal>
</goals>
<id>announcement-mail</id>
</execution>
</executions>
<!-- Automatically notifies the list when release is done. Please supply username and password in the command line -->
<configuration>
<smtpHost>mail.sourcesense.com</smtpHost>
<smtpPort implementation="java.lang.Integer">25</smtpPort>
<toAddresses>
<!--
<toAddress implementation="java.lang.String">sysadmin@sourcesense.com</toAddress>
<toAddress implementation="java.lang.String">alfresco@sourcesense.com</toAddress>
<toAddress implementation="java.lang.String">alfresco-dev@lists.sourcesense.com</toAddress>
<toAddress implementation="java.lang.String">users@maven.apache.org</toAddress>
<toAddress implementation="java.lang.String">announce@maven.apache.org</toAddress>
-->
<toAddress implementation="java.lang.String">g.columbro@sourcesense.com</toAddress>
</toAddresses>
<username>${smtp.username}</username>
<password>${smtp.password}</password>
<fromDeveloperId>g.columbro</fromDeveloperId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-9</version>
<configuration>
<!-- useEditMode>true</useEditMode>-->
<preparationGoals>clean package</preparationGoals>
<goals>deploy site-deploy</goals>
<tagBase>${svn.tags.url}</tagBase>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-clover-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>changes-report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>changelog-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>taglist-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<distributionManagement>
<repository>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2</url>
</repository>
<site>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2-sites/${pom.artifactId}</url>
</site>
</distributionManagement>
</project>

View File

@@ -1,15 +1,16 @@
<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">
<parent>
<artifactId>maven-plugins</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<version>8</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.alfresco.maven.plugin</groupId>
<artifactId>maven-amp-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>Alfresco AMP Plugin</name>
<version>3.0.1-SNAPSHOT</version>
<parent>
<groupId>org.alfresco</groupId>
<artifactId>maven-alfresco-lifecycle</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<description>
This plugin defines a lifecycle for Alfresco ECM Modules packaging (.amp), handles AMP transitive dependencies from AMP and WAR projects,
providing a more enterprise oriented support alternative to the Alfresco MMT (module management tool) usage. It is used by
@@ -17,18 +18,8 @@
AMPs and WARs. It is a modification of the org.apache.maven.plugins:maven-war-plugin of which it uses the whole core infrastructure. See
${site.url} for more info
</description>
<url>${site.url}</url>
<prerequisites>
<maven>2.0.8</maven>
</prerequisites>
<issueManagement>
<system>GForge</system>
<url>https://forge.alfresco.com/tracker/?group_id=121</url>
</issueManagement>
<url>${project.artifactId}</url>
<properties>
<svn.url>https://maven-alfresco-archetypes.googlecode.com/svn/trunk/plugins/maven-amp-plugin</svn.url>
<svn.tags.url>https://maven-alfresco-archetypes.googlecode.com/svn/tags</svn.tags.url>
<site.url>https://repository.sourcesense.com/maven2-sites/${pom.artifactId}</site.url>
<site_pom_description>${pom.description}</site_pom_description>
<site_pom_url>${pom.url}</site_pom_url>
<site_pom_groupId>${pom.groupId}</site_pom_groupId>
@@ -38,12 +29,12 @@
</properties>
<developers>
<developer>
<id>mindthegab</id>
<id>columbro</id>
<name>Gabriele Columbro</name>
<email>g.columbro@sourcesense.com</email>
<email>gabriele.columbro@alfresco.com</email>
<roles />
<organization>Sourcesense</organization>
<organizationUrl>http://www.sourcesense.com</organizationUrl>
<organization>Alfresco</organization>
<organizationUrl>http://www.alfresco.com</organizationUrl>
</developer>
<developer>
<id>rdanner</id>
@@ -53,62 +44,6 @@
</developer>
</developers>
<scm>
<developerConnection>scm:svn:https://forge.alfresco.com/svn/maven4alfresco/amp-plugin/tags/maven-amp-plugin-3.0.0</developerConnection>
<url>https://forge.alfresco.com/svn/maven4alfresco/amp-plugin/tags/maven-amp-plugin-3.0.0</url>
<connection>scm:svn:https://forge.alfresco.com/svn/maven4alfresco/amp-plugin/tags/maven-amp-plugin-3.0.0</connection>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<!-- Automatically notifies the list when release is done. Please supply username and password in the command line -->
<configuration>
<smtpHost>mail.sourcesense.com</smtpHost>
<smtpPort implementation="java.lang.Integer">25</smtpPort>
<toAddresses>
<toAddress implementation="java.lang.String">sysadmin@sourcesense.com</toAddress>
<toAddress implementation="java.lang.String">alfresco@sourcesense.com</toAddress>
<toAddress implementation="java.lang.String">alfresco-dev@lists.sourcesense.com</toAddress>
<toAddress implementation="java.lang.String">users@maven.apache.org</toAddress>
<toAddress implementation="java.lang.String">announce@maven.apache.org</toAddress>
</toAddresses>
<username>${smtp.username}</username>
<password>${smtp.password}</password>
<fromDeveloperId>mindthegab</fromDeveloperId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-5</version>
<configuration>
<!-- useEditMode>true</useEditMode>-->
<!-- dryRun>true</dryRun-->
<preparationGoals>clean package</preparationGoals>
<goals>deploy site:site site:deploy changes:announcement-mail</goals>
<tagBase>${svn.tags.url}</tagBase>
<arguments>-Dgpg.skip=true</arguments>
</configuration>
</plugin>
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
@@ -148,19 +83,4 @@
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>ss-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2</url>
</repository>
<snapshotRepository>
<id>ss-public</id>
<name>SS public repo</name>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2-snapshots</url>
</snapshotRepository>
<site>
<id>ss-site-public</id>
<url>scp://repository.sourcesense.com/var/www/repository.sourcesense.com/maven2-sites/${pom.artifactId}</url>
</site>
</distributionManagement>
</project>

View File

@@ -4,12 +4,15 @@
<artifactId>maven-nosnapshot-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>0.0.5-SNAPSHOT</version>
<name>Custom version manipulator Maven Plugin. It's non invasive and puts modified versions in configurable pom properties</name>
<url>http://maven.apache.org</url>
<scm>
<developerConnection>scm:svn:https://maven-alfresco-archetypes.googlecode.com/svn/trunk/plugins/maven-nosnapshot-plugin</developerConnection>
<url>https://maven-alfresco-archetypes.googlecode.com/svn/trunk/plugins/maven-nosnapshot-plugin</url>
</scm>
<name>Custom version manipulator Maven Plugin</name>
<description>It's non invasive and puts modified versions in configurable pom properties</description>
<url>${project.artifactId}</url>
<parent>
<groupId>org.alfresco</groupId>
<artifactId>maven-alfresco-lifecycle</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
@@ -34,32 +37,5 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<!-- useEditMode>true</useEditMode>-->
<preparationGoals>clean</preparationGoals>
<goals>deploy</goals>
<tagBase>https://maven-alfresco-archetypes.googlecode.com/svn/tags</tagBase>
<useEditMode>true</useEditMode>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>ss-nexus</id>
<url>http://repository.sourcesense.com/nexus/content/repositories/releases</url>
</repository>
</distributionManagement>
</project>

221
pom.xml Normal file
View File

@@ -0,0 +1,221 @@
<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>
<groupId>org.alfresco</groupId>
<artifactId>maven-alfresco-lifecycle</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>Maven Alfresco Lifecycle support base project</name>
<parent>
<groupId>com.sourcesense.maven</groupId>
<artifactId>maven-calm</artifactId>
<version>1.0-beta-21</version>
</parent>
<description>
This project is meant to gather all commons configurations, plugins and archetypes
for the full Maven Alfresco lifecycle support
</description>
<issueManagement>
<system>Google Code</system>
<url>http://code.google.com/p/maven-alfresco-archetypes/issues/list</url>
</issueManagement>
<organization>
<name>Sourcesense</name>
<url>http://www.sourcesense.com</url>
</organization>
<modules>
<module>maven-alfresco-archetypes</module>
<module>plugins/maven-amp-plugin</module>
<module>plugins/maven-nosnapshot-plugin</module>
</modules>
<properties>
<svn.base.url>https://maven-alfresco-archetypes.googlecode.com/svn</svn.base.url>
<svn.url>${svn.base.url}/trunk</svn.url>
<svn.tags.url>${svn.base.url}/tags</svn.tags.url>
<site.url>http://repository.sourcesense.com/nexus/content/repositories/alfresco.public.sites/${pom.artifactId}</site.url>
<!--
These redundancies are due to filtering issues of Maven. See here
http://maven.apache.org/plugins/maven-site-plugin/usage.html
-->
<site_pom_description>${pom.description}</site_pom_description>
<site_pom_url>${pom.organization.url}</site_pom_url>
<site_pom_groupId>${pom.groupId}</site_pom_groupId>
<site_pom_artifactId>${pom.artifactId}</site_pom_artifactId>
<site_pom_version>${pom.version}</site_pom_version>
<site_tags_url>${svn.tags.url}</site_tags_url>
<site_site_url>${site.url}</site_site_url>
</properties>
<scm>
<connection>scm:svn:${svn.url}</connection>
<developerConnection>scm:svn:${svn.url}</developerConnection>
<url>${svn.url}</url>
</scm>
<repositories>
<repository>
<id>ss-public-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public</url>
</repository>
<repository>
<id>ss-public-snapshots-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public-snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>ss-public-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public</url>
</pluginRepository>
<pluginRepository>
<id>ss-public-snapshots-mirror</id>
<url>http://repository.sourcesense.com/nexus/content/groups/public-snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
<developers>
<developer>
<id>columbro</id>
<name>Gabriele Columbro</name>
<email>gabriele.columbro@alfresco.com</email>
<roles>
<role>Founder</role>
<role>Alfresco Solution Engineer</role>
<role>Developer</role>
</roles>
<organization>Alfresco</organization>
<organizationUrl>http://www.alfresco.com</organizationUrl>
</developer>
<developer>
<id>maurizio@session.it</id>
<name>Maurizio Pillitu</name>
<email>m.pillitu@sourcesense.com</email>
<organization>Sourcesense</organization>
<organizationUrl>http://www.sourcesense.com</organizationUrl>
<roles>
<role>Solution architect</role>
<role>Agile guru</role>
<role>Maven Calm Expert</role>
</roles>
</developer>
</developers>
<mailingLists>
<mailingList>
<name>Maven Alfresco Google Group</name>
<archive>http://groups.google.com/group/maven-alfresco</archive>
<subscribe>http://groups.google.com/group/maven-alfresco/subscribe</subscribe>
</mailingList>
</mailingLists>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>announcement-generate</goal>
</goals>
<id>announcement-generate</id>
</execution>
<execution>
<goals>
<goal>announcement-mail</goal>
</goals>
<id>announcement-mail</id>
</execution>
</executions>
<!--
Automatically notifies the list when release is done. Please supply
username and password in the command line
-->
<!--
NB: Define smtp.* properties either in command line or in
settings.xml
-->
<configuration>
<smtpHost>${smtp.server}</smtpHost>
<smtpPort implementation="java.lang.Integer">${smtp.port}</smtpPort>
<toAddresses>
<toAddress implementation="java.lang.String">columbro@gmail.com</toAddress>
</toAddresses>
<username>${smtp.username}</username>
<password>${smtp.password}</password>
<fromDeveloperId>columbro</fromDeveloperId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<!-- useEditMode>true</useEditMode>-->
<preparationGoals>clean package</preparationGoals>
<goals>deploy site-deploy changes:announcement-generate
changes:announcement-email site-deploy</goals>
<tagBase>${svn.tags.url}</tagBase>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>report-only</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-changes-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>changes-report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>changelog-maven-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<distributionManagement>
<repository>
<id>ss-public</id>
<url>http://repository.sourcesense.com/nexus/content/repositories/alfresco.public.releases</url>
</repository>
<snapshotRepository>
<id>ss-public-snapshots</id>
<url>http://repository.sourcesense.com/nexus/content/repositories/alfresco.public.snapshots</url>
</snapshotRepository>
<site>
<id>ss-public-sites</id>
<url>http://repository.sourcesense.com/nexus/content/repositories/alfresco.public.sites/${project.artifactId}</url>
</site>
</distributionManagement>
</project>

13
src/changes/changes.xml Normal file
View File

@@ -0,0 +1,13 @@
<document>
<properties>
<title>Maven Alfresco Extension archetype</title>
<author email="g.columbro@sourcesense.com">Gabriele Columbro</author>
</properties>
<body>
<release version="1.9.0" date="2009-11-03" description="Complete refactoring of the full support in one multimodule project">
<action dev="columbro" type="add">
Added this wrapper project to group all Maven Alfresco plugins and archetype useful for the Maven Alfresco Lifecycle support
</action>
</release>
</body>
</document>

31
src/site/site.xml Normal file
View File

@@ -0,0 +1,31 @@
<project>
<skin>
<groupId>org.apache.maven.skins</groupId>
<artifactId>maven-stylus-skin</artifactId>
<version>1.0</version>
</skin>
<poweredBy>
<logo name="Maven" href="http://maven.apache.org" img="http://maven.apache.org/images/logos/maven-feather.png"/>
<logo name="Alfresco - Open source ECM" img="http://alfresco.com/assets/images/icons/powered_by_alfresco.gif" href="http://www.sourcesense.com" />
</poweredBy>
<publishDate position="navigation-bottom" format="MM-dd-yy"/>
<bannerLeft>
<name>Maven Alfresco Lifecycle support - v. ${project.version}</name>
<href>${site_site_url}</href>
<src>images/logo_noclaim.png</src>
</bannerLeft>
<body>
<links>
<item name="Maven" href="http://maven.apache.org/"/>
<item name="Apache" href="http://www.apache.org/"/>
<item name="Alfresco" href="http://www.afresco.com/"/>
</links>
<menu ref="modules">
</menu>
<menu ref="reports" />
</body>
</project>