From 501aeb9ee89c60248794d2d7ab91c81d589654ff Mon Sep 17 00:00:00 2001 From: antelder Date: Mon, 20 Jun 2011 10:14:14 +0000 Subject: [maven-release-plugin] copy for tag tuscany-bundle-plugin-1.0.8 git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1137585 13f79535-47bb-0310-9956-ffa450edef68 --- .../tags/tuscany-bundle-plugin-1.0.8/LICENSE | 205 +++ .../tags/tuscany-bundle-plugin-1.0.8/NOTICE | 6 + .../tags/tuscany-bundle-plugin-1.0.8/README | 72 + .../tags/tuscany-bundle-plugin-1.0.8/RELEASE_NOTES | 56 + .../tags/tuscany-bundle-plugin-1.0.8/pom.xml | 242 +++ .../bundle/plugin/AggregatedBundleActivator.java | 56 + .../maven/bundle/plugin/ArtifactAggregation.java | 72 + .../maven/bundle/plugin/ArtifactManifest.java | 37 + .../maven/bundle/plugin/ArtifactMember.java | 61 + .../maven/bundle/plugin/BundleAggregatorMojo.java | 259 +++ .../tuscany/maven/bundle/plugin/BundleUtil.java | 640 +++++++ .../bundle/plugin/BundlesMetaDataBuildMojo.java | 1465 +++++++++++++++ .../tuscany/maven/bundle/plugin/Extension.java | 60 + .../tuscany/maven/bundle/plugin/Feature.java | 59 + .../tuscany/maven/bundle/plugin/HeaderParser.java | 331 ++++ .../bundle/plugin/ModuleBundlesBuildMojo.java | 1338 ++++++++++++++ .../maven/bundle/plugin/OSGIArtifactVersion.java | 219 +++ .../bundle/plugin/ThirdPartyBundleBuildMojo.java | 152 ++ .../plugin/eclipse/AbstractIdeSupportMojo.java | 1150 ++++++++++++ .../plugin/eclipse/EclipseClasspathWriter.java | 635 +++++++ .../maven/plugin/eclipse/EclipseCleanMojo.java | 208 +++ .../maven/plugin/eclipse/EclipsePlugin.java | 1877 ++++++++++++++++++++ .../maven/plugin/eclipse/EclipseProjectWriter.java | 357 ++++ .../tuscany/maven/plugin/eclipse/Messages.java | 68 + .../apache/tuscany/maven/bundle/plugin/LICENSE.txt | 205 +++ .../apache/tuscany/maven/bundle/plugin/NOTICE.txt | 5 + .../maven/plugin/eclipse/messages.properties | 81 + 27 files changed, 9916 insertions(+) create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/LICENSE create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/NOTICE create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/README create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/RELEASE_NOTES create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/pom.xml create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/AggregatedBundleActivator.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleAggregatorMojo.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundlesMetaDataBuildMojo.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Extension.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Feature.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/HeaderParser.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/AbstractIdeSupportMojo.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseClasspathWriter.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseCleanMojo.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipsePlugin.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseProjectWriter.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/Messages.java create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/LICENSE.txt create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/NOTICE.txt create mode 100644 maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/plugin/eclipse/messages.properties (limited to 'maven-plugins') diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/LICENSE b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/LICENSE new file mode 100644 index 0000000000..8aa906c321 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/LICENSE @@ -0,0 +1,205 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/NOTICE b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/NOTICE new file mode 100644 index 0000000000..444110438a --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/NOTICE @@ -0,0 +1,6 @@ +Apache Tuscany Maven Bundle Plugin +Copyright (c) 2005 - 2009 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/README b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/README new file mode 100644 index 0000000000..74b16f3266 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/README @@ -0,0 +1,72 @@ +A Maven plugin used by the Tuscany SCA project that can build an OSGi bundle for a +project's third-party dependencies, generate a directory containing OSGi bundles +for all the project's module dependencies, and create Eclipse project files +(.project, .classpath etc) to configure the Eclipse PDE environment for a project. + +To build, from the top maven-bundle-plugin run maven: + +mvn + +or once all the dependencies have been downloaded and a succesful build run use: + +mvn clean install -o + +So as to avoid the Tuscany SCA project using SNAPSHOT dependencies any changes +to this module should be released and the Tuscany SCA project updated to use +the newly released version. + +To release this module: + +mvn release:prepare + +followed by: + +mvn release:perform + +That will automatically create an SVN tag from the release, update the version +numbers in the pom.xml files in the trunk and tag, and deploy the artifacts to the +staging repository defined by the in your Maven settings.xml. +While running it will prompt you for the names for the tag, release version etc. + +Note: there seem to be issues with having empty folders in the src tree which causes + release:prepare to fail, not sure why but deleting the empty folder fixes the + problem. You can do "mvn release:rollback" to undo a failed release. + +In your maven settings.xml file you must have a server defined named "apache.releases", +and a profile named "release". For example: + + + ... + + apache.releases + antelder + \ant\id_dsa + xxx + 775 + 664 + + + + + ... + + release + + ... + apache.releases::default::scp://people.apache.org/home/antelder/public_html/tuscany/maven-bundle-plugin-1.0 + + + + +Call a vote to release the module, eg: http://apache.markmail.org/message/6jnlfxbx7uklt5nv + +After a successful vote copy the staging artifacts to the live repository, eg: + +cp -p -v -R maven-bundle-plugin-1.0/org/apache/tuscany/maven/plugins/ /x1/www/people.apache.org/repo/m2-ibiblio-rsync-repository/org/apache/tuscany/maven/plugins + + + + + + + diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/RELEASE_NOTES b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/RELEASE_NOTES new file mode 100644 index 0000000000..e30b357d2f --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/RELEASE_NOTES @@ -0,0 +1,56 @@ +Apache Tuscany Maven Bundle Plugin 1.0.8 Release Notes +====================================================== + +- TUSCANY-3861: Rename bundle plugin to be tuscany-bundle-plugin to conform to Maven naming. + +Apache Tuscany Maven Bundle Plugin 1.0.7 Release Notes +====================================================== + +- changes to generate metadata for extensions. + +Apache Tuscany Maven Bundle Plugin 1.0.6 Release Notes +====================================================== + +- TUSCANY-3457: maven-bundle-plugin filtering manually specified manifests +- Add new goal so that we can generate a single OSGi bundle from the modules + +Apache Tuscany Maven Bundle Plugin 1.0.5 Release Notes +====================================================== + +- Filter out system packages in export from non-bundle jars such as xerces, xalan or saxon to avoid package conflicts. + This now means Tuscany can be used with Apache Felix + +Apache Tuscany Maven Bundle Plugin 1.0.4 Release Notes +====================================================== + +- Add compile dependencies to the .classpath file if it doesn't supply any packages to the OSGi import. This maks this plugin more closer to the mvn eclipse:eclipse behavior. +- Exclude the project itself from the resolution so that it can be built offline +- Add support to include different versions of 3rd party jars into the distribution if it is omitted by a lower version in maven +- Check the partial attr to decide if the bundle needs to be required +- Don't generate Import-Package header for the 3rd party jars so that either local package is used if there are split packages +- Add the option to generate a gateway bundle that aggregates split packages and export them +- Fix svn:eol-style and svn:keywords properties for java/xml files +- Add import statement for the generated MF +- Upgrade to Equinox 3.5 + +Apache Tuscany Maven Bundle Plugin 1.0.3 Release Notes +====================================================== + +Apache Tuscany Maven Bundle Plugin 1.0.2 Release Notes +====================================================== + +Apache Tuscany Maven Bundle Plugin 1.0.1 Release Notes +====================================================== + +TUSCANY-2877: Introducing a generic Eclipse-BuddyPolicy header for the bundles generated from dependent artifacts would be helpful +TUSCANY-2876: In artifact aggrations, artifactMemebers is misspelled and may lead to error prone configurations +TUSCANY-2873: Wrapping of non-OSGi components creates versions that may makes no-sense +TUSCANY-2872: Maven Bundle Plugin throws NPE when a dependent non-OSGI jar has no manifest +r747530: Use the equinox as the osgi dependency + + + +Apache Tuscany Maven Bundle Plugin 1.0 Release Notes +==================================================== + +Initial release diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/pom.xml b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/pom.xml new file mode 100644 index 0000000000..cf313ccca5 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/pom.xml @@ -0,0 +1,242 @@ + + + + 4.0.0 + + org.apache + apache + 7 + + + org.apache.tuscany.sca + tuscany-bundle-plugin + maven-plugin + Apache Tuscany Maven OSGi Bundle Plugin + 1.0.8 + + + scm:svn:http://svn.apache.org/repos/asf/tuscany/maven-plugins/tags/tuscany-bundle-plugin-1.0.8 + scm:svn:https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags/tuscany-bundle-plugin-1.0.8 + scm:svn:https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags/tuscany-bundle-plugin-1.0.8 + + + + + release + + + + + true + maven-deploy-plugin + 2.4 + + ${deploy.altRepository} + true + + + + + maven-gpg-plugin + 1.0-alpha-4 + + + + sign + + + + + + + + + + + deploy + + deploy + + + org.apache.maven.plugins + maven-source-plugin + 2.0.4 + + + attach-sources + + jar + + + + + + + + + + + + org.apache.maven + maven-plugin-api + 2.0.8 + + + + org.apache.maven + maven-project + 2.0.8 + + + junit + junit + + + + + + org.apache.maven + maven-settings + 2.0.8 + + + + org.apache.maven + maven-artifact + 2.0.8 + + + + org.apache.maven + maven-model + 2.0.8 + + + + org.apache.maven.shared + maven-dependency-tree + 1.1 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.6 + + + + org.eclipse + osgi + 3.5.0.v20090520 + compile + + + + + + install + + + + src/main/resources + + + . + META-INF + true + + LICENSE + NOTICE + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + 1.5 + 1.5 + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.1 + + + + ${project.artifactId} + ${project.name} + The Apache Software Foundation + ${project.version} + ${project.name} + org.apache + The Apache Software Foundation + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.4.3 + + + **/*TestCase.java + + brief + false + once + -ea -Xmx256m + + + + + org.apache.maven.plugins + maven-release-plugin + 2.0-beta-8 + + https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags + false + clean install + deploy + -Prelease,deploy + true + + + + + + + + + + diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/AggregatedBundleActivator.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/AggregatedBundleActivator.java new file mode 100644 index 0000000000..64999cb309 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/AggregatedBundleActivator.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.maven.bundle.plugin; + +import java.util.ArrayList; +import java.util.List; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * A bundle activator that delegates to others + */ +public class AggregatedBundleActivator implements BundleActivator { + public static final String BUNDLE_ACTIVATOR_LIST = "Tuscany-Bundle-Activator-List"; + private List activators = new ArrayList(); + + public void start(BundleContext context) throws Exception { + String list = (String)context.getBundle().getHeaders().get(BUNDLE_ACTIVATOR_LIST); + if (list == null) { + return; + } + for (String cls : list.split(",")) { + Object i = context.getBundle().loadClass(cls).newInstance(); + if (i instanceof BundleActivator) { + ((BundleActivator)i).start(context); + activators.add((BundleActivator)i); + } + } + } + + public void stop(BundleContext context) throws Exception { + for (BundleActivator a : activators) { + a.stop(context); + } + + } + +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java new file mode 100644 index 0000000000..9abbe1ebd7 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.maven.artifact.Artifact; + +public class ArtifactAggregation { + private String symbolicName; + private String version; + private List artifactMembers = new ArrayList(); + private transient List artifacts = new ArrayList(); + + public List getArtifacts() { + return artifacts; + } + + public String getSymbolicName() { + return symbolicName; + } + + public void setSymbolicName(String symbolicName) { + this.symbolicName = symbolicName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List getArtifactMembers() { + return artifactMembers; + } + + public void setArtifactMembers(List artifacts) { + this.artifactMembers = artifacts; + } + + public String toString() { + return symbolicName + ";version=\"" + version + "\"\n" + artifactMembers; + } + + public boolean matches(Artifact artifact) { + for(ArtifactMember m: artifactMembers) { + if(m.matches(artifact)) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java new file mode 100644 index 0000000000..f6eca87c8e --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.maven.bundle.plugin; + +import java.io.File; + +/** + * + */ +public class ArtifactManifest extends ArtifactMember { + private File manifestFile; + + public File getManifestFile() { + return manifestFile; + } + + public void setManifestFile(File manifestFile) { + this.manifestFile = manifestFile; + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java new file mode 100644 index 0000000000..834ee7825e --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +import org.apache.maven.artifact.Artifact; + +public class ArtifactMember { + private String groupId; + private String artifactId; + private String version; + + 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 getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String toString() { + return groupId + ":" + artifactId + ":" + version; + } + + public boolean matches(Artifact artifact) { + return groupId.equals(artifact.getGroupId()) && (artifactId == null || artifactId.equals("") + || artifactId.equals("*") || artifactId.equals(artifact.getArtifactId())) + && (version == null || version.equals("") || version.equals("*") || version.equals(artifact.getVersion())); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleAggregatorMojo.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleAggregatorMojo.java new file mode 100644 index 0000000000..9c36ae34a2 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleAggregatorMojo.java @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.maven.bundle.plugin; + +import static org.apache.tuscany.maven.bundle.plugin.AggregatedBundleActivator.BUNDLE_ACTIVATOR_LIST; +import static org.apache.tuscany.maven.bundle.plugin.HeaderParser.merge; +import static org.osgi.framework.Constants.BUNDLE_ACTIVATOR; +import static org.osgi.framework.Constants.BUNDLE_CLASSPATH; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +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.tuscany.maven.bundle.plugin.HeaderParser.HeaderClause; + +/** + * @version $Rev$ $Date$ + * @goal aggregate-modules + * @phase process-resources + * @requiresDependencyResolution test + * @description Generate an aggregated bundle that contains all the modules and 3rd party jars + */ +public class BundleAggregatorMojo extends AbstractMojo { + /** + * Root directory. + * + * @parameter expression="${project.build.directory}/modules" + */ + private File rootDirectory; + + /** + * Aggregated bundle + * + * @parameter expression="${project.build.directory}/singlebundle/tuscany-bundle.jar" + */ + private File targetBundleFile; + + /** + * @parameter default-value== "org.apache.tuscany.sca.bundle"; + */ + private String bundleName = "org.apache.tuscany.sca.bundle"; + + /** + * @parameter default-value== "2.0.0"; + */ + private String bundleVersion = "2.0.0"; + + // private static final Logger logger = Logger.getLogger(BundleAggregatorMojo.class.getName()); + + public static void aggregateBundles(Log log, + File root, + File[] files, + File targetBundleFile, + String bundleName, + String bundleVersion) throws Exception { + targetBundleFile.getParentFile().mkdirs(); + Set jarFiles = new HashSet(); + List manifests = new ArrayList(); + for (File child : files) { + try { + Manifest manifest = null; + if (child.isDirectory()) { + File mf = new File(child, "META-INF/MANIFEST.MF"); + if (mf.isFile()) { + FileInputStream is = new FileInputStream(mf); + manifest = new Manifest(is); + is.close(); + if (manifest != null) { + String classpath = manifest.getMainAttributes().getValue("Bundle-ClassPath"); + if (classpath != null) { + for (HeaderClause clause : HeaderParser.parse(classpath)) { + if (clause.getValue().equals(".")) { + continue; + } else { + jarFiles.add(new File(child, clause.getValue())); + } + } + } else { + // + } + } + } + } else if (child.getName().endsWith(".jar")) { + JarFile jar = new JarFile(child); + manifest = jar.getManifest(); + jar.close(); + if (manifest != null) { + String id = manifest.getMainAttributes().getValue("Bundle-SymbolicName"); + if (id != null && (id.startsWith("org.eclipse.") || id + .startsWith("org.apache.tuscany.sca.gateway"))) { + manifest = null; + } else { + jarFiles.add(child); + } + } + } + if (manifest == null) { + continue; + } + + log.debug("Bundle file: " + child); + manifests.add(manifest); + } catch (Exception e) { + throw e; + } + } + Manifest merged = new Manifest(); + Attributes attributes = merged.getMainAttributes(); + attributes.putValue("Manifest-Version", "1.0"); + attributes.putValue("Bundle-ManifestVersion", "2"); + attributes.putValue("Bundle-License", "http://www.apache.org/licenses/LICENSE-2.0.txt"); + attributes.putValue("Bundle-DocURL", "http://www.apache.org/"); + attributes.putValue("Bundle-RequiredExecutionEnvironment", "J2SE-1.5,JavaSE-1.6"); + attributes.putValue("Bundle-Vendor", "The Apache Software Foundation"); + attributes.putValue("Bundle-Version", bundleVersion); + attributes.putValue("Bundle-SymbolicName", bundleName); + attributes.putValue("SCA-Version", "1.1"); + attributes.putValue("Bundle-Name", bundleName); + // attributes.putValue("Bundle-ActivationPolicy", "lazy"); + for (Manifest mf : manifests) { + for (Map.Entry e : mf.getMainAttributes().entrySet()) { + Attributes.Name key = (Attributes.Name)e.getKey(); + String name = key.toString(); + String oldValue = attributes.getValue(name); + String value = (String)e.getValue(); + if (name.equals("Export-Package") || name.equals("Import-Package") + || name.equals("Require-Bundle") + || name.equals("DynamicImport-Package") + || name.equals("Bundle-ClassPath") + || name.equals("Private-Package") + || name.equals("Bundle-Description")) { + attributes.putValue(name, merge(oldValue, value)); + } else if (name.equals(BUNDLE_ACTIVATOR)) { + oldValue = attributes.getValue(BUNDLE_ACTIVATOR_LIST); + attributes.putValue(BUNDLE_ACTIVATOR_LIST, merge(oldValue, value)); + } else if (name.equals("Main-Class") || name.startsWith("Eclipse-") || name.startsWith("Bundle-")) { + // Ignore + } else { + // Ignore + // attributes.putValue(name, value); + } + } + } + log.info("Generating " + targetBundleFile); + attributes.putValue(BUNDLE_ACTIVATOR, AggregatedBundleActivator.class.getName()); + String bundleClassPath = attributes.getValue(BUNDLE_CLASSPATH); + bundleClassPath = merge(bundleClassPath, "."); + for (File f : jarFiles) { + bundleClassPath = merge(bundleClassPath, f.getName()); + } + attributes.putValue(BUNDLE_CLASSPATH, bundleClassPath); + + FileOutputStream fos = new FileOutputStream(targetBundleFile); + JarOutputStream bundle = new JarOutputStream(fos, merged); + + for (File file : jarFiles) { + log.info("Adding " + file); + addEntry(bundle, file.getName(), file); + } + + String classFile = AggregatedBundleActivator.class.getName().replace(".", "/") + ".class"; + InputStream classStream = BundleAggregatorMojo.class.getClassLoader().getResourceAsStream(classFile); + addEntry(bundle, classFile, classStream); + bundle.close(); + } + + private static void addDir(JarOutputStream jos, File root, File dir) throws IOException, FileNotFoundException { + for (File file : dir.listFiles()) { + if (file.isDirectory()) { + addDir(jos, root, file); + } else if (file.isFile()) { + // getLog().info(file.toString()); + String uri = root.toURI().relativize(file.toURI()).toString(); + if ("META-INF/MANIFEST.MF".equals(uri)) { + continue; + } + addEntry(jos, uri, file); + } + } + } + + private static void addEntry(JarOutputStream jos, String name, File file) throws IOException { + FileInputStream in = new FileInputStream(file); + addEntry(jos, name, in); + } + + private static final byte[] buf = new byte[4096]; + + private static void addEntry(JarOutputStream jos, String name, InputStream in) throws IOException { + ZipEntry entry = new ZipEntry(name); + jos.putNextEntry(entry); + for (;;) { + int len = in.read(buf); + if (len > 0) { + jos.write(buf, 0, len); + } else { + break; + } + } + in.close(); + jos.closeEntry(); + } + + private static void generateJar(File root, File jar, Manifest mf) throws IOException { + FileOutputStream fos = new FileOutputStream(jar); + JarOutputStream jos = mf != null ? new JarOutputStream(fos, mf) : new JarOutputStream(fos); + addDir(jos, root, root); + jos.close(); + } + + public void execute() throws MojoExecutionException, MojoFailureException { + try { + Log log = getLog(); + if (!rootDirectory.isDirectory()) { + log.warn(rootDirectory + " is not a directory"); + return; + } + File[] files = rootDirectory.listFiles(); + aggregateBundles(log, rootDirectory, files, targetBundleFile, bundleName, bundleVersion); + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java new file mode 100644 index 0000000000..8f280e59e9 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java @@ -0,0 +1,640 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.maven.bundle.plugin; + +import static org.osgi.framework.Constants.BUNDLE_CLASSPATH; +import static org.osgi.framework.Constants.BUNDLE_MANIFESTVERSION; +import static org.osgi.framework.Constants.BUNDLE_NAME; +import static org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME; +import static org.osgi.framework.Constants.BUNDLE_VERSION; +import static org.osgi.framework.Constants.DYNAMICIMPORT_PACKAGE; +import static org.osgi.framework.Constants.EXPORT_PACKAGE; +import static org.osgi.framework.Constants.IMPORT_PACKAGE; + +import java.io.BufferedInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.Version; + +/** + * Common functions used by the plugin. + * + * @version $Rev$ $Date$ + */ +public final class BundleUtil { + static final String META_INF_SERVICES = "META-INF.services;partial=true;mandatory:=partial"; + private final static Logger logger = Logger.getLogger(BundleUtil.class.getName()); + /** + * Returns the name of a bundle, or null if the given file is not a bundle. + * + * @param file + * @return + * @throws IOException + */ + public static String getBundleSymbolicName(File file) throws IOException { + Manifest manifest = getManifest(file); + return getBundleSymbolicName(manifest); + } + + static String getBundleSymbolicName(Manifest manifest) { + if (manifest == null) { + return null; + } + + String bundleName = manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME); + if (bundleName == null) { + return bundleName; + } + int sc = bundleName.indexOf(';'); + if (sc != -1) { + bundleName = bundleName.substring(0, sc); + } + return bundleName; + } + + static Manifest getManifest(File file) throws IOException { + if (!file.exists()) { + return null; + } + Manifest manifest = null; + if (file.isDirectory()) { + File mf = new File(file, "META-INF/MANIFEST.MF"); + if (mf.isFile()) { + InputStream is = new FileInputStream(mf); + manifest = new Manifest(new FileInputStream(mf)); + is.close(); + } + } else { + JarFile jar = new JarFile(file, false); + manifest = jar.getManifest(); + jar.close(); + } + return manifest; + } + + /** + * Generate a Bundle manifest for a set of JAR files. + * + * @param jarFiles + * @param name + * @param symbolicName + * @param version + * @param dir + * @return + * @throws IllegalStateException + */ + static Manifest libraryManifest(Set jarFiles, String name, String symbolicName, String version, String dir) + throws IllegalStateException { + return libraryManifest(jarFiles, name, symbolicName, version, dir, null, null); + } + /** + * Generate a Bundle manifest for a set of JAR files. + * + * @param jarFiles + * @param name + * @param symbolicName + * @param version + * @param dir + * @param buddyPolicy + * @param env + * @return + * @throws IllegalStateException + */ + static Manifest libraryManifest(Set jarFiles, String name, String symbolicName, String version, String dir, String buddyPolicy, String env) + throws IllegalStateException { + try { + + // List exported packages and bundle classpath entries + StringBuffer classpath = new StringBuffer(); + Set exportedPackages = new HashSet(); + for (File jarFile : jarFiles) { + if (!jarFile.exists()) { + logger.warning(jarFile + " doesn't exist."); + continue; + } + addPackages(jarFile, exportedPackages, version); + if (dir != null) { + classpath.append(dir).append("/"); + } + classpath.append(jarFile.getName()); + classpath.append(","); + } + + if (env == null) { + env = "JavaSE-1.6"; + } + Set sysPackages = getSystemPackages(env); + + // Generate export-package and import-package declarations + StringBuffer exports = new StringBuffer(); + StringBuffer imports = new StringBuffer(); + Set pkgs = new HashSet(); + for (String export : exportedPackages) { + String packageName = packageName(export); + if (!pkgs.contains(packageName) && !sysPackages.contains(packageName)) { + // Add corresponding import declaration + if (!"META-INF.services".equals(packageName)) { + imports.append(export); + imports.append(','); + } + pkgs.add(packageName); + exports.append(export); + exports.append(','); + } else { + logger.warning("Duplicate or system package skipped: " + export); + } + } + + // Create a manifest + Manifest manifest = new Manifest(); + Attributes attributes = manifest.getMainAttributes(); + attributes.putValue("Manifest-Version", "1.0"); + attributes.putValue(BUNDLE_MANIFESTVERSION, "2"); + attributes.putValue(BUNDLE_SYMBOLICNAME, symbolicName); + attributes.putValue(BUNDLE_NAME, name); + attributes.putValue(BUNDLE_VERSION, version); + // The system bundle has incomplete javax.transaction* packages exported + attributes.putValue(DYNAMICIMPORT_PACKAGE, "javax.transaction;version=\"1.1\",javax.transaction.xa;version=\"1.1\",*"); + if (buddyPolicy != null && buddyPolicy.length() > 0){ + attributes.putValue("Eclipse-BuddyPolicy", buddyPolicy); + } + if (exports.length() > 1) { + attributes.putValue(EXPORT_PACKAGE, exports.substring(0, exports.length() - 1)); + } + /* + if (imports.length() > 1) { + attributes.putValue(IMPORT_PACKAGE, imports.substring(0, imports.length() - 1)); + } + */ + if (classpath.length() > 1) { + attributes.putValue(BUNDLE_CLASSPATH, classpath.substring(0, classpath.length() - 1)); + } + + return manifest; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + /** + * Write a bundle manifest. + * + * @param manifest + * @param out + * @throws IOException + */ + static void write(Manifest manifest, OutputStream out) throws IOException { + DataOutputStream dos = new DataOutputStream(out); + Attributes attributes = manifest.getMainAttributes(); + write(attributes, "Manifest-Version", dos); + write(attributes, BUNDLE_MANIFESTVERSION, dos); + write(attributes, BUNDLE_SYMBOLICNAME, dos); + write(attributes, BUNDLE_NAME, dos); + write(attributes, BUNDLE_VERSION, dos); + write(attributes, DYNAMICIMPORT_PACKAGE, dos); + write(attributes, BUNDLE_CLASSPATH, dos); + write(attributes, IMPORT_PACKAGE, dos); + write(attributes, EXPORT_PACKAGE, dos); + write(attributes, "Eclipse-BuddyPolicy", dos); + dos.flush(); + } + + /** + * Add packages to be exported out of a JAR file. + * + * @param jarFile + * @param packages + * @throws IOException + */ + private static void addPackages(File jarFile, Set packages, String version) throws IOException { +// if (getBundleSymbolicName(jarFile) == null) { + String ver = ";version=" + version; + addAllPackages(jarFile, packages, ver); +// } else { +// addExportedPackages(jarFile, packages); +// } + } + + /** + * Write manifest attributes. + * + * @param attributes + * @param key + * @param dos + * @throws IOException + */ + private static void write(Attributes attributes, String key, DataOutputStream dos) throws IOException { + String value = attributes.getValue(key); + if (value == null) { + return; + } + StringBuffer line = new StringBuffer(); + line.append(key); + line.append(": "); + line.append(new String(value.getBytes("UTF8"))); + line.append("\r\n"); + int l = line.length(); + if (l > 72) { + for (int i = 70; i < l - 2;) { + line.insert(i, "\r\n "); + i += 72; + l += 3; + } + } + dos.writeBytes(line.toString()); + } + + /** + * Strip an OSGi export, only retain the package name and version. + * + * @param export + * @return + */ + private static String stripExport(String export) { + int sc = export.indexOf(';'); + if (sc == -1) { + return export; + } + String base = export.substring(0, sc); + int v = export.indexOf("version="); + if (v != -1) { + sc = export.indexOf(';', v + 1); + if (sc != -1) { + return base + ";" + export.substring(v, sc); + } else { + return base + ";" + export.substring(v); + } + } else { + return base; + } + } + + /** + * Add all the packages out of a JAR. + * + * @param jarFile + * @param packages + * @param version + * @throws IOException + */ + private static void addAllPackages(File jarFile, Set packages, String version) throws IOException { + ZipInputStream is = new ZipInputStream(new FileInputStream(jarFile)); + ZipEntry entry; + while ((entry = is.getNextEntry()) != null) { + String entryName = entry.getName(); + // Export split packages for META-INF/services + if(entryName.startsWith("META-INF/services/")) { + packages.add(META_INF_SERVICES); + } + if (!entry.isDirectory() && entryName != null + && entryName.length() > 0 + && !entryName.startsWith(".") + && entryName.endsWith(".class") // Exclude resources from Export-Package + && entryName.lastIndexOf("/") > 0 + && Character.isJavaIdentifierStart(entryName.charAt(0))) { + String pkg = entryName.substring(0, entryName.lastIndexOf("/")).replace('/', '.'); + if (!pkg.endsWith(".enum")) { + packages.add(pkg + version); + } + } + } + is.close(); + } + + private static Set getSystemPackages(String env) throws IOException { + Set sysPackages = new HashSet(); + InputStream is = BundleUtil.class.getResourceAsStream("/" + env + ".profile"); + if (is != null) { + Properties props = new Properties(); + props.load(is); + String pkgs = (String)props.get("org.osgi.framework.system.packages"); + if (pkgs != null) { + for (String p : pkgs.split(",")) { + sysPackages.add(p.trim()); + } + } + } + return sysPackages; + } + + /** + * Returns the name of the exported package in the given export. + * @param export + * @return + */ + private static String packageName(String export) { + int sc = export.indexOf(';'); + if (sc != -1) { + export = export.substring(0, sc); + } + return export; + } + + /** + * Add the packages exported by a bundle. + * + * @param file + * @param packages + * @return + * @throws IOException + */ + public static Set getExportedPackages(File file) throws IOException { + if (!file.exists()) { + return Collections.emptySet(); + } + + Set packages = new HashSet(); + Manifest manifest = getManifest(file); + + // Read the export-package declaration and get a list of the packages available in a JAR + String bundleName = null; + String exports = null; + + if (manifest != null) { + exports = manifest.getMainAttributes().getValue(EXPORT_PACKAGE); + bundleName = manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME); + } + + if (bundleName == null) { + Set allPackages = new HashSet(); + addAllPackages(file, allPackages, ""); + for (String p : allPackages) { + packages.add(packageName(p)); + } + return packages; + } + + packages.addAll(parsePackages(exports)); + + return packages; + } + + public static Set getImportedPackages(File file) throws IOException { + if (!file.exists()) { + return Collections.emptySet(); + } + + Manifest manifest = getManifest(file); + + // Read the export-package declaration and get a list of the packages available in a JAR + String bundleName = null; + String imports = null; + + if (manifest != null) { + imports = manifest.getMainAttributes().getValue(IMPORT_PACKAGE); + bundleName = manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME); + if (imports != null && bundleName != null) { + return parsePackages(imports); + } + } + return Collections.emptySet(); + } + + private static Set parsePackages(String header) { + if (header == null) { + return Collections.emptySet(); + } + Set packages = new HashSet(); + // Parse the export-package declaration, and extract the individual packages + StringBuffer buffer = new StringBuffer(); + boolean q = false; + for (int i = 0, n = header.length(); i < n; i++) { + char c = header.charAt(i); + if (c == '\"') { + q = !q; + } + if (!q) { + if (c == ',') { + + // Add the exported package to the set, after making sure it really exists in + // the JAR + String export = buffer.toString(); + packages.add(packageName(export)); + buffer = new StringBuffer(); + continue; + } + } + buffer.append(c); + } + if (buffer.length() != 0) { + String export = buffer.toString(); + packages.add(packageName(export)); + } + return packages; + } + + /** + * Convert the maven version into OSGi version + * @param mavenVersion + * @return + */ + static String osgiVersion(String mavenVersion) { + ArtifactVersion ver = new OSGIArtifactVersion(mavenVersion); + String qualifer = ver.getQualifier(); + if (qualifer != null) { + StringBuffer buf = new StringBuffer(qualifer); + for (int i = 0; i < buf.length(); i++) { + char c = buf.charAt(i); + if (Character.isLetterOrDigit(c) || c == '-' || c == '_') { + // Keep as-is + } else { + buf.setCharAt(i, '_'); + } + } + qualifer = buf.toString(); + } + Version osgiVersion = + new Version(ver.getMajorVersion(), ver.getMinorVersion(), ver.getIncrementalVersion(), qualifer); + String version = osgiVersion.toString(); + return version; + } + + private static String J2SE = "J2SE-"; + private static String JAVASE = "JavaSE-"; + private static String PROFILE_EXT = ".profile"; + private static URL findInSystemBundle(String entry) { + ClassLoader loader = BundleUtil.class.getClassLoader(); + return loader == null ? ClassLoader.getSystemResource(entry) : loader.getResource(entry); + } + + private static URL findNextBestProfile(String javaEdition, Version javaVersion) { + URL result = null; + int minor = javaVersion.getMinor(); + do { + result = findInSystemBundle(javaEdition + javaVersion.getMajor() + "." + minor + PROFILE_EXT); + minor = minor - 1; + } while (result == null && minor > 0); + return result; + } + + private static Properties findVMProfile(Properties properties) { + Properties result = new Properties(); + // Find the VM profile name using J2ME properties + String j2meConfig = properties.getProperty(Constants.J2ME_MICROEDITION_CONFIGURATION); + String j2meProfiles = properties.getProperty(Constants.J2ME_MICROEDITION_PROFILES); + String vmProfile = null; + String javaEdition = null; + Version javaVersion = null; + if (j2meConfig != null && j2meConfig.length() > 0 && j2meProfiles != null && j2meProfiles.length() > 0) { + // save the vmProfile based off of the config and profile + // use the last profile; assuming that is the highest one + String[] j2meProfileList = ManifestElement.getArrayFromList(j2meProfiles, " "); + if (j2meProfileList != null && j2meProfileList.length > 0) + vmProfile = j2meConfig + '_' + j2meProfileList[j2meProfileList.length - 1]; + } else { + // No J2ME properties; use J2SE properties + // Note that the CDC spec appears not to require VM implementations to set the + // javax.microedition properties!! So we will try to fall back to the + // java.specification.name property, but this is pretty ridiculous!! + String javaSpecVersion = properties.getProperty("java.specification.version"); + // set the profile and EE based off of the java.specification.version + // TODO We assume J2ME Foundation and J2SE here. need to support other profiles J2EE ... + if (javaSpecVersion != null) { + StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); + javaSpecVersion = st.nextToken(); + String javaSpecName = properties.getProperty("java.specification.name"); + if ("J2ME Foundation Specification".equals(javaSpecName)) + vmProfile = "CDC-" + javaSpecVersion + "_Foundation-" + javaSpecVersion; //$NON-NLS-2$ + else { + // look for JavaSE if 1.6 or greater; otherwise look for J2SE + Version v16 = new Version("1.6"); + javaEdition = J2SE; + try { + javaVersion = new Version(javaSpecVersion); + if (v16.compareTo(javaVersion) <= 0) + javaEdition = JAVASE; + } catch (IllegalArgumentException e) { + // do nothing + } + vmProfile = javaEdition + javaSpecVersion; + } + } + } + URL url = null; + // check for the java profile property for a url + String propJavaProfile = FrameworkProperties.getProperty(Constants.OSGI_JAVA_PROFILE); + if (propJavaProfile != null) + try { + // we assume a URL + url = new URL(propJavaProfile); + } catch (MalformedURLException e1) { + // try using a relative path in the system bundle + url = findInSystemBundle(propJavaProfile); + } + if (url == null && vmProfile != null) { + // look for a profile in the system bundle based on the vm profile + String javaProfile = vmProfile + PROFILE_EXT; + url = findInSystemBundle(javaProfile); + if (url == null) + url = getNextBestProfile(javaEdition, javaVersion); + } + if (url == null) + // the profile url is still null then use the osgi min profile in OSGi by default + url = findInSystemBundle("OSGi_Minimum-1.1.profile"); + if (url != null) { + InputStream in = null; + try { + in = url.openStream(); + result.load(new BufferedInputStream(in)); + } catch (IOException e) { + // TODO consider logging ... + } finally { + if (in != null) + try { + in.close(); + } catch (IOException ee) { + // do nothing + } + } + } + // set the profile name if it does not provide one + if (result.getProperty(Constants.OSGI_JAVA_PROFILE_NAME) == null) + if (vmProfile != null) + result.put(Constants.OSGI_JAVA_PROFILE_NAME, vmProfile.replace('_', '/')); + else + // last resort; default to the absolute minimum profile name for the framework + result.put(Constants.OSGI_JAVA_PROFILE_NAME, "OSGi/Minimum-1.1"); + return result; + } +/* doesn't work with Equinox 3.5.0 + public static void loadVMProfile(Properties properties) { + Properties profileProps = findVMProfile(properties); + String systemExports = properties.getProperty(Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES); + // set the system exports property using the vm profile; only if the property is not already set + if (systemExports == null) { + systemExports = profileProps.getProperty(Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES); + if (systemExports != null) + properties.put(Constants.OSGI_FRAMEWORK_SYSTEM_PACKAGES, systemExports); + } + // set the org.osgi.framework.bootdelegation property according to the java profile + String type = properties.getProperty(Constants.OSGI_JAVA_PROFILE_BOOTDELEGATION); // a null value means ignore + String profileBootDelegation = profileProps.getProperty(Constants.OSGI_BOOTDELEGATION); + if (Constants.OSGI_BOOTDELEGATION_OVERRIDE.equals(type)) { + if (profileBootDelegation == null) + properties.remove(Constants.OSGI_BOOTDELEGATION); // override with a null value + else + properties.put(Constants.OSGI_BOOTDELEGATION, profileBootDelegation); // override with the profile value + } else if (Constants.OSGI_BOOTDELEGATION_NONE.equals(type)) + properties.remove(Constants.OSGI_BOOTDELEGATION); // remove the bootdelegation property in case it was set + // set the org.osgi.framework.executionenvironment property according to the java profile + if (properties.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT) == null) { + // get the ee from the java profile; if no ee is defined then try the java profile name + String ee = + profileProps.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, profileProps + .getProperty(Constants.OSGI_JAVA_PROFILE_NAME)); + if (ee != null) + properties.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee); + } + } +*/ + + private static URL getNextBestProfile(String javaEdition, Version javaVersion) { + if (javaVersion == null || (javaEdition != J2SE && javaEdition != JAVASE)) + return null; // we cannot automatically choose the next best profile unless this is a J2SE or JavaSE vm + URL bestProfile = findNextBestProfile(javaEdition, javaVersion); + if (bestProfile == null && javaEdition == JAVASE) + // if this is a JavaSE VM then search for a lower J2SE profile + bestProfile = findNextBestProfile(J2SE, javaVersion); + return bestProfile; + } + +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundlesMetaDataBuildMojo.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundlesMetaDataBuildMojo.java new file mode 100644 index 0000000000..8d6cfd9aa4 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundlesMetaDataBuildMojo.java @@ -0,0 +1,1465 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +import static org.apache.tuscany.maven.bundle.plugin.BundleUtil.write; +import static org.osgi.framework.Constants.BUNDLE_CLASSPATH; +import static org.osgi.framework.Constants.BUNDLE_VERSION; +import static org.osgi.framework.Constants.RESOLUTION_DIRECTIVE; +import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL; +import static org.osgi.framework.Constants.VISIBILITY_DIRECTIVE; +import static org.osgi.framework.Constants.VISIBILITY_REEXPORT; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.jar.Attributes; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.resolver.ArtifactCollector; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectBuilder; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.artifact.InvalidDependencyVersionException; +import org.apache.maven.shared.dependency.tree.DependencyNode; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; +import org.apache.maven.shared.dependency.tree.traversal.CollectingDependencyNodeVisitor; +import org.osgi.framework.Constants; + +/** + * A maven plugin that generates meta-data for groups of Tuscany jars from the distribution's + * modules directory. The meta-data group jars either as mnaifest jars, ant filesets or + * simply as human readable lists of jars + * + * @version $Rev: 929729 $ $Date: 2010-03-31 22:52:37 +0100 (Wed, 31 Mar 2010) $ + * @goal generate-meta-data + * @phase generate-resources + * @requiresDependencyResolution test + * @description Generate a modules directory containing OSGi bundles for all the project's module dependencies. + */ +public class BundlesMetaDataBuildMojo extends AbstractMojo { + + private static final String GATEWAY_BUNDLE = "org.apache.tuscany.sca.gateway"; + + /** + * The project to create a distribution for. + * + * @parameter expression="${project}" + * @required + * @readonly + */ + private MavenProject project; + + /** + * Project builder -- builds a model from a pom.xml + * + * @component role="org.apache.maven.project.MavenProjectBuilder" + * @required + * @readonly + */ + private MavenProjectBuilder mavenProjectBuilder; + /** + * Used to look up Artifacts in the remote repository. + * + * @component + */ + private org.apache.maven.artifact.factory.ArtifactFactory factory; + + /** + * Used to look up Artifacts in the remote repository. + * + * @component + */ + private org.apache.maven.artifact.resolver.ArtifactResolver resolver; + + /** + * @component role="org.apache.maven.artifact.metadata.ArtifactMetadataSource" + * hint="maven" + * @required + * @readonly + */ + private ArtifactMetadataSource artifactMetadataSource; + + /** + * The artifact collector to use. + * + * @component + * @required + * @readonly + */ + private ArtifactCollector artifactCollector; + + /** + * The dependency tree builder to use. + * + * @component + * @required + * @readonly + */ + private DependencyTreeBuilder dependencyTreeBuilder; + + + /** + * Location of the local repository. + * + * @parameter expression="${localRepository}" + * @readonly + * @required + */ + private org.apache.maven.artifact.repository.ArtifactRepository local; + + /** + * List of Remote Repositories used by the resolver + * + * @parameter expression="${project.remoteArtifactRepositories}" + * @readonly + * @required + */ + private java.util.List remoteRepos; + + /** + * Target directory. + * + * @parameter expression="${project.build.directory}/modules" + */ + private File targetDirectory; + + /** + * @parameter default-value="features" + */ + private String featuresName = "features"; + + /** + * Directories containing artifacts to exclude. + * + * @parameter + */ + private File[] excludeDirectories; + + /** + * Directories containing groupids to exclude. + * + * @parameter + */ + private String[] excludeGroupIds; + + /** + * Directories containing groupids to include. + * + * @parameter + */ + private String[] includeGroupIds; + + /** + * Set to true to generate configurations under a folder named as the distro + * + * @parameter default-value="true" + */ + private boolean useDistributionName = false; + + /** + * Set to true to generate the contents of the modules directory. + * + * @parameter default-value="true" + */ + private boolean generateModules = false; + + /** + * Set to true to generate a PDE target platform configuration. + * + * @parameter default-value="true" + */ + private boolean generateTargetPlatform = true; + + /** + * Expand non-tuscany bundles as a folder + * @parameter default-value="false" + */ + private boolean expandThirdPartyBundle = false; + + /** + * OSGi execution environment + */ + private String executionEnvironment; + + /** + * A list of Eclipse features to be added to the target definition + * @parameter + */ + private String[] eclipseFeatures; + + /** + * If we use the running eclipse as the default location for the target + * @parameter default-value="true" + */ + private boolean useDefaultLocation = true; + + /** + * Set to true to generate a gateway bundle tuscany-gateway-.jar that handles split packages and META-INF/services. + * + * @parameter default-value="true" + */ + private boolean generateGatewayBundle; + + /** + * @parameter default-value="false" + */ + private boolean gatewayReexport; + + /** + * Set to true to generate a plugin.xml. + * + * @parameter default-value="false" + */ + private boolean generatePlugin; + + /** + * Generate a configuration/config.ini for equinox + * @parameter default-value="true" + */ + private boolean generateConfig = true; + + /** + * Generate an aggregated OSGi bundle for each feature + * @parameter default-value="false" + */ + private boolean generateAggregatedBundle = false; + + /** + * @parameter default-value="true" + */ + private boolean generateBundleStart = true; + + /** + * @parameter default-value="true" + */ + private boolean includeConflictingDepedencies = true; + + /** + * Generete manifest.jar + * @parameter default-value="true" + */ + private boolean generateManifestJar = true; + + /** + * @parameter default-value="tuscany-sca-manifest.jar" + */ + private String manifestJarName = "tuscany-sca-manifest.jar"; + + /** + * @parameter default-value="tuscany-sca-equinox-manifest.jar" + */ + private String equinoxManifestJarName = "tuscany-sca-equinox-manifest.jar"; + + /** + * @parameter default-value="jar,bundle" + */ + private String artifactTypes; + + /** + * @parameter default-value="true" + */ + private boolean generateAntScript = true; + + /** + * @parameter default-value="true" + */ + private boolean generateWhichJars = true; + + /** + * @parameter + */ + private ArtifactAggregation[] artifactAggregations; + + /** + * @parameter + */ + private ArtifactManifest[] artifactManifests; + + /** + * Feature artifact IDs to be processed and included in the features directory + * @parameter + */ + private Feature[] features; + + /** + * Extension artifact IDs to be processed and included in the extensions directory + * @parameter + */ + private Extension[] extensions; + + /** + * Inserts a generic Eclipse-BuddyPolicy header into generated artifacts manifests + * @parameter + */ + private String eclipseBuddyPolicy = null; + + private static final String XML_PI = ""; + private static final String ASL_HEADER = + ""; + + /** + * Group the artifacts by distribution poms + */ + private class ProjectSet { + // Distribution projects + private Map projects; + // Key: the pom artifact id + // Value: the names for the artifacts + private Map> nameMap = new HashMap>(); + + private Map artifactToNameMap = new HashMap(); + + public ProjectSet(List projects) { + super(); + this.projects = new HashMap(); + for (MavenProject p : projects) { + this.projects.put(p.getArtifactId(), p); + } + } + + private MavenProject getProject(String artifactId) { + return projects.get(artifactId); + } + + private void add(Artifact artifact, String name) { + String key = ArtifactUtils.versionlessKey(artifact); + for (MavenProject p : projects.values()) { + Artifact a = (Artifact)p.getArtifactMap().get(key); + if (a == null && + artifact.getArtifactId().equals(p.getArtifactId())){ + a = p.getArtifact(); + } + if (a != null) { + if (a.getScope() != null && + (a.getScope().equals("provided") || + a.getScope().equals("test") || + a.getScope().equals("system"))){ + // ignore the artifact + } else { + Set names = nameMap.get(p.getArtifactId()); + if (names == null) { + names = new TreeSet(); + nameMap.put(p.getArtifactId(), names); + } + names.add(name); + } + } + } + artifactToNameMap.put(key, name); + } + } + + private Manifest findManifest(Artifact artifact) throws IOException { + if (artifactManifests == null) { + return null; + } + for (ArtifactManifest m : artifactManifests) { + if (m.matches(artifact)) { + File mf = m.getManifestFile(); + if (mf != null) { + FileInputStream is = new FileInputStream(mf); + Manifest manifest = new Manifest(is); + is.close(); + getLog().info("MANIFEST.MF found for " + artifact + " (" + mf + ")"); + return manifest; + } else { + getLog().info("Overriding the manifest for " + artifact); + Manifest manifest = BundleUtil.getManifest(artifact.getFile()); + Set jarFiles = new HashSet(); + jarFiles.add(artifact.getFile()); + String symbolicName = BundleUtil.getBundleSymbolicName(manifest); + if (symbolicName == null) { + // Not a bundle + continue; + } + String version = manifest.getMainAttributes().getValue(BUNDLE_VERSION); + manifest = + BundleUtil.libraryManifest(jarFiles, + symbolicName, + symbolicName, + version, + null, + this.eclipseBuddyPolicy, + this.executionEnvironment); + // Remove it as it will be added later on + manifest.getMainAttributes().remove(new Attributes.Name(BUNDLE_CLASSPATH)); + return manifest; + } + } + } + return null; + } + + /** + * Gets the artifact filter to use when resolving the dependency tree. + * + * @return the artifact filter + */ + private ArtifactFilter createResolvingArtifactFilter(String scope) { + ArtifactFilter filter; + + // filter scope + if (scope != null) { + getLog().debug("+ Resolving dependency tree for scope '" + scope + "'"); + + filter = new ScopeArtifactFilter(scope); + } else { + filter = null; + } + + return filter; + } + + public void execute() throws MojoExecutionException { + Log log = getLog(); + + Set artifacts = null; + if (includeConflictingDepedencies) { + try { + artifacts = getDependencyArtifacts(project); + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + } else { + artifacts = project.getArtifacts(); + } + + try { + + // Create the target directory + File root; + if (targetDirectory == null) { + root = new File(project.getBuild().getDirectory(), "plugins/"); + } else { + root = targetDirectory; + } + + if (generateModules){ + root.mkdirs(); + } + + // Build sets of exclude directories and included/excluded/groupids + Set excludedFileNames = new HashSet(); + if (excludeDirectories != null) { + for (File f : excludeDirectories) { + if (f.isDirectory()) { + for (String n : f.list()) { + excludedFileNames.add(n); + } + } + } + } + Set includedGroupIds = new HashSet(); + if (includeGroupIds != null) { + for (String g : includeGroupIds) { + includedGroupIds.add(g); + } + } + Set excludedGroupIds = new HashSet(); + if (excludeGroupIds != null) { + for (String g : excludeGroupIds) { + excludedGroupIds.add(g); + } + } + + // Find all the distribution poms + List poms = new ArrayList(); + + if (useDistributionName) { + for (Object o : project.getArtifacts()) { + Artifact artifact = (Artifact)o; + if ("pom".equals(artifact.getType()) && artifact.getGroupId().equals(project.getGroupId()) + && artifact.getArtifactId().startsWith("tuscany-feature-")) { + log.info("Dependent distribution: " + artifact); + MavenProject pomProject = buildProject(artifact); + poms.add(pomProject); + // log.info(pomProject.getArtifactMap().toString()); + } + } + } + + if (features != null){ + // find all the features that require processing + for (Object o : project.getArtifacts()) { + Artifact artifact = (Artifact)o; + for(Feature feature : features){ + if (artifact.getGroupId().equals(feature.getGroupId()) && + artifact.getArtifactId().equals(feature.getArtifactId())) { + log.info("Feature: " + artifact); + MavenProject pomProject = buildProject(artifact); + poms.add(pomProject); + } + } + } + + // force useDistributionName to true so that subsequent generation works + useDistributionName = true; + } + + if (extensions != null){ + // find all the extensions that require processing + // TODO - putting them in features dir for the time being + for (Object o : project.getArtifacts()) { + Artifact artifact = (Artifact)o; + for(Extension extension : extensions) { + if (artifact.getGroupId().equals(extension.getGroupId()) && + artifact.getArtifactId().equals(extension.getArtifactId())) { + log.info("Extension: " + artifact); + MavenProject pomProject = buildProject(artifact); + poms.add(pomProject); + } + } + } + + // force useDistributionName to true so that subsequent generation works + useDistributionName = true; + } + + // If no features have been specified assume that the current + // project defines the feature + if (poms.size() == 0){ + poms.add(project); + } + + // Process all the dependency artifacts + ProjectSet bundleSymbolicNames = new ProjectSet(poms); + ProjectSet bundleLocations = new ProjectSet(poms); + ProjectSet jarNames = new ProjectSet(poms); + ProjectSet serviceProviders = new ProjectSet(poms); + + for (Artifact artifact: artifacts) { + + log.info("Processing artifact: " + artifact); + + // Only consider Compile and Runtime dependencies + if (!(Artifact.SCOPE_COMPILE.equals(artifact.getScope()) || Artifact.SCOPE_RUNTIME.equals(artifact + .getScope()) + || Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) || (generateTargetPlatform && Artifact.SCOPE_TEST + .equals(artifact.getScope())))) { + log.info("Skipping artifact: " + artifact); + continue; + } + + if (artifactTypes == null) { + artifactTypes = "jar,bundle"; + } + String types[] = artifactTypes.trim().split("( |\t|\n|\r|\f|,)+"); + Set typeSet = new HashSet(Arrays.asList(types)); + + // Only consider JAR and WAR files + if (!typeSet.contains(artifact.getType())) { + log.debug("Artifact with unknown type is skipped: " + artifact); + continue; + } + + // Exclude artifact if its groupId is excluded or if it's not included + if (excludedGroupIds.contains(artifact.getGroupId())) { + log.debug("Artifact groupId is excluded: " + artifact); + continue; + } + if (!includedGroupIds.isEmpty()) { + if (!includedGroupIds.contains(artifact.getGroupId())) { + log.debug("Artifact groupId is not included: " + artifact); + continue; + } + } + + File artifactFile = artifact.getFile(); + if (!artifactFile.exists()) { + log.warn("Artifact doesn't exist: " + artifact); + continue; + } + + if (log.isDebugEnabled()) { + log.debug("Processing artifact: " + artifact); + } + + Manifest customizedMF = findManifest(artifact); + + // Get the bundle name if the artifact is an OSGi bundle + Manifest mf = null; + String bundleName = null; + try { + mf = BundleUtil.getManifest(artifactFile); + bundleName = BundleUtil.getBundleSymbolicName(mf); + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + if (bundleName != null && customizedMF == null) { + + // Exclude artifact if its file name is excluded + if (excludedFileNames.contains(artifactFile.getName())) { + log.debug("Artifact file is excluded: " + artifact); + continue; + } + + if (generateModules){ + // Copy an OSGi bundle as is + log.info("Adding OSGi bundle artifact: " + artifact); + } + + if (!expandThirdPartyBundle || artifact.getGroupId().startsWith("org.apache.tuscany.sca") + || artifact.getGroupId().startsWith("org.eclipse")) { + if (generateModules){ + copyFile(artifactFile, root); + } + bundleSymbolicNames.add(artifact, bundleName); + bundleLocations.add(artifact, artifactFile.getName()); + jarNames.add(artifact, artifactFile.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, bundleName); + } + } else { + // Expanding the bundle into a folder + + setBundleClassPath(mf, artifactFile); + + int index = artifactFile.getName().lastIndexOf('.'); + String dirName = artifactFile.getName().substring(0, index); + File dir = new File(root, dirName); + if (generateModules){ + File file = new File(dir, "META-INF"); + file.mkdirs(); + file = new File(file, "MANIFEST.MF"); + + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + copyFile(artifactFile, dir); + } + bundleSymbolicNames.add(artifact, bundleName); + bundleLocations.add(artifact, dir.getName()); + jarNames.add(artifact, dirName + "/" + artifactFile.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, bundleName); + } + } + + } else if ("war".equals(artifact.getType())) { + + // Exclude artifact if its file name is excluded + if (excludedFileNames.contains(artifactFile.getName())) { + log.debug("Artifact file is excluded: " + artifact); + continue; + } + + if (generateModules){ + // Copy a WAR as is + log.info("Adding WAR artifact: " + artifact); + copyFile(artifactFile, root); + } + } else { + + int index = artifactFile.getName().lastIndexOf('.'); + String dirName = artifactFile.getName().substring(0, index); + File dir = new File(root, dirName); + + // Exclude artifact if its file name is excluded + if (excludedFileNames.contains(dir.getName())) { + log.debug("Artifact file is excluded: " + artifact); + continue; + } + + if (artifactAggregations != null) { + boolean aggregated = false; + for (ArtifactAggregation group : artifactAggregations) { + if (group.matches(artifact)) { + group.getArtifacts().add(artifact); + aggregated = true; + break; + } + } + if (aggregated) { + continue; + } + } + + // create manifest directory + File file = new File(dir, "META-INF"); + if (generateModules){ + // Create a bundle directory for a non-OSGi JAR + log.info("Adding JAR artifact: " + artifact); + + file.mkdirs(); + } + + String symbolicName = null; + if (customizedMF == null) { + String version = BundleUtil.osgiVersion(artifact.getVersion()); + + Set jarFiles = new HashSet(); + jarFiles.add(artifactFile); + symbolicName = (artifact.getGroupId() + "." + artifact.getArtifactId()); + if (generateModules){ + mf = + BundleUtil.libraryManifest(jarFiles, + symbolicName, + symbolicName, + version, + null, + this.eclipseBuddyPolicy, + this.executionEnvironment); + + file = new File(file, "MANIFEST.MF"); + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + log.info("Writing generated manifest for: " + artifact + " to " + file); + } + } else { + mf = customizedMF; + symbolicName = BundleUtil.getBundleSymbolicName(mf); + if (symbolicName == null) { + throw new MojoExecutionException("Invalid customized MANIFEST.MF for " + artifact); + } + setBundleClassPath(mf, artifactFile); + + // re-find the custom MF file and copy it + // I can't get the manifest file from the manifest itself + // the Manifest read/write operation seems to be filtering + // out some entries that I've added manually???? + File artifactManifest = null; + + if (artifactManifests != null) { + for (ArtifactManifest m : artifactManifests) { + if (m.matches(artifact)) { + artifactManifest = m.getManifestFile(); + break; + } + } + } + + if (generateModules){ + file = new File(file, "MANIFEST.MF"); + + if (artifactManifest != null){ + log.info("Copying: " + artifactManifest + " to " + file); + copyManifest(artifactManifest, file); + } else { + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + log.info("Writing generated manifest for: " + artifact + " to " + file); + } + } + } + + if (generateModules){ + copyFile(artifactFile, dir); + } + + bundleSymbolicNames.add(artifact, symbolicName); + bundleLocations.add(artifact, dir.getName()); + jarNames.add(artifact, dirName + "/" + artifactFile.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, symbolicName); + } + } + } + + + if (artifactAggregations != null) { + for (ArtifactAggregation group : artifactAggregations) { + if (group.getArtifacts().isEmpty()) { + continue; + } + String symbolicName = group.getSymbolicName(); + String version = group.getVersion(); + File dir = new File(root, symbolicName + "-" + version); + dir.mkdir(); + Set jarFiles = new HashSet(); + Artifact artifact = null; + for (Artifact a : group.getArtifacts()) { + log.info("Aggragating JAR artifact: " + a); + artifact = a; + jarFiles.add(a.getFile()); + copyFile(a.getFile(), dir); + jarNames.add(a, symbolicName + "-" + version + "/" + a.getFile().getName()); + } + Manifest mf = + BundleUtil.libraryManifest(jarFiles, + symbolicName, + symbolicName, + version, + null, + this.eclipseBuddyPolicy, + this.executionEnvironment); + File file = new File(dir, "META-INF"); + file.mkdirs(); + file = new File(file, "MANIFEST.MF"); + + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + log.info("Written aggregate manifest"); + bundleSymbolicNames.add(artifact, symbolicName); + bundleLocations.add(artifact, dir.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, symbolicName); + } + } + } + + + if (generateGatewayBundle) { + generateGatewayBundle(serviceProviders); + } + + /* + if (useDistributionName) { + bundleLocations.nameMap.remove(project.getArtifactId()); + jarNames.nameMap.remove(project.getArtifactId()); + bundleSymbolicNames.nameMap.remove(project.getArtifactId()); + } + */ + + // Generate a PDE target + if (generateTargetPlatform) { + generatePDETarget(bundleSymbolicNames, root, log); + } + + // Generate a plugin.xml referencing the PDE target + if (generatePlugin) { + File pluginxml = new File(project.getBasedir(), "plugin.xml"); + FileOutputStream pluginXMLFile = new FileOutputStream(pluginxml); + writePluginXML(new PrintStream(pluginXMLFile)); + pluginXMLFile.close(); + } + + if (generateConfig) { + generateEquinoxConfig(bundleLocations, root, log); + } + + if (generateManifestJar) { + generateManifestJar(jarNames, root, log); + generateEquinoxLauncherManifestJar(jarNames, root, log); + } + + if (generateAntScript) { + generateANTPath(jarNames, root, log); + } + + if (generateWhichJars) { + generateWhichJars(jarNames, root, log); + } + + if (generateAggregatedBundle) { + generateAggregatedBundles(bundleLocations, root, log); + } + + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + } + + private Set getDependencyArtifacts(MavenProject project) throws DependencyTreeBuilderException, + ArtifactResolutionException, ArtifactNotFoundException { + Log log = getLog(); + Set artifacts = new HashSet(); + ArtifactFilter artifactFilter = createResolvingArtifactFilter(Artifact.SCOPE_RUNTIME); + + // TODO: note that filter does not get applied due to MNG-3236 + + DependencyNode rootNode = + dependencyTreeBuilder.buildDependencyTree(project, + local, + factory, + artifactMetadataSource, + artifactFilter, + artifactCollector); + CollectingDependencyNodeVisitor visitor = new CollectingDependencyNodeVisitor(); + rootNode.accept(visitor); + + // Add included artifacts + for (Object node : visitor.getNodes()) { + DependencyNode depNode = (DependencyNode)node; + int state = depNode.getState(); + if (state == DependencyNode.INCLUDED ) { + Artifact artifact = depNode.getArtifact(); + // Exclude the project artifact to avoid offline resolution failure + if (!artifact.equals(project.getArtifact())) { + resolver.resolve(artifact, remoteRepos, local); + artifacts.add(artifact); + } + } + } + // Scan for newer versions that are omitted + for (Object node : visitor.getNodes()) { + DependencyNode depNode = (DependencyNode)node; + int state = depNode.getState(); + if (state == DependencyNode.OMITTED_FOR_CONFLICT) { + Artifact artifact = depNode.getArtifact(); + resolver.resolve(artifact, remoteRepos, local); + if (state == DependencyNode.OMITTED_FOR_CONFLICT) { + Artifact related = depNode.getRelatedArtifact(); + if (log.isDebugEnabled()) { + log.debug("Dependency node: " + depNode); + } + // Compare the version + ArtifactVersion v1 = new DefaultArtifactVersion(artifact.getVersion()); + ArtifactVersion v2 = new DefaultArtifactVersion(related.getVersion()); + if (v1.compareTo(v2) > 0) { + // Only add newer version if it is omitted for conflict + if (artifacts.add(artifact)) { + log.info("Dependency node added: " + depNode); + } + } + } + } + } + return artifacts; + } + + private static boolean isServiceProvider(Manifest mf) { + if (mf != null) { + String export = (String)mf.getMainAttributes().getValue(Constants.EXPORT_PACKAGE); + if (export != null && export.contains(BundleUtil.META_INF_SERVICES)) { + return true; + } + } + return false; + } + + /** + * Generate a gateway bundle that aggregate other bundles to handle split packages + * @param bundleSymbolicNames + * @throws FileNotFoundException + * @throws IOException + */ + private void generateGatewayBundle(ProjectSet bundleSymbolicNames) throws FileNotFoundException, IOException { + Manifest manifest = new Manifest(); + Attributes attrs = manifest.getMainAttributes(); + StringBuffer requireBundle = new StringBuffer(); + for (String name : new HashSet(bundleSymbolicNames.artifactToNameMap.values())) { + requireBundle.append(name).append(";").append(RESOLUTION_DIRECTIVE).append(":=") + .append(RESOLUTION_OPTIONAL); + if (gatewayReexport) { + requireBundle.append(";").append(VISIBILITY_DIRECTIVE).append(":=").append(VISIBILITY_REEXPORT); + } + requireBundle.append(","); + } + int len = requireBundle.length(); + if (len > 0 && requireBundle.charAt(len - 1) == ',') { + requireBundle.deleteCharAt(len - 1); + attrs.putValue(Constants.REQUIRE_BUNDLE, requireBundle.toString()); + attrs.putValue("Manifest-Version", "1.0"); + attrs.putValue("Implementation-Vendor", "The Apache Software Foundation"); + attrs.putValue("Implementation-Vendor-Id", "org.apache"); + attrs.putValue(Constants.BUNDLE_VERSION, "2.0.0"); + attrs.putValue(Constants.BUNDLE_MANIFESTVERSION, "2"); + attrs.putValue(Constants.BUNDLE_SYMBOLICNAME, GATEWAY_BUNDLE); + attrs.putValue(Constants.BUNDLE_NAME, "Apache Tuscany SCA Gateway Bundle"); + attrs.putValue(Constants.BUNDLE_VENDOR, "The Apache Software Foundation"); + attrs.putValue(Constants.EXPORT_PACKAGE, "META-INF.services"); + attrs.putValue(Constants.DYNAMICIMPORT_PACKAGE, "*"); + attrs.putValue(Constants.BUNDLE_ACTIVATIONPOLICY, Constants.ACTIVATION_LAZY); + File file = new File(targetDirectory, "tuscany-gateway-" + project.getVersion() + ".jar"); + getLog().info("Generating gateway bundle: " + file.getAbsolutePath()); + FileOutputStream fos = new FileOutputStream(file); + JarOutputStream jos = new JarOutputStream(fos, manifest); + addFileToJar(jos, "META-INF/LICENSE", getClass().getResource("LICENSE.txt")); + addFileToJar(jos, "META-INF/NOTICE", getClass().getResource("NOTICE.txt")); + jos.close(); + } + } + + private void setBundleClassPath(Manifest mf, File artifactFile) { + // Add the Bundle-ClassPath + String cp = mf.getMainAttributes().getValue(BUNDLE_CLASSPATH); + if (cp == null) { + cp = artifactFile.getName(); + } else { + cp = cp + "," + artifactFile.getName(); + } + mf.getMainAttributes().putValue(BUNDLE_CLASSPATH, cp); + } + + private void generateANTPath(ProjectSet jarNames, File root, Log log) throws FileNotFoundException, IOException { + for (Map.Entry> e : jarNames.nameMap.entrySet()) { + Set jars = e.getValue(); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + feature.mkdirs(); + File antPath = new File(feature, "build-path.xml"); + log.info("Generating ANT build path: " + antPath.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(antPath); + PrintStream ps = new PrintStream(fos); + // ps.println(XML_PI); + ps.println(ASL_HEADER); + String name = trim(e.getKey()); + ps.println(""); + ps.println(" "); + ps.println(" "); + ps.println(" "); + ps.println(" "); + for (String jar : jars) { + ps.println(" "); + } + ps.println(" "); + ps.println(" "); + ps.println(""); + } + } + + private void generateWhichJars(ProjectSet jarNames, File root, Log log) throws FileNotFoundException, IOException { + for (Map.Entry> e : jarNames.nameMap.entrySet()) { + Set jars = e.getValue(); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + feature.mkdirs(); + File whichJarsPath = new File(feature, "which-jars"); + log.info("Generating Which Jars: " + whichJarsPath.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(whichJarsPath); + PrintStream ps = new PrintStream(fos); + + ps.println(ASL_HEADER); + String name = trim(e.getKey()); + ps.println("Jars required to enable extension: " + name); + ps.println(""); + for (String jar : jars) { + ps.println(jar); + } + } + } + + private void generateManifestJar(ProjectSet jarNames, File root, Log log) throws FileNotFoundException, IOException { + for (Map.Entry> e : jarNames.nameMap.entrySet()) { + MavenProject pom = jarNames.getProject(e.getKey()); + Set jars = e.getValue(); + String name = trim(e.getKey()); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + feature.mkdirs(); + String manifestName = name + "-manifest.jar"; + File mfJar = new File(feature, manifestName); + log.info("Generating manifest jar: " + mfJar.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(mfJar); + Manifest mf = new Manifest(); + StringBuffer cp = new StringBuffer(); + String path = (useDistributionName ? "../../" : "../") + root.getName(); + for (String jar : jars) { + cp.append(path).append('/').append(jar).append(' '); + } + if (cp.length() > 0) { + cp.deleteCharAt(cp.length() - 1); + } + Attributes attrs = mf.getMainAttributes(); + attrs.putValue("Manifest-Version", "1.0"); + attrs.putValue("Implementation-Title", pom.getName()); + attrs.putValue("Implementation-Vendor", "The Apache Software Foundation"); + attrs.putValue("Implementation-Vendor-Id", "org.apache"); + attrs.putValue("Implementation-Version", pom.getVersion()); + attrs.putValue("Class-Path", cp.toString()); + attrs.putValue("Main-Class", "org.apache.tuscany.sca.node.launcher.NodeMain"); + JarOutputStream jos = new JarOutputStream(fos, mf); + addFileToJar(jos, "META-INF/LICENSE", getClass().getResource("LICENSE.txt")); + addFileToJar(jos, "META-INF/NOTICE", getClass().getResource("NOTICE.txt")); + jos.close(); + } + } + + private void generateEquinoxLauncherManifestJar(ProjectSet jarNames, File root, Log log) throws Exception { + String equinoxLauncher = "org.apache.tuscany.sca:tuscany-node-launcher-equinox"; + Artifact artifact = (Artifact)project.getArtifactMap().get(equinoxLauncher); + if (artifact == null) { + return; + } + Set artifacts = resolveTransitively(artifact).getArtifacts(); + File feature = new File(root, "../" + featuresName + "/"); + feature.mkdirs(); + File mfJar = new File(feature, equinoxManifestJarName); + log.info("Generating equinox manifest jar: " + mfJar.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(mfJar); + Manifest mf = new Manifest(); + StringBuffer cp = new StringBuffer(); + String path = "../" + root.getName(); + + for (Object o : artifacts) { + Artifact a = (Artifact)o; + if (!Artifact.SCOPE_TEST.equals(a.getScope())) { + String id = ArtifactUtils.versionlessKey(a); + String jar = jarNames.artifactToNameMap.get(id); + if (jar != null) { + cp.append(path).append('/').append(jar).append(' '); + } + } + } + if (cp.length() > 0) { + cp.deleteCharAt(cp.length() - 1); + } + Attributes attrs = mf.getMainAttributes(); + attrs.putValue("Manifest-Version", "1.0"); + attrs.putValue("Implementation-Title", artifact.getId()); + attrs.putValue("Implementation-Vendor", "The Apache Software Foundation"); + attrs.putValue("Implementation-Vendor-Id", "org.apache"); + attrs.putValue("Implementation-Version", artifact.getVersion()); + attrs.putValue("Class-Path", cp.toString()); + attrs.putValue("Main-Class", "org.apache.tuscany.sca.node.equinox.launcher.NodeMain"); + JarOutputStream jos = new JarOutputStream(fos, mf); + addFileToJar(jos, "META-INF/LICENSE", getClass().getResource("LICENSE.txt")); + addFileToJar(jos, "META-INF/NOTICE", getClass().getResource("NOTICE.txt")); + jos.close(); + } + + private void generateEquinoxConfig(ProjectSet bundleLocations, File root, Log log) throws IOException { + for (Map.Entry> e : bundleLocations.nameMap.entrySet()) { + Set locations = new HashSet(e.getValue()); + if (generateGatewayBundle) { + locations.add("tuscany-gateway-" + project.getVersion() + ".jar"); + } + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + File config = new File(feature, "configuration"); + config.mkdirs(); + File ini = new File(config, "config.ini"); + log.info("Generating configuation: " + ini.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(ini); + PrintStream ps = new PrintStream(fos); + int size = locations.size(); + if (size > 0) { + ps.println("osgi.bundles=\\"); + int count = 0; + for (String f : locations) { + if (f.startsWith("osgi")) { + count++; + continue; + } + ps.print(" "); + ps.print(f); + // FIXME: We should not add @start for fragments + if (generateBundleStart) { + ps.print("@:start"); + } + if (count == size - 1) { + // Last one + ps.println(); + } else { + ps.println(",\\"); + } + count++; + } + } + ps.println("eclipse.ignoreApp=true"); + // Do not shutdown + ps.println("osgi.noShutdown=true"); + ps.close(); + } + } + + private void generateAggregatedBundles(ProjectSet bundleLocations, File root, Log log) throws Exception { + for (Map.Entry> e : bundleLocations.nameMap.entrySet()) { + Set locations = new HashSet(e.getValue()); + String featureName = (useDistributionName ? trim(e.getKey()) : ""); + File feature = new File(root, "../" + featuresName + "/" + featureName); +// String bundleFileName = "tuscany-bundle-" + featureName + ".jar"; +// if ("".equals(featureName)) { +// bundleFileName = "tuscany-bundle.jar"; +// } + String bundleFileName = "tuscany-bundle.jar"; + File bundleFile = new File(feature, bundleFileName); + log.info("Generating aggregated OSGi bundle: " + bundleFile); + File[] files = new File[locations.size()]; + int i = 0; + for (String child : locations) { + files[i++] = new File(root, child); + } + String bundleVersion = "2.0.0"; + String bundleName = "org.apache.tuscany.sca.bundle"; + +// String bundleName = "org.apache.tuscany.sca.bundle." + featureName; +// if ("".equals(featureName)) { +// bundleName = "org.apache.tuscany.sca.bundle"; +// } + BundleAggregatorMojo.aggregateBundles(log, root, files, bundleFile, bundleName, bundleVersion); + } + } + + private void generatePDETarget(ProjectSet bundleSymbolicNames, File root, Log log) throws FileNotFoundException, + IOException { + for (Map.Entry> e : bundleSymbolicNames.nameMap.entrySet()) { + Set bundles = new HashSet(e.getValue()); + String name = trim(e.getKey()); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? name : "")); + feature.mkdirs(); + File target = new File(feature, "tuscany.target"); + log.info("Generating target definition: " + target.getCanonicalPath()); + FileOutputStream targetFile = new FileOutputStream(target); + if (!bundles.contains("org.eclipse.osgi")) { + bundles.add("org.eclipse.osgi"); + } + if (generateGatewayBundle) { + bundles.add(GATEWAY_BUNDLE); + } + writeTarget(new PrintStream(targetFile), name, bundles, eclipseFeatures); + targetFile.close(); + + // Generate the PDE target definition file for PDE 3.5 + File target35 = new File(feature, "tuscany-pde35.target"); + log.info("Generating target definition: " + target35.getCanonicalPath()); + FileOutputStream target35File = new FileOutputStream(target35); + writePDE35Target(new PrintStream(target35File), name, bundles, eclipseFeatures); + target35File.close(); + + } + } + + private MavenProject buildProject(Artifact artifact) throws ProjectBuildingException, + InvalidDependencyVersionException, ArtifactResolutionException, ArtifactNotFoundException, DependencyTreeBuilderException { + MavenProject pomProject = mavenProjectBuilder.buildFromRepository(artifact, this.remoteRepos, this.local); + if (pomProject.getDependencyArtifacts() == null) { + pomProject.setDependencyArtifacts(pomProject.createArtifacts(factory, null, // Artifact.SCOPE_TEST, + new ScopeArtifactFilter(Artifact.SCOPE_TEST))); + } + if (includeConflictingDepedencies) { + pomProject.setArtifacts(getDependencyArtifacts(pomProject)); + } else { + ArtifactResolutionResult result = + resolver.resolveTransitively(pomProject.getDependencyArtifacts(), + pomProject.getArtifact(), + remoteRepos, + local, + artifactMetadataSource); + pomProject.setArtifacts(result.getArtifacts()); + } + return pomProject; + } + + private ArtifactResolutionResult resolveTransitively(Artifact artifact) throws ArtifactResolutionException, + ArtifactNotFoundException { + Artifact originatingArtifact = factory.createBuildArtifact("dummy", "dummy", "1.0", "jar"); + + return resolver.resolveTransitively(Collections.singleton(artifact), + originatingArtifact, + local, + remoteRepos, + artifactMetadataSource, + null); + } + + /** + * Convert tuscany-feature-xyz to feature-xyz + * @param artifactId + * @return + */ + private String trim(String artifactId) { + if (artifactId.startsWith("tuscany-feature-")) { + return artifactId.substring("tuscany-feature-".length()); + } else { + return artifactId; + } + } + + private static void copyFile(File jar, File dir) throws FileNotFoundException, IOException { + byte[] buf = new byte[4096]; + File jarFile = new File(dir, jar.getName()); + FileInputStream in = new FileInputStream(jar); + FileOutputStream out = new FileOutputStream(jarFile); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.close(); + } + + private static void copyManifest(File mfFrom, File mfTo) throws FileNotFoundException, IOException { + byte[] buf = new byte[4096]; + FileInputStream in = new FileInputStream(mfFrom); + FileOutputStream out = new FileOutputStream(mfTo); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.close(); + } + + private static void addFileToJar(JarOutputStream out, String entryName, URL file) throws FileNotFoundException, + IOException { + byte[] buf = new byte[4096]; + InputStream in = file.openStream(); + out.putNextEntry(new ZipEntry(entryName)); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.closeEntry(); + } + + private void writeTarget(PrintStream ps, String pom, Set ids, String[] features) { + ps.println(XML_PI); + ps.println(""); + ps.println(ASL_HEADER); + + ps.println(""); + + if (executionEnvironment != null) { + ps.println(" "); + ps.println(" " + executionEnvironment + ""); + ps.println(" "); + } + + if (useDefaultLocation) { + ps.println(" "); + } else { + ps.println(" "); + } + + // ps.println(""); + ps.println(" "); + ps.println(" "); + for (String id : ids) { + ps.println(" "); + } + ps.println(" "); + ps.println(" "); + if (features != null) { + for (String f : features) { + ps.println(" "); + } + } + ps.println(" "); + if (useDefaultLocation) { + ps.println(" "); + // Not sure why the extra path needs to the plugins folder + ps.println(" "); + ps.println(" "); + } + ps.println(" "); + + ps.println(""); + + } + + private void writePDE35Target(PrintStream ps, String pom, Set ids, String[] features) { + ps.println(XML_PI); + ps.println(""); + ps.println(ASL_HEADER); + + ps.println(""); + + if (executionEnvironment != null) { + ps + .println(" "); + } + + ps.println(""); + if (ids.size() > 0) { + ps.println(" "); + ps.println(" "); + for (String id : ids) { + ps.println(" "); + } + ps.println(" "); + ps.println(" "); + } + + /* + if (useDefaultLocation) { + ps.println(" "); + } + */ + + /* + if (features != null) { + for (String f : features) { + ps.println(" "); + } + } + */ + + ps.println(""); + ps.println(""); + + } + + private static void writePluginXML(PrintStream ps) { + ps.println(XML_PI); + ps.println(""); + ps.println(ASL_HEADER); + ps.println(""); + ps.println(""); + ps.println(""); + ps.println(""); + ps.println(""); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Extension.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Extension.java new file mode 100644 index 0000000000..dd4a9b502c --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Extension.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + + +public class Extension { + private String groupId; + private String artifactId; + private String version; + + 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 getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String toString() { + return groupId + ":" + artifactId + ":" + version; + } + + public boolean matches(Extension extension) { + return groupId.equals(extension.getGroupId()) && (artifactId == null || artifactId.equals("") + || artifactId.equals("*") || artifactId.equals(extension.getArtifactId())) + && (version == null || version.equals("") || version.equals("*") || version.equals(extension.getVersion())); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Feature.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Feature.java new file mode 100644 index 0000000000..41d3b2dc44 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/Feature.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +public class Feature { + private String groupId; + private String artifactId; + private String version; + + 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 getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String toString() { + return groupId + ":" + artifactId + ":" + version; + } + + public boolean matches(Feature feature) { + return groupId.equals(feature.getGroupId()) && (artifactId == null || artifactId.equals("") + || artifactId.equals("*") || artifactId.equals(feature.getArtifactId())) + && (version == null || version.equals("") || version.equals("*") || version.equals(feature.getVersion())); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/HeaderParser.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/HeaderParser.java new file mode 100644 index 0000000000..c49261e3ff --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/HeaderParser.java @@ -0,0 +1,331 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.maven.bundle.plugin; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; + +/** + * Parser for the service descriptors. The syntax of the service declaration is similar with the OSGi + * headers with the following exceptions: + *
    + *
  • Tuscany uses , and ; as the separator for attibutes + *
  • Tuscany + */ +public class HeaderParser { + + private static final String PATH_SEPARATOR = ","; // OSGi style + // private static final String PATH_SEPARATOR = "|"; + + private static final String SEGMENT_SEPARATOR = ";"; // OSGi style + // private static final String SEGMENT_SEPARATOR = ";,"; + + private static final String ATTRIBUTE_SEPARATOR = "="; + private static final String DIRECTIVE_SEPARATOR = ":="; + + private static final char QUOTE_CHAR = '"'; + private static final String QUOTE = "\""; + + // Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2, + // path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2 + public static List parse(String header) { + + if (header != null) { + if (header.length() == 0) { + throw new IllegalArgumentException("A header cannot be an empty string."); + } + + String[] clauseStrings = parseDelimitedString(header, PATH_SEPARATOR); + + List completeList = new ArrayList(); + for (int i = 0; (clauseStrings != null) && (i < clauseStrings.length); i++) { + completeList.add(parseClause(clauseStrings[i])); + } + + return completeList; + } + + return null; + + } + + // Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2 + private static HeaderClause parseClause(String clauseString) throws IllegalArgumentException { + // Break string into semi-colon delimited pieces. + String[] pieces = parseDelimitedString(clauseString, SEGMENT_SEPARATOR); + + // Count the number of different paths; paths + // will not have an '=' in their string. This assumes + // that paths come first, before directives and + // attributes. + int pathCount = 0; + for (int pieceIdx = 0; pieceIdx < pieces.length; pieceIdx++) { + if (pieces[pieceIdx].indexOf('=') >= 0) { + break; + } + pathCount++; + } + + // Create an array of paths. + String[] paths = new String[pathCount]; + System.arraycopy(pieces, 0, paths, 0, pathCount); + + // Parse the directives/attributes. + Map dirsMap = new HashMap(); + Map attrsMap = new HashMap(); + int idx = -1; + String sep = null; + for (int pieceIdx = pathCount; pieceIdx < pieces.length; pieceIdx++) { + // Check if it is a directive. + if ((idx = pieces[pieceIdx].indexOf(DIRECTIVE_SEPARATOR)) >= 0) { + sep = DIRECTIVE_SEPARATOR; + } + // Check if it is an attribute. + else if ((idx = pieces[pieceIdx].indexOf(ATTRIBUTE_SEPARATOR)) >= 0) { + sep = ATTRIBUTE_SEPARATOR; + } + // It is an error. + else { + throw new IllegalArgumentException("Not a directive/attribute: " + clauseString); + } + + String key = pieces[pieceIdx].substring(0, idx).trim(); + String value = pieces[pieceIdx].substring(idx + sep.length()).trim(); + + // Remove quotes, if value is quoted. + if (value.startsWith(QUOTE) && value.endsWith(QUOTE)) { + value = value.substring(1, value.length() - 1); + } + + // Save the directive/attribute in the appropriate array. + if (sep.equals(DIRECTIVE_SEPARATOR)) { + // Check for duplicates. + if (dirsMap.get(key) != null) { + throw new IllegalArgumentException("Duplicate directive: " + key); + } + dirsMap.put(key, value); + } else { + // Check for duplicates. + if (attrsMap.get(key) != null) { + throw new IllegalArgumentException("Duplicate attribute: " + key); + } + attrsMap.put(key, value); + } + } + + StringBuffer path = new StringBuffer(); + for (int i = 0; i < paths.length; i++) { + path.append(paths[i]); + if (i != paths.length - 1) { + path.append(';'); + } + } + + HeaderClause descriptor = new HeaderClause(); + descriptor.text = clauseString; + descriptor.value = path.toString(); + descriptor.valueComponents = paths; + descriptor.attributes = attrsMap; + descriptor.directives = dirsMap; + + return descriptor; + } + + /** + * Parses delimited string and returns an array containing the tokens. This + * parser obeys quotes, so the delimiter character will be ignored if it is + * inside of a quote. This method assumes that the quote character is not + * included in the set of delimiter characters. + * @param value the delimited string to parse. + * @param delim the characters delimiting the tokens. + * @return an array of string tokens or null if there were no tokens. + **/ + private static String[] parseDelimitedString(String value, String delim) { + if (value == null) { + value = ""; + } + + List list = new ArrayList(); + + int CHAR = 1; + int DELIMITER = 2; + int STARTQUOTE = 4; + int ENDQUOTE = 8; + + StringBuffer sb = new StringBuffer(); + + int expecting = (CHAR | DELIMITER | STARTQUOTE); + + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + + boolean isDelimiter = (delim.indexOf(c) >= 0); + boolean isQuote = (c == QUOTE_CHAR); + + if (isDelimiter && ((expecting & DELIMITER) > 0)) { + list.add(sb.toString().trim()); + sb.delete(0, sb.length()); + expecting = (CHAR | DELIMITER | STARTQUOTE); + } else if (isQuote && ((expecting & STARTQUOTE) > 0)) { + sb.append(c); + expecting = CHAR | ENDQUOTE; + } else if (isQuote && ((expecting & ENDQUOTE) > 0)) { + sb.append(c); + expecting = (CHAR | STARTQUOTE | DELIMITER); + } else if ((expecting & CHAR) > 0) { + sb.append(c); + } else { + throw new IllegalArgumentException("Invalid delimited string: " + value); + } + } + + if (sb.length() > 0) { + list.add(sb.toString().trim()); + } + + return (String[])list.toArray(new String[list.size()]); + } + + public static class HeaderClause { + private String text; + private String value; + private String[] valueComponents; + private Map attributes; + private Map directives; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String[] getValueComponents() { + return valueComponents; + } + + public void setValueComponents(String[] valueComponents) { + this.valueComponents = valueComponents; + } + + public Map getAttributes() { + return attributes; + } + + public Map getDirectives() { + return directives; + } + + public String toString() { + String text = null; + if (text == null) { + StringBuffer buf = new StringBuffer(); + if (value == null) { + int start = buf.length(); + for (int i = 0; i < valueComponents.length; i++) { + if (i != valueComponents.length - 1) { + buf.append(valueComponents[i]).append(';'); + } else { + buf.append(valueComponents[i]); + } + } + int end = buf.length(); + if (end > start) { + value = buf.substring(start, end); + } + } + buf.append(value); + for (Map.Entry e : attributes.entrySet()) { + buf.append(';').append(e.getKey()).append("=\"").append(e.getValue()).append("\""); + } + for (Map.Entry e : directives.entrySet()) { + buf.append(';').append(e.getKey()).append(":=\"").append(e.getValue()).append("\""); + } + text = buf.toString(); + } + return text; + } + + } + + /** + * Returns a QName object from a QName expressed as {ns}name + * or ns#name. + * + * @param qname + * @return + */ + public static QName getQName(String qname) { + if (qname == null) { + return null; + } + qname = qname.trim(); + if (qname.startsWith("{")) { + int h = qname.indexOf('}'); + if (h != -1) { + return new QName(qname.substring(1, h), qname.substring(h + 1)); + } + } else { + int h = qname.indexOf('#'); + if (h != -1) { + return new QName(qname.substring(0, h), qname.substring(h + 1)); + } + } + return new QName(qname); + } + + public static String toHeader(List descriptors) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < descriptors.size(); i++) { + HeaderClause descriptor = descriptors.get(i); + buf.append(descriptor); + if (i != descriptors.size() - 1) { + buf.append(','); + } + } + return buf.toString(); + } + + public static String merge(String... headers) { + List merged = new ArrayList(); + for (String header : headers) { + if (header == null || header.length() == 0) { + continue; + } + List descriptors = parse(header); + merged.addAll(descriptors); + } + Set values = new HashSet(); + for (Iterator i = merged.iterator(); i.hasNext();) { + if (!values.add(i.next().getValue())) { + i.remove(); + } + } + return toHeader(merged); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java new file mode 100644 index 0000000000..12733181e8 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java @@ -0,0 +1,1338 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +import static org.apache.tuscany.maven.bundle.plugin.BundleUtil.write; +import static org.osgi.framework.Constants.BUNDLE_CLASSPATH; +import static org.osgi.framework.Constants.BUNDLE_VERSION; +import static org.osgi.framework.Constants.RESOLUTION_DIRECTIVE; +import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL; +import static org.osgi.framework.Constants.VISIBILITY_DIRECTIVE; +import static org.osgi.framework.Constants.VISIBILITY_REEXPORT; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.resolver.ArtifactCollector; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectBuilder; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.artifact.InvalidDependencyVersionException; +import org.apache.maven.shared.dependency.tree.DependencyNode; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; +import org.apache.maven.shared.dependency.tree.traversal.CollectingDependencyNodeVisitor; +import org.osgi.framework.Constants; + +/** + * A maven plugin that generates a modules directory containing OSGi bundles for all the project's module dependencies. + * + * @version $Rev$ $Date$ + * @goal generate-modules + * @phase generate-resources + * @requiresDependencyResolution test + * @description Generate a modules directory containing OSGi bundles for all the project's module dependencies. + */ +public class ModuleBundlesBuildMojo extends AbstractMojo { + + private static final String GATEWAY_BUNDLE = "org.apache.tuscany.sca.gateway"; + + /** + * The project to create a distribution for. + * + * @parameter expression="${project}" + * @required + * @readonly + */ + private MavenProject project; + + /** + * Project builder -- builds a model from a pom.xml + * + * @component role="org.apache.maven.project.MavenProjectBuilder" + * @required + * @readonly + */ + private MavenProjectBuilder mavenProjectBuilder; + /** + * Used to look up Artifacts in the remote repository. + * + * @component + */ + private org.apache.maven.artifact.factory.ArtifactFactory factory; + + /** + * Used to look up Artifacts in the remote repository. + * + * @component + */ + private org.apache.maven.artifact.resolver.ArtifactResolver resolver; + + /** + * @component role="org.apache.maven.artifact.metadata.ArtifactMetadataSource" + * hint="maven" + * @required + * @readonly + */ + private ArtifactMetadataSource artifactMetadataSource; + + /** + * The artifact collector to use. + * + * @component + * @required + * @readonly + */ + private ArtifactCollector artifactCollector; + + /** + * The dependency tree builder to use. + * + * @component + * @required + * @readonly + */ + private DependencyTreeBuilder dependencyTreeBuilder; + + + /** + * Location of the local repository. + * + * @parameter expression="${localRepository}" + * @readonly + * @required + */ + private org.apache.maven.artifact.repository.ArtifactRepository local; + + /** + * List of Remote Repositories used by the resolver + * + * @parameter expression="${project.remoteArtifactRepositories}" + * @readonly + * @required + */ + private java.util.List remoteRepos; + + /** + * Target directory. + * + * @parameter expression="${project.build.directory}/modules" + */ + private File targetDirectory; + + /** + * @parameter default-value="features" + */ + private String featuresName = "features"; + + /** + * Directories containing artifacts to exclude. + * + * @parameter + */ + private File[] excludeDirectories; + + /** + * Directories containing groupids to exclude. + * + * @parameter + */ + private String[] excludeGroupIds; + + /** + * Directories containing groupids to include. + * + * @parameter + */ + private String[] includeGroupIds; + + /** + * Set to true to generate configurations under a folder named as the distro + * + * @parameter default-value="true" + */ + private boolean useDistributionName = true; + + /** + * Set to true to generate a PDE target platform configuration. + * + * @parameter default-value="true" + */ + private boolean generateTargetPlatform = true; + + /** + * Expand non-tuscany bundles as a folder + * @parameter default-value="false" + */ + private boolean expandThirdPartyBundle = false; + + /** + * OSGi execution environment + */ + private String executionEnvironment; + + /** + * A list of Eclipse features to be added to the target definition + * @parameter + */ + private String[] eclipseFeatures; + + /** + * If we use the running eclipse as the default location for the target + * @parameter default-value="true" + */ + private boolean useDefaultLocation = true; + + /** + * Set to true to generate a gateway bundle tuscany-gateway-.jar that handles split packages and META-INF/services. + * + * @parameter default-value="true" + */ + private boolean generateGatewayBundle; + + /** + * @parameter default-value="false" + */ + private boolean gatewayReexport; + + /** + * Set to true to generate a plugin.xml. + * + * @parameter default-value="false" + */ + private boolean generatePlugin; + + /** + * Generate a configuration/config.ini for equinox + * @parameter default-value="true" + */ + private boolean generateConfig = true; + + /** + * Generate an aggregated OSGi bundle for each feature + * @parameter default-value="false" + */ + private boolean generateAggregatedBundle = false; + + /** + * @parameter default-value="true" + */ + private boolean generateBundleStart = true; + + /** + * @parameter default-value="true" + */ + private boolean includeConflictingDepedencies = true; + + /** + * Generete manifest.jar + * @parameter default-value="true" + */ + private boolean generateManifestJar = true; + + /** + * @parameter default-value="tuscany-sca-manifest.jar" + */ + private String manifestJarName = "tuscany-sca-manifest.jar"; + + /** + * @parameter default-value="tuscany-sca-equinox-manifest.jar" + */ + private String equinoxManifestJarName = "tuscany-sca-equinox-manifest.jar"; + + /** + * @parameter default-value="jar,bundle" + */ + private String artifactTypes; + + /** + * @parameter default-value="true" + */ + private boolean generateAntScript = true; + + /** + * @parameter + */ + private ArtifactAggregation[] artifactAggregations; + + /** + * @parameter + */ + private ArtifactManifest[] artifactManifests; + + /** + * Inserts a generic Eclipse-BuddyPolicy header into generated artifacts manifests + * @parameter + */ + private String eclipseBuddyPolicy = null; + + private static final String XML_PI = ""; + private static final String ASL_HEADER = + ""; + + /** + * Group the artifacts by distribution poms + */ + private class ProjectSet { + // Distribution projects + private Map projects; + // Key: the pom artifact id + // Value: the names for the artifacts + private Map> nameMap = new HashMap>(); + + private Map artifactToNameMap = new HashMap(); + + public ProjectSet(List projects) { + super(); + this.projects = new HashMap(); + for (MavenProject p : projects) { + this.projects.put(p.getArtifactId(), p); + } + } + + private MavenProject getProject(String artifactId) { + return projects.get(artifactId); + } + + private void add(Artifact artifact, String name) { + String key = ArtifactUtils.versionlessKey(artifact); + for (MavenProject p : projects.values()) { + Artifact a = (Artifact)p.getArtifactMap().get(key); + if (a != null) { + Set names = nameMap.get(p.getArtifactId()); + if (names == null) { + names = new HashSet(); + nameMap.put(p.getArtifactId(), names); + } + names.add(name); + } + } + artifactToNameMap.put(key, name); + } + } + + private Manifest findManifest(Artifact artifact) throws IOException { + if (artifactManifests == null) { + return null; + } + for (ArtifactManifest m : artifactManifests) { + if (m.matches(artifact)) { + File mf = m.getManifestFile(); + if (mf != null) { + FileInputStream is = new FileInputStream(mf); + Manifest manifest = new Manifest(is); + is.close(); + getLog().info("MANIFEST.MF found for " + artifact + " (" + mf + ")"); + return manifest; + } else { + getLog().info("Overriding the manifest for " + artifact); + Manifest manifest = BundleUtil.getManifest(artifact.getFile()); + Set jarFiles = new HashSet(); + jarFiles.add(artifact.getFile()); + String symbolicName = BundleUtil.getBundleSymbolicName(manifest); + if (symbolicName == null) { + // Not a bundle + continue; + } + String version = manifest.getMainAttributes().getValue(BUNDLE_VERSION); + manifest = + BundleUtil.libraryManifest(jarFiles, + symbolicName, + symbolicName, + version, + null, + this.eclipseBuddyPolicy, + this.executionEnvironment); + // Remove it as it will be added later on + manifest.getMainAttributes().remove(new Attributes.Name(BUNDLE_CLASSPATH)); + return manifest; + } + } + } + return null; + } + + /** + * Gets the artifact filter to use when resolving the dependency tree. + * + * @return the artifact filter + */ + private ArtifactFilter createResolvingArtifactFilter(String scope) { + ArtifactFilter filter; + + // filter scope + if (scope != null) { + getLog().debug("+ Resolving dependency tree for scope '" + scope + "'"); + + filter = new ScopeArtifactFilter(scope); + } else { + filter = null; + } + + return filter; + } + + public void execute() throws MojoExecutionException { + Log log = getLog(); + + Set artifacts = null; + if (includeConflictingDepedencies) { + try { + artifacts = getDependencyArtifacts(project); + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + } else { + artifacts = project.getArtifacts(); + } + + try { + + // Create the target directory + File root; + if (targetDirectory == null) { + root = new File(project.getBuild().getDirectory(), "plugins/"); + } else { + root = targetDirectory; + } + root.mkdirs(); + + // Build sets of exclude directories and included/excluded/groupids + Set excludedFileNames = new HashSet(); + if (excludeDirectories != null) { + for (File f : excludeDirectories) { + if (f.isDirectory()) { + for (String n : f.list()) { + excludedFileNames.add(n); + } + } + } + } + Set includedGroupIds = new HashSet(); + if (includeGroupIds != null) { + for (String g : includeGroupIds) { + includedGroupIds.add(g); + } + } + Set excludedGroupIds = new HashSet(); + if (excludeGroupIds != null) { + for (String g : excludeGroupIds) { + excludedGroupIds.add(g); + } + } + + // Find all the distribution poms + List poms = new ArrayList(); + poms.add(project); + if (useDistributionName) { + for (Object o : project.getArtifacts()) { + Artifact artifact = (Artifact)o; + if ("pom".equals(artifact.getType()) && artifact.getGroupId().equals(project.getGroupId()) + && artifact.getArtifactId().startsWith("tuscany-feature-")) { + log.info("Dependent distribution: " + artifact); + MavenProject pomProject = buildProject(artifact); + poms.add(pomProject); + // log.info(pomProject.getArtifactMap().toString()); + } + } + } + + // Process all the dependency artifacts + ProjectSet bundleSymbolicNames = new ProjectSet(poms); + ProjectSet bundleLocations = new ProjectSet(poms); + ProjectSet jarNames = new ProjectSet(poms); + ProjectSet serviceProviders = new ProjectSet(poms); + + for (Artifact artifact: artifacts) { + + // Only consider Compile and Runtime dependencies + if (!(Artifact.SCOPE_COMPILE.equals(artifact.getScope()) || Artifact.SCOPE_RUNTIME.equals(artifact + .getScope()) + || Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) || (generateTargetPlatform && Artifact.SCOPE_TEST + .equals(artifact.getScope())))) { + log.info("Skipping artifact: " + artifact); + continue; + } + + if (artifactTypes == null) { + artifactTypes = "jar,bundle"; + } + String types[] = artifactTypes.trim().split("( |\t|\n|\r|\f|,)+"); + Set typeSet = new HashSet(Arrays.asList(types)); + + // Only consider JAR and WAR files + if (!typeSet.contains(artifact.getType())) { + log.debug("Artifact with unknown type is skipped: " + artifact); + continue; + } + + // Exclude artifact if its groupId is excluded or if it's not included + if (excludedGroupIds.contains(artifact.getGroupId())) { + log.debug("Artifact groupId is excluded: " + artifact); + continue; + } + if (!includedGroupIds.isEmpty()) { + if (!includedGroupIds.contains(artifact.getGroupId())) { + log.debug("Artifact groupId is not included: " + artifact); + continue; + } + } + + File artifactFile = artifact.getFile(); + if (!artifactFile.exists()) { + log.warn("Artifact doesn't exist: " + artifact); + continue; + } + + if (log.isDebugEnabled()) { + log.debug("Processing artifact: " + artifact); + } + + Manifest customizedMF = findManifest(artifact); + + // Get the bundle name if the artifact is an OSGi bundle + Manifest mf = null; + String bundleName = null; + try { + mf = BundleUtil.getManifest(artifactFile); + bundleName = BundleUtil.getBundleSymbolicName(mf); + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + if (bundleName != null && customizedMF == null) { + + // Exclude artifact if its file name is excluded + if (excludedFileNames.contains(artifactFile.getName())) { + log.debug("Artifact file is excluded: " + artifact); + continue; + } + + // Copy an OSGi bundle as is + log.info("Adding OSGi bundle artifact: " + artifact); + + if (!expandThirdPartyBundle || artifact.getGroupId().startsWith("org.apache.tuscany.sca") + || artifact.getGroupId().startsWith("org.eclipse")) { + copyFile(artifactFile, root); + bundleSymbolicNames.add(artifact, bundleName); + bundleLocations.add(artifact, artifactFile.getName()); + jarNames.add(artifact, artifactFile.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, bundleName); + } + } else { + // Expanding the bundle into a folder + + setBundleClassPath(mf, artifactFile); + + int index = artifactFile.getName().lastIndexOf('.'); + String dirName = artifactFile.getName().substring(0, index); + File dir = new File(root, dirName); + + File file = new File(dir, "META-INF"); + file.mkdirs(); + file = new File(file, "MANIFEST.MF"); + + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + copyFile(artifactFile, dir); + bundleSymbolicNames.add(artifact, bundleName); + bundleLocations.add(artifact, dir.getName()); + jarNames.add(artifact, dirName + "/" + artifactFile.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, bundleName); + } + } + + } else if ("war".equals(artifact.getType())) { + + // Exclude artifact if its file name is excluded + if (excludedFileNames.contains(artifactFile.getName())) { + log.debug("Artifact file is excluded: " + artifact); + continue; + } + + // Copy a WAR as is + log.info("Adding WAR artifact: " + artifact); + copyFile(artifactFile, root); + + } else { + + int index = artifactFile.getName().lastIndexOf('.'); + String dirName = artifactFile.getName().substring(0, index); + File dir = new File(root, dirName); + + // Exclude artifact if its file name is excluded + if (excludedFileNames.contains(dir.getName())) { + log.debug("Artifact file is excluded: " + artifact); + continue; + } + + if (artifactAggregations != null) { + boolean aggregated = false; + for (ArtifactAggregation group : artifactAggregations) { + if (group.matches(artifact)) { + group.getArtifacts().add(artifact); + aggregated = true; + break; + } + } + if (aggregated) { + continue; + } + } + + // Create a bundle directory for a non-OSGi JAR + log.info("Adding JAR artifact: " + artifact); + + // create manifest directory + File file = new File(dir, "META-INF"); + file.mkdirs(); + + String symbolicName = null; + if (customizedMF == null) { + String version = BundleUtil.osgiVersion(artifact.getVersion()); + + Set jarFiles = new HashSet(); + jarFiles.add(artifactFile); + symbolicName = (artifact.getGroupId() + "." + artifact.getArtifactId()); + mf = + BundleUtil.libraryManifest(jarFiles, + symbolicName, + symbolicName, + version, + null, + this.eclipseBuddyPolicy, + this.executionEnvironment); + + file = new File(file, "MANIFEST.MF"); + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + log.info("Writing generated manifest for: " + artifact + " to " + file); + } else { + mf = customizedMF; + symbolicName = BundleUtil.getBundleSymbolicName(mf); + if (symbolicName == null) { + throw new MojoExecutionException("Invalid customized MANIFEST.MF for " + artifact); + } + setBundleClassPath(mf, artifactFile); + + // re-find the custom MF file and copy it + // I can't get the manifest file from the manifest itself + // the Manifest read/write operation seems to be filtering + // out some entries that I've added manually???? + File artifactManifest = null; + + if (artifactManifests != null) { + for (ArtifactManifest m : artifactManifests) { + if (m.matches(artifact)) { + artifactManifest = m.getManifestFile(); + break; + } + } + } + + file = new File(file, "MANIFEST.MF"); + + if (artifactManifest != null){ + log.info("Copying: " + artifactManifest + " to " + file); + copyManifest(artifactManifest, file); + } else { + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + log.info("Writing generated manifest for: " + artifact + " to " + file); + } + } + + copyFile(artifactFile, dir); + bundleSymbolicNames.add(artifact, symbolicName); + bundleLocations.add(artifact, dir.getName()); + jarNames.add(artifact, dirName + "/" + artifactFile.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, symbolicName); + } + } + } + + if (artifactAggregations != null) { + for (ArtifactAggregation group : artifactAggregations) { + if (group.getArtifacts().isEmpty()) { + continue; + } + String symbolicName = group.getSymbolicName(); + String version = group.getVersion(); + File dir = new File(root, symbolicName + "-" + version); + dir.mkdir(); + Set jarFiles = new HashSet(); + Artifact artifact = null; + for (Artifact a : group.getArtifacts()) { + log.info("Aggragating JAR artifact: " + a); + artifact = a; + jarFiles.add(a.getFile()); + copyFile(a.getFile(), dir); + jarNames.add(a, symbolicName + "-" + version + "/" + a.getFile().getName()); + } + Manifest mf = + BundleUtil.libraryManifest(jarFiles, + symbolicName, + symbolicName, + version, + null, + this.eclipseBuddyPolicy, + this.executionEnvironment); + File file = new File(dir, "META-INF"); + file.mkdirs(); + file = new File(file, "MANIFEST.MF"); + + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + log.info("Written aggregate manifest"); + bundleSymbolicNames.add(artifact, symbolicName); + bundleLocations.add(artifact, dir.getName()); + if (isServiceProvider(mf)) { + serviceProviders.add(artifact, symbolicName); + } + } + } + + if (generateGatewayBundle) { + generateGatewayBundle(serviceProviders); + } + + /* + if (useDistributionName) { + bundleLocations.nameMap.remove(project.getArtifactId()); + jarNames.nameMap.remove(project.getArtifactId()); + bundleSymbolicNames.nameMap.remove(project.getArtifactId()); + } + */ + + // Generate a PDE target + if (generateTargetPlatform) { + generatePDETarget(bundleSymbolicNames, root, log); + } + + // Generate a plugin.xml referencing the PDE target + if (generatePlugin) { + File pluginxml = new File(project.getBasedir(), "plugin.xml"); + FileOutputStream pluginXMLFile = new FileOutputStream(pluginxml); + writePluginXML(new PrintStream(pluginXMLFile)); + pluginXMLFile.close(); + } + + if (generateConfig) { + generateEquinoxConfig(bundleLocations, root, log); + } + + if (generateManifestJar) { + generateManifestJar(jarNames, root, log); + generateEquinoxLauncherManifestJar(jarNames, root, log); + } + + if (generateAntScript) { + generateANTPath(jarNames, root, log); + } + + if (generateAggregatedBundle) { + generateAggregatedBundles(bundleLocations, root, log); + } + + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + } + + private Set getDependencyArtifacts(MavenProject project) throws DependencyTreeBuilderException, + ArtifactResolutionException, ArtifactNotFoundException { + Log log = getLog(); + Set artifacts = new HashSet(); + ArtifactFilter artifactFilter = createResolvingArtifactFilter(Artifact.SCOPE_RUNTIME); + + // TODO: note that filter does not get applied due to MNG-3236 + + DependencyNode rootNode = + dependencyTreeBuilder.buildDependencyTree(project, + local, + factory, + artifactMetadataSource, + artifactFilter, + artifactCollector); + CollectingDependencyNodeVisitor visitor = new CollectingDependencyNodeVisitor(); + rootNode.accept(visitor); + + // Add included artifacts + for (Object node : visitor.getNodes()) { + DependencyNode depNode = (DependencyNode)node; + int state = depNode.getState(); + if (state == DependencyNode.INCLUDED ) { + Artifact artifact = depNode.getArtifact(); + // Exclude the project artifact to avoid offline resolution failure + if (!artifact.equals(project.getArtifact())) { + resolver.resolve(artifact, remoteRepos, local); + artifacts.add(artifact); + } + } + } + // Scan for newer versions that are omitted + for (Object node : visitor.getNodes()) { + DependencyNode depNode = (DependencyNode)node; + int state = depNode.getState(); + if (state == DependencyNode.OMITTED_FOR_CONFLICT) { + Artifact artifact = depNode.getArtifact(); + resolver.resolve(artifact, remoteRepos, local); + if (state == DependencyNode.OMITTED_FOR_CONFLICT) { + Artifact related = depNode.getRelatedArtifact(); + if (log.isDebugEnabled()) { + log.debug("Dependency node: " + depNode); + } + // Compare the version + ArtifactVersion v1 = new DefaultArtifactVersion(artifact.getVersion()); + ArtifactVersion v2 = new DefaultArtifactVersion(related.getVersion()); + if (v1.compareTo(v2) > 0) { + // Only add newer version if it is omitted for conflict + if (artifacts.add(artifact)) { + log.info("Dependency node added: " + depNode); + } + } + } + } + } + return artifacts; + } + + private static boolean isServiceProvider(Manifest mf) { + if (mf != null) { + String export = (String)mf.getMainAttributes().getValue(Constants.EXPORT_PACKAGE); + if (export != null && export.contains(BundleUtil.META_INF_SERVICES)) { + return true; + } + } + return false; + } + + /** + * Generate a gateway bundle that aggregate other bundles to handle split packages + * @param bundleSymbolicNames + * @throws FileNotFoundException + * @throws IOException + */ + private void generateGatewayBundle(ProjectSet bundleSymbolicNames) throws FileNotFoundException, IOException { + Manifest manifest = new Manifest(); + Attributes attrs = manifest.getMainAttributes(); + StringBuffer requireBundle = new StringBuffer(); + for (String name : new HashSet(bundleSymbolicNames.artifactToNameMap.values())) { + requireBundle.append(name).append(";").append(RESOLUTION_DIRECTIVE).append(":=") + .append(RESOLUTION_OPTIONAL); + if (gatewayReexport) { + requireBundle.append(";").append(VISIBILITY_DIRECTIVE).append(":=").append(VISIBILITY_REEXPORT); + } + requireBundle.append(","); + } + int len = requireBundle.length(); + if (len > 0 && requireBundle.charAt(len - 1) == ',') { + requireBundle.deleteCharAt(len - 1); + attrs.putValue(Constants.REQUIRE_BUNDLE, requireBundle.toString()); + attrs.putValue("Manifest-Version", "1.0"); + attrs.putValue("Implementation-Vendor", "The Apache Software Foundation"); + attrs.putValue("Implementation-Vendor-Id", "org.apache"); + attrs.putValue(Constants.BUNDLE_VERSION, "2.0.0"); + attrs.putValue(Constants.BUNDLE_MANIFESTVERSION, "2"); + attrs.putValue(Constants.BUNDLE_SYMBOLICNAME, GATEWAY_BUNDLE); + attrs.putValue(Constants.BUNDLE_NAME, "Apache Tuscany SCA Gateway Bundle"); + attrs.putValue(Constants.BUNDLE_VENDOR, "The Apache Software Foundation"); + attrs.putValue(Constants.EXPORT_PACKAGE, "META-INF.services"); + attrs.putValue(Constants.DYNAMICIMPORT_PACKAGE, "*"); + attrs.putValue(Constants.BUNDLE_ACTIVATIONPOLICY, Constants.ACTIVATION_LAZY); + File file = new File(targetDirectory, "tuscany-gateway-" + project.getVersion() + ".jar"); + getLog().info("Generating gateway bundle: " + file.getAbsolutePath()); + FileOutputStream fos = new FileOutputStream(file); + JarOutputStream jos = new JarOutputStream(fos, manifest); + addFileToJar(jos, "META-INF/LICENSE", getClass().getResource("LICENSE.txt")); + addFileToJar(jos, "META-INF/NOTICE", getClass().getResource("NOTICE.txt")); + jos.close(); + } + } + + private void setBundleClassPath(Manifest mf, File artifactFile) { + // Add the Bundle-ClassPath + String cp = mf.getMainAttributes().getValue(BUNDLE_CLASSPATH); + if (cp == null) { + cp = artifactFile.getName(); + } else { + cp = cp + "," + artifactFile.getName(); + } + mf.getMainAttributes().putValue(BUNDLE_CLASSPATH, cp); + } + + private void generateANTPath(ProjectSet jarNames, File root, Log log) throws FileNotFoundException, IOException { + for (Map.Entry> e : jarNames.nameMap.entrySet()) { + Set jars = e.getValue(); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + feature.mkdirs(); + File antPath = new File(feature, "build-path.xml"); + log.info("Generating ANT build path: " + antPath.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(antPath); + PrintStream ps = new PrintStream(fos); + // ps.println(XML_PI); + ps.println(ASL_HEADER); + String name = trim(e.getKey()); + ps.println(""); + ps.println(" "); + ps.println(" "); + ps.println(" "); + ps.println(" "); + for (String jar : jars) { + ps.println(" "); + } + ps.println(" "); + ps.println(" "); + ps.println(""); + } + } + + private void generateManifestJar(ProjectSet jarNames, File root, Log log) throws FileNotFoundException, IOException { + for (Map.Entry> e : jarNames.nameMap.entrySet()) { + MavenProject pom = jarNames.getProject(e.getKey()); + Set jars = e.getValue(); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + feature.mkdirs(); + File mfJar = new File(feature, manifestJarName); + log.info("Generating manifest jar: " + mfJar.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(mfJar); + Manifest mf = new Manifest(); + StringBuffer cp = new StringBuffer(); + String path = (useDistributionName ? "../../" : "../") + root.getName(); + for (String jar : jars) { + cp.append(path).append('/').append(jar).append(' '); + } + if (cp.length() > 0) { + cp.deleteCharAt(cp.length() - 1); + } + Attributes attrs = mf.getMainAttributes(); + attrs.putValue("Manifest-Version", "1.0"); + attrs.putValue("Implementation-Title", pom.getName()); + attrs.putValue("Implementation-Vendor", "The Apache Software Foundation"); + attrs.putValue("Implementation-Vendor-Id", "org.apache"); + attrs.putValue("Implementation-Version", pom.getVersion()); + attrs.putValue("Class-Path", cp.toString()); + attrs.putValue("Main-Class", "org.apache.tuscany.sca.node.launcher.NodeMain"); + JarOutputStream jos = new JarOutputStream(fos, mf); + addFileToJar(jos, "META-INF/LICENSE", getClass().getResource("LICENSE.txt")); + addFileToJar(jos, "META-INF/NOTICE", getClass().getResource("NOTICE.txt")); + jos.close(); + } + } + + private void generateEquinoxLauncherManifestJar(ProjectSet jarNames, File root, Log log) throws Exception { + String equinoxLauncher = "org.apache.tuscany.sca:tuscany-node-launcher-equinox"; + Artifact artifact = (Artifact)project.getArtifactMap().get(equinoxLauncher); + if (artifact == null) { + return; + } + Set artifacts = resolveTransitively(artifact).getArtifacts(); + File feature = new File(root, "../" + featuresName + "/"); + feature.mkdirs(); + File mfJar = new File(feature, equinoxManifestJarName); + log.info("Generating equinox manifest jar: " + mfJar.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(mfJar); + Manifest mf = new Manifest(); + StringBuffer cp = new StringBuffer(); + String path = "../" + root.getName(); + + for (Object o : artifacts) { + Artifact a = (Artifact)o; + if (!Artifact.SCOPE_TEST.equals(a.getScope())) { + String id = ArtifactUtils.versionlessKey(a); + String jar = jarNames.artifactToNameMap.get(id); + if (jar != null) { + cp.append(path).append('/').append(jar).append(' '); + } + } + } + if (cp.length() > 0) { + cp.deleteCharAt(cp.length() - 1); + } + Attributes attrs = mf.getMainAttributes(); + attrs.putValue("Manifest-Version", "1.0"); + attrs.putValue("Implementation-Title", artifact.getId()); + attrs.putValue("Implementation-Vendor", "The Apache Software Foundation"); + attrs.putValue("Implementation-Vendor-Id", "org.apache"); + attrs.putValue("Implementation-Version", artifact.getVersion()); + attrs.putValue("Class-Path", cp.toString()); + attrs.putValue("Main-Class", "org.apache.tuscany.sca.node.equinox.launcher.NodeMain"); + JarOutputStream jos = new JarOutputStream(fos, mf); + addFileToJar(jos, "META-INF/LICENSE", getClass().getResource("LICENSE.txt")); + addFileToJar(jos, "META-INF/NOTICE", getClass().getResource("NOTICE.txt")); + jos.close(); + } + + private void generateEquinoxConfig(ProjectSet bundleLocations, File root, Log log) throws IOException { + for (Map.Entry> e : bundleLocations.nameMap.entrySet()) { + Set locations = new HashSet(e.getValue()); + if (generateGatewayBundle) { + locations.add("tuscany-gateway-" + project.getVersion() + ".jar"); + } + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? trim(e.getKey()) : "")); + File config = new File(feature, "configuration"); + config.mkdirs(); + File ini = new File(config, "config.ini"); + log.info("Generating configuation: " + ini.getCanonicalPath()); + FileOutputStream fos = new FileOutputStream(ini); + PrintStream ps = new PrintStream(fos); + int size = locations.size(); + if (size > 0) { + ps.println("osgi.bundles=\\"); + int count = 0; + for (String f : locations) { + if (f.startsWith("osgi")) { + count++; + continue; + } + ps.print(" "); + ps.print(f); + // FIXME: We should not add @start for fragments + if (generateBundleStart) { + ps.print("@:start"); + } + if (count == size - 1) { + // Last one + ps.println(); + } else { + ps.println(",\\"); + } + count++; + } + } + ps.println("eclipse.ignoreApp=true"); + // Do not shutdown + ps.println("osgi.noShutdown=true"); + ps.close(); + } + } + + private void generateAggregatedBundles(ProjectSet bundleLocations, File root, Log log) throws Exception { + for (Map.Entry> e : bundleLocations.nameMap.entrySet()) { + Set locations = new HashSet(e.getValue()); + String featureName = (useDistributionName ? trim(e.getKey()) : ""); + File feature = new File(root, "../" + featuresName + "/" + featureName); +// String bundleFileName = "tuscany-bundle-" + featureName + ".jar"; +// if ("".equals(featureName)) { +// bundleFileName = "tuscany-bundle.jar"; +// } + String bundleFileName = "tuscany-bundle.jar"; + File bundleFile = new File(feature, bundleFileName); + log.info("Generating aggregated OSGi bundle: " + bundleFile); + File[] files = new File[locations.size()]; + int i = 0; + for (String child : locations) { + files[i++] = new File(root, child); + } + String bundleVersion = "2.0.0"; + String bundleName = "org.apache.tuscany.sca.bundle"; + +// String bundleName = "org.apache.tuscany.sca.bundle." + featureName; +// if ("".equals(featureName)) { +// bundleName = "org.apache.tuscany.sca.bundle"; +// } + BundleAggregatorMojo.aggregateBundles(log, root, files, bundleFile, bundleName, bundleVersion); + } + } + + private void generatePDETarget(ProjectSet bundleSymbolicNames, File root, Log log) throws FileNotFoundException, + IOException { + for (Map.Entry> e : bundleSymbolicNames.nameMap.entrySet()) { + Set bundles = new HashSet(e.getValue()); + String name = trim(e.getKey()); + File feature = new File(root, "../" + featuresName + "/" + (useDistributionName ? name : "")); + feature.mkdirs(); + File target = new File(feature, "tuscany.target"); + log.info("Generating target definition: " + target.getCanonicalPath()); + FileOutputStream targetFile = new FileOutputStream(target); + if (!bundles.contains("org.eclipse.osgi")) { + bundles.add("org.eclipse.osgi"); + } + if (generateGatewayBundle) { + bundles.add(GATEWAY_BUNDLE); + } + writeTarget(new PrintStream(targetFile), name, bundles, eclipseFeatures); + targetFile.close(); + + // Generate the PDE target definition file for PDE 3.5 + File target35 = new File(feature, "tuscany-pde35.target"); + log.info("Generating target definition: " + target35.getCanonicalPath()); + FileOutputStream target35File = new FileOutputStream(target35); + writePDE35Target(new PrintStream(target35File), name, bundles, eclipseFeatures); + target35File.close(); + + } + } + + private MavenProject buildProject(Artifact artifact) throws ProjectBuildingException, + InvalidDependencyVersionException, ArtifactResolutionException, ArtifactNotFoundException, DependencyTreeBuilderException { + MavenProject pomProject = mavenProjectBuilder.buildFromRepository(artifact, this.remoteRepos, this.local); + if (pomProject.getDependencyArtifacts() == null) { + pomProject.setDependencyArtifacts(pomProject.createArtifacts(factory, null, // Artifact.SCOPE_TEST, + new ScopeArtifactFilter(Artifact.SCOPE_TEST))); + } + if (includeConflictingDepedencies) { + pomProject.setArtifacts(getDependencyArtifacts(pomProject)); + } else { + ArtifactResolutionResult result = + resolver.resolveTransitively(pomProject.getDependencyArtifacts(), + pomProject.getArtifact(), + remoteRepos, + local, + artifactMetadataSource); + pomProject.setArtifacts(result.getArtifacts()); + } + return pomProject; + } + + private ArtifactResolutionResult resolveTransitively(Artifact artifact) throws ArtifactResolutionException, + ArtifactNotFoundException { + Artifact originatingArtifact = factory.createBuildArtifact("dummy", "dummy", "1.0", "jar"); + + return resolver.resolveTransitively(Collections.singleton(artifact), + originatingArtifact, + local, + remoteRepos, + artifactMetadataSource, + null); + } + + /** + * Convert tuscany-feature-xyz to feature-xyz + * @param artifactId + * @return + */ + private String trim(String artifactId) { + if (artifactId.startsWith("tuscany-feature-")) { + return artifactId.substring("tuscany-feature-".length()); + } else { + return artifactId; + } + } + + private static void copyFile(File jar, File dir) throws FileNotFoundException, IOException { + byte[] buf = new byte[4096]; + File jarFile = new File(dir, jar.getName()); + FileInputStream in = new FileInputStream(jar); + FileOutputStream out = new FileOutputStream(jarFile); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.close(); + } + + private static void copyManifest(File mfFrom, File mfTo) throws FileNotFoundException, IOException { + byte[] buf = new byte[4096]; + FileInputStream in = new FileInputStream(mfFrom); + FileOutputStream out = new FileOutputStream(mfTo); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.close(); + } + + private static void addFileToJar(JarOutputStream out, String entryName, URL file) throws FileNotFoundException, + IOException { + byte[] buf = new byte[4096]; + InputStream in = file.openStream(); + out.putNextEntry(new ZipEntry(entryName)); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.closeEntry(); + } + + private void writeTarget(PrintStream ps, String pom, Set ids, String[] features) { + ps.println(XML_PI); + ps.println(""); + ps.println(ASL_HEADER); + + ps.println(""); + + if (executionEnvironment != null) { + ps.println(" "); + ps.println(" " + executionEnvironment + ""); + ps.println(" "); + } + + if (useDefaultLocation) { + ps.println(" "); + } else { + ps.println(" "); + } + + // ps.println(""); + ps.println(" "); + ps.println(" "); + for (String id : ids) { + ps.println(" "); + } + ps.println(" "); + ps.println(" "); + if (features != null) { + for (String f : features) { + ps.println(" "); + } + } + ps.println(" "); + if (useDefaultLocation) { + ps.println(" "); + // Not sure why the extra path needs to the plugins folder + ps.println(" "); + ps.println(" "); + } + ps.println(" "); + + ps.println(""); + + } + + private void writePDE35Target(PrintStream ps, String pom, Set ids, String[] features) { + ps.println(XML_PI); + ps.println(""); + ps.println(ASL_HEADER); + + ps.println(""); + + if (executionEnvironment != null) { + ps + .println(" "); + } + + ps.println(""); + if (ids.size() > 0) { + ps.println(" "); + ps.println(" "); + for (String id : ids) { + ps.println(" "); + } + ps.println(" "); + ps.println(" "); + } + + /* + if (useDefaultLocation) { + ps.println(" "); + } + */ + + /* + if (features != null) { + for (String f : features) { + ps.println(" "); + } + } + */ + + ps.println(""); + ps.println(""); + + } + + private static void writePluginXML(PrintStream ps) { + ps.println(XML_PI); + ps.println(""); + ps.println(ASL_HEADER); + ps.println(""); + ps.println(""); + ps.println(""); + ps.println(""); + ps.println(""); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java new file mode 100644 index 0000000000..d87ae0cb9f --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +import java.util.StringTokenizer; + +import org.apache.maven.artifact.versioning.ArtifactVersion; + +public class OSGIArtifactVersion implements ArtifactVersion { + private Integer buildNumber; + + private Integer incrementalVersion; + + private Integer majorVersion; + + private Integer minorVersion; + + private String qualifier; + + private String unparsed; + + public OSGIArtifactVersion(String version) { + parseVersion(version); + } + + public int compareTo(Object o) { + ArtifactVersion otherVersion = (ArtifactVersion)o; + + int result = getMajorVersion() - otherVersion.getMajorVersion(); + if (result == 0) { + result = getMinorVersion() - otherVersion.getMinorVersion(); + } + if (result == 0) { + result = getIncrementalVersion() - otherVersion.getIncrementalVersion(); + } + if (result == 0) { + if (this.qualifier != null) { + String otherQualifier = otherVersion.getQualifier(); + + if (otherQualifier != null) { + if ((this.qualifier.length() > otherQualifier.length()) && this.qualifier + .startsWith(otherQualifier)) { + // here, the longer one that otherwise match is + // considered older + result = -1; + } else if ((this.qualifier.length() < otherQualifier.length()) && otherQualifier + .startsWith(this.qualifier)) { + // here, the longer one that otherwise match is + // considered older + result = 1; + } else { + result = this.qualifier.compareTo(otherQualifier); + } + } else { + // otherVersion has no qualifier but we do - that's newer + result = -1; + } + } else if (otherVersion.getQualifier() != null) { + // otherVersion has a qualifier but we don't, we're newer + result = 1; + } else { + result = getBuildNumber() - otherVersion.getBuildNumber(); + } + } + return result; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (false == (other instanceof ArtifactVersion)) { + return false; + } + + return 0 == compareTo(other); + } + + public int getBuildNumber() { + return this.buildNumber != null ? this.buildNumber.intValue() : 0; + } + + public int getIncrementalVersion() { + return this.incrementalVersion != null ? this.incrementalVersion.intValue() : 0; + } + + public int getMajorVersion() { + return this.majorVersion != null ? this.majorVersion.intValue() : 0; + } + + public int getMinorVersion() { + return this.minorVersion != null ? this.minorVersion.intValue() : 0; + } + + public String getQualifier() { + return this.qualifier; + } + + @Override + public int hashCode() { + int result = 1229; + + result = 1223 * result + getMajorVersion(); + result = 1223 * result + getMinorVersion(); + result = 1223 * result + getIncrementalVersion(); + result = 1223 * result + getBuildNumber(); + + if (null != getQualifier()) { + result = 1223 * result + getQualifier().hashCode(); + } + + return result; + } + + public final void parseVersion(String version) { + this.unparsed = version; + + int index = version.indexOf("-"); + + String part1; + String part2 = null; + + if (index < 0) { + part1 = version; + } else { + part1 = version.substring(0, index); + part2 = version.substring(index + 1); + } + + if (part2 != null) { + try { + if ((part2.length() == 1) || !part2.startsWith("0")) { + this.buildNumber = Integer.valueOf(part2); + } else { + this.qualifier = part2; + } + } catch (NumberFormatException e) { + this.qualifier = part2; + } + } + + if ((part1.indexOf(".") < 0) && !part1.startsWith("0")) { + try { + this.majorVersion = Integer.valueOf(part1); + } catch (NumberFormatException e) { + // qualifier is the whole version, including "-" + this.qualifier = version; + this.buildNumber = null; + } + } else { + StringTokenizer tok = new StringTokenizer(part1, "."); + + String s; + + if (tok.hasMoreTokens()) { + s = tok.nextToken(); + try { + this.majorVersion = Integer.valueOf(s); + + if (tok.hasMoreTokens()) { + s = tok.nextToken(); + try { + this.minorVersion = Integer.valueOf(s); + if (tok.hasMoreTokens()) { + + s = tok.nextToken(); + try { + this.incrementalVersion = Integer.valueOf(s); + + } catch (NumberFormatException e) { + this.qualifier = s; + } + } + } catch (NumberFormatException e) { + this.qualifier = s; + } + } + } catch (NumberFormatException e) { + this.qualifier = s; + } + } + + if (tok.hasMoreTokens()) { + StringBuffer qualifier = new StringBuffer(this.qualifier != null ? this.qualifier : ""); + qualifier.append(tok.nextToken()); + while (tok.hasMoreTokens()) { + qualifier.append("_"); + qualifier.append(tok.nextToken()); + } + + this.qualifier = qualifier.toString(); + } + + } + } + + @Override + public String toString() { + return this.unparsed; + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java new file mode 100644 index 0000000000..880f1379e0 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.bundle.plugin; + +import static org.apache.tuscany.maven.bundle.plugin.BundleUtil.write; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.Manifest; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; + +/** + * A Maven plugin that builds an OSGi bundle for the project's third-party dependencies. + * + * @version $Rev$ $Date$ + * @goal assemble-thirdparty-bundle + * @phase generate-resources + * @requiresDependencyResolution test + * @description Build an OSGi bundle for the project's third party dependencies + */ +public class ThirdPartyBundleBuildMojo extends AbstractMojo { + + /** + * The project to build the bundle for. + * + * @parameter expression="${project}" + * @required + * @readonly + */ + private MavenProject project; + + /** + * The bundle symbolic name + * + * @parameter + */ + private String symbolicName; + + public void execute() throws MojoExecutionException { + Log log = getLog(); + + String projectGroupId = project.getGroupId(); + Set jarFiles = new HashSet(); + for (Object o : project.getArtifacts()) { + Artifact artifact = (Artifact)o; + + if (!(Artifact.SCOPE_COMPILE.equals(artifact.getScope()) || Artifact.SCOPE_RUNTIME.equals(artifact + .getScope()))) { + if (log.isDebugEnabled()) { + log.debug("Skipping artifact: " + artifact); + } + continue; + } + if (!"jar".equals(artifact.getType())) { + continue; + } + if (projectGroupId.equals(artifact.getGroupId())) { + continue; + } + + if (log.isDebugEnabled()) { + log.debug("Artifact: " + artifact); + } + String bundleName = null; + try { + bundleName = BundleUtil.getBundleSymbolicName(artifact.getFile()); + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + if (bundleName == null || true) { + if (artifact.getFile().exists()) { + log.info("Adding third party jar: " + artifact); + jarFiles.add(artifact.getFile()); + } else { + log.warn("Third party jar not found: " + artifact); + } + } + } + + try { + String version = BundleUtil.osgiVersion(project.getVersion()); + + Manifest mf = BundleUtil.libraryManifest(jarFiles, project.getName(), symbolicName, version, "lib"); + File file = new File(project.getBasedir(), "META-INF"); + file.mkdir(); + file = new File(file, "MANIFEST.MF"); + if (log.isDebugEnabled()) { + log.debug("Generating " + file); + } + + FileOutputStream fos = new FileOutputStream(file); + write(mf, fos); + fos.close(); + + File lib = new File(project.getBasedir(), "lib"); + if (lib.isDirectory()) { + for (File c : lib.listFiles()) { + c.delete(); + } + } + lib.mkdir(); + byte[] buf = new byte[4096]; + for (File jar : jarFiles) { + File jarFile = new File(lib, jar.getName()); + if (log.isDebugEnabled()) { + log.debug("Copying " + jar + " to " + jarFile); + } + FileInputStream in = new FileInputStream(jar); + FileOutputStream out = new FileOutputStream(jarFile); + for (;;) { + int len = in.read(buf); + if (len > 0) { + out.write(buf, 0, len); + } else { + break; + } + } + in.close(); + out.close(); + } + } catch (Exception e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + } + +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/AbstractIdeSupportMojo.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/AbstractIdeSupportMojo.java new file mode 100644 index 0000000000..6fc8295a4e --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/AbstractIdeSupportMojo.java @@ -0,0 +1,1150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.plugin.eclipse; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.jar.Manifest; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactCollector; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.artifact.resolver.DebugResolutionListener; +import org.apache.maven.artifact.resolver.ResolutionNode; +import org.apache.maven.artifact.resolver.WarningResolutionListener; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.execution.RuntimeInformation; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.DependencyManagement; +import org.apache.maven.model.Exclusion; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.eclipse.Constants; +import org.apache.maven.plugin.eclipse.Messages; +import org.apache.maven.plugin.ide.IdeDependency; +import org.apache.maven.plugin.ide.IdeUtils; +import org.apache.maven.project.MavenProject; +import org.apache.tuscany.maven.bundle.plugin.BundleUtil; +import org.codehaus.plexus.logging.LogEnabled; +import org.codehaus.plexus.logging.Logger; + +/** + * Abstract base plugin which takes care of the common stuff usually needed by maven IDE plugins. A plugin extending + * AbstractIdeSupportMojo should implement the setup() and writeConfiguration() methods, plus + * the getters needed to get the various configuration flags and required components. The lifecycle: + * + *
    + *       *** calls setup() where you can configure your specific stuff and stop the mojo from execute if appropriate ***
    + *       - manually resolve project dependencies, NOT failing if a dependency is missing
    + *       - compute project references (reactor projects) if the getUseProjectReferences() flag is set
    + *       - download sources/javadocs if the getDownloadSources() flag is set
    + *       *** calls writeConfiguration(), passing the list of resolved referenced dependencies ***
    + *       - report the list of missing sources or just tell how to turn this feature on if the flag was disabled
    + * 
    + * + * @author Fabrizio Giustina + * @version $Id: AbstractIdeSupportMojo.java 727620 2008-12-18 02:35:18Z baerrach $ + */ +public abstract class AbstractIdeSupportMojo + extends AbstractMojo + implements LogEnabled +{ + /** + * Is it an PDE project? If yes, the plugin adds the necessary natures and build commands to the .project file. + * Additionally it copies all libraries to a project local directory and references them instead of referencing the + * files in the local Maven repository. It also ensured that the "Bundle-Classpath" in META-INF/MANIFEST.MF is + * synchronized. + * + * @parameter expression="${eclipse.pde}" default-value="true" + */ + protected boolean pde; + + /** + * The project whose project files to create. + * + * @parameter expression="${project}" + * @required + * @readonly + */ + protected MavenProject project; + + /** + * The currently executed project (can be a reactor project). + * + * @parameter expression="${executedProject}" + * @readonly + */ + protected MavenProject executedProject; + + /** + * The project packaging. + * + * @parameter expression="${project.packaging}" + */ + protected String packaging; + + /** + * Artifact factory, needed to download source jars for inclusion in classpath. + * + * @component role="org.apache.maven.artifact.factory.ArtifactFactory" + * @required + * @readonly + */ + protected ArtifactFactory artifactFactory; + + /** + * Artifact resolver, needed to download source jars for inclusion in classpath. + * + * @component role="org.apache.maven.artifact.resolver.ArtifactResolver" + * @required + * @readonly + */ + protected ArtifactResolver artifactResolver; + + /** + * Artifact collector, needed to resolve dependencies. + * + * @component role="org.apache.maven.artifact.resolver.ArtifactCollector" + * @required + * @readonly + */ + protected ArtifactCollector artifactCollector; + + /** + * @component role="org.apache.maven.artifact.metadata.ArtifactMetadataSource" hint="maven" + */ + protected ArtifactMetadataSource artifactMetadataSource; + + /** + * The runtime information for Maven, used to retrieve Maven's version number. + * + * @component + */ + private RuntimeInformation runtimeInformation; + + /** + * Remote repositories which will be searched for source attachments. + * + * @parameter expression="${project.remoteArtifactRepositories}" + * @required + * @readonly + */ + protected List remoteArtifactRepositories; + + /** + * Local maven repository. + * + * @parameter expression="${localRepository}" + * @required + * @readonly + */ + protected ArtifactRepository localRepository; + + /** + * If the executed project is a reactor project, this will contains the full list of projects in the reactor. + * + * @parameter expression="${reactorProjects}" + * @required + * @readonly + */ + protected List reactorProjects; + + /** + * Skip the operation when true. + * + * @parameter expression="${eclipse.skip}" default-value="false" + */ + private boolean skip; + + /** + * Enables/disables the downloading of source attachments. Defaults to false. When this flag is true + * remote repositories are checked for sources: in order to avoid repeated check for unavailable source archives, a + * status cache is mantained. To reset this cache run mvn eclipse:remove-cache, or use the + * forceRecheck option. + * + * @parameter expression="${downloadSources}" + */ + protected boolean downloadSources; + + /** + * Enables/disables the downloading of javadoc attachments. Defaults to false. When this flag is true + * remote repositories are checked for javadocs: in order to avoid repeated check for unavailable javadoc archives, + * a status cache is mantained. To reset this cache run mvn eclipse:remove-cache, or use the + * forceRecheck option. + * + * @parameter expression="${downloadJavadocs}" + */ + protected boolean downloadJavadocs; + + /** + * Enables/disables the rechecking of the remote repository for downloading source/javadoc attachments. Defaults to + * false. When this flag is true and the source or javadoc attachment has a status cache to indicate + * that it is not available, then the remote repository will be rechecked for a source or javadoc attachment and the + * status cache updated to reflect the new state. + * + * @parameter expression="${forceRecheck}" + */ + protected boolean forceRecheck; + + /** + * Plexus logger needed for debugging manual artifact resolution. + */ + protected Logger logger; + + /** + * Getter for artifactMetadataSource. + * + * @return Returns the artifactMetadataSource. + */ + public ArtifactMetadataSource getArtifactMetadataSource() + { + return artifactMetadataSource; + } + + /** + * Setter for artifactMetadataSource. + * + * @param artifactMetadataSource The artifactMetadataSource to set. + */ + public void setArtifactMetadataSource( ArtifactMetadataSource artifactMetadataSource ) + { + this.artifactMetadataSource = artifactMetadataSource; + } + + /** + * Getter for project. + * + * @return Returns the project. + */ + public MavenProject getProject() + { + return project; + } + + /** + * Setter for project. + * + * @param project The project to set. + */ + public void setProject( MavenProject project ) + { + this.project = project; + } + + /** + * Getter for reactorProjects. + * + * @return Returns the reactorProjects. + */ + public List getReactorProjects() + { + return reactorProjects; + } + + /** + * Setter for reactorProjects. + * + * @param reactorProjects The reactorProjects to set. + */ + public void setReactorProjects( List reactorProjects ) + { + this.reactorProjects = reactorProjects; + } + + /** + * Getter for remoteArtifactRepositories. + * + * @return Returns the remoteArtifactRepositories. + */ + public List getRemoteArtifactRepositories() + { + return remoteArtifactRepositories; + } + + /** + * Setter for remoteArtifactRepositories. + * + * @param remoteArtifactRepositories The remoteArtifactRepositories to set. + */ + public void setRemoteArtifactRepositories( List remoteArtifactRepositories ) + { + this.remoteArtifactRepositories = remoteArtifactRepositories; + } + + /** + * Getter for artifactFactory. + * + * @return Returns the artifactFactory. + */ + public ArtifactFactory getArtifactFactory() + { + return artifactFactory; + } + + /** + * Setter for artifactFactory. + * + * @param artifactFactory The artifactFactory to set. + */ + public void setArtifactFactory( ArtifactFactory artifactFactory ) + { + this.artifactFactory = artifactFactory; + } + + /** + * Getter for artifactResolver. + * + * @return Returns the artifactResolver. + */ + public ArtifactResolver getArtifactResolver() + { + return artifactResolver; + } + + /** + * Setter for artifactResolver. + * + * @param artifactResolver The artifactResolver to set. + */ + public void setArtifactResolver( ArtifactResolver artifactResolver ) + { + this.artifactResolver = artifactResolver; + } + + /** + * Getter for executedProject. + * + * @return Returns the executedProject. + */ + public MavenProject getExecutedProject() + { + return executedProject; + } + + /** + * Setter for executedProject. + * + * @param executedProject The executedProject to set. + */ + public void setExecutedProject( MavenProject executedProject ) + { + this.executedProject = executedProject; + } + + /** + * Getter for localRepository. + * + * @return Returns the localRepository. + */ + public ArtifactRepository getLocalRepository() + { + return localRepository; + } + + /** + * Setter for localRepository. + * + * @param localRepository The localRepository to set. + */ + public void setLocalRepository( ArtifactRepository localRepository ) + { + this.localRepository = localRepository; + } + + /** + * Getter for downloadJavadocs. + * + * @return Returns the downloadJavadocs. + */ + public boolean getDownloadJavadocs() + { + return downloadJavadocs; + } + + /** + * Setter for downloadJavadocs. + * + * @param downloadJavadoc The downloadJavadocs to set. + */ + public void setDownloadJavadocs( boolean downloadJavadoc ) + { + downloadJavadocs = downloadJavadoc; + } + + /** + * Getter for downloadSources. + * + * @return Returns the downloadSources. + */ + public boolean getDownloadSources() + { + return downloadSources; + } + + /** + * Setter for downloadSources. + * + * @param downloadSources The downloadSources to set. + */ + public void setDownloadSources( boolean downloadSources ) + { + this.downloadSources = downloadSources; + } + + protected void setResolveDependencies( boolean resolveDependencies ) + { + this.resolveDependencies = resolveDependencies; + } + + protected boolean isResolveDependencies() + { + return resolveDependencies; + } + + /** + * return false if projects available in a reactor build should be considered normal dependencies, + * true if referenced project will be linked and not need artifact resolution. + * + * @return true if referenced project will be linked and not need artifact resolution + */ + protected abstract boolean getUseProjectReferences(); + + /** + * Hook for preparation steps before the actual plugin execution. + * + * @return true if execution should continue or false if not. + * @throws MojoExecutionException generic mojo exception + */ + protected abstract boolean setup() + throws MojoExecutionException; + + /** + * Main plugin method where dependencies should be processed in order to generate IDE configuration files. + * + * @param deps list of IdeDependency objects, with artifacts, sources and javadocs already resolved + * @throws MojoExecutionException generic mojo exception + */ + protected abstract void writeConfiguration( IdeDependency[] deps ) + throws MojoExecutionException; + + /** + * Not a plugin parameter. Collect the list of dependencies with a missing source artifact for the final report. + */ + private List missingSourceDependencies = new ArrayList(); + + /** + * Not a plugin parameter. Collect the list of dependencies with a missing javadoc artifact for the final report. + */ + // TODO merge this with the missingSourceDependencies in a classifier based map? + private List missingJavadocDependencies = new ArrayList(); + + /** + * Cached array of resolved dependencies. + */ + private IdeDependency[] ideDeps; + + /** + * Flag for mojo implementations to control whether normal maven dependencies should be resolved. Default value is + * true. + */ + private boolean resolveDependencies = true; + + /** + * @see org.codehaus.plexus.logging.LogEnabled#enableLogging(org.codehaus.plexus.logging.Logger) + */ + public void enableLogging( Logger logger ) + { + this.logger = logger; + } + + /** + * @see org.apache.maven.plugin.Mojo#execute() + */ + public final void execute() + throws MojoExecutionException, MojoFailureException + { + if ( skip ) + { + return; + } + + boolean processProject = setup(); + if ( !processProject ) + { + return; + } + + // resolve artifacts + IdeDependency[] deps = doDependencyResolution(); + + resolveSourceAndJavadocArtifacts( deps ); + + writeConfiguration( deps ); + + reportMissingArtifacts(); + + } + + /** + * Resolve project dependencies. Manual resolution is needed in order to avoid resolution of multiproject artifacts + * (if projects will be linked each other an installed jar is not needed) and to avoid a failure when a jar is + * missing. + * + * @throws MojoExecutionException if dependencies can't be resolved + * @return resolved IDE dependencies, with attached jars for non-reactor dependencies + */ + protected IdeDependency[] doDependencyResolution() + throws MojoExecutionException + { + if ( ideDeps == null ) + { + if ( resolveDependencies ) + { + MavenProject project = getProject(); + Set imported = Collections.emptySet(); + try { + imported = BundleUtil.getImportedPackages(project.getBasedir()); + } catch (IOException e1) { + throw new MojoExecutionException(e1.getMessage(), e1); + } + ArtifactRepository localRepo = getLocalRepository(); + + List deps = getProject().getDependencies(); + + // Collect the list of resolved IdeDependencies. + List dependencies = new ArrayList(); + + if ( deps != null ) + { + Map managedVersions = + createManagedVersionMap( getArtifactFactory(), project.getId(), + project.getDependencyManagement() ); + + ArtifactResolutionResult artifactResolutionResult = null; + + try + { + + List listeners = new ArrayList(); + + if ( logger.isDebugEnabled() ) + { + listeners.add( new DebugResolutionListener( logger ) ); + } + + listeners.add( new WarningResolutionListener( logger ) ); + + artifactResolutionResult = + artifactCollector.collect( getProjectArtifacts(), project.getArtifact(), managedVersions, + localRepo, project.getRemoteArtifactRepositories(), + getArtifactMetadataSource(), null, listeners ); + } + catch ( ArtifactResolutionException e ) + { + getLog().debug( e.getMessage(), e ); + getLog().error( + Messages.getString( "AbstractIdeSupportMojo.artifactresolution", new Object[] { //$NON-NLS-1$ + e.getGroupId(), e.getArtifactId(), e.getVersion(), + e.getMessage() } ) ); + + // if we are here artifactResolutionResult is null, create a project without dependencies but + // don't fail + // (this could be a reactor projects, we don't want to fail everything) + // Causes MECLIPSE-185. Not sure if it should be handled this way?? + return new IdeDependency[0]; + } + + // keep track of added reactor projects in order to avoid duplicates + Set emittedReactorProjectId = new HashSet(); + + for ( Iterator i = artifactResolutionResult.getArtifactResolutionNodes().iterator(); i.hasNext(); ) + { + + ResolutionNode node = (ResolutionNode) i.next(); + int dependencyDepth = node.getDepth(); + Artifact art = node.getArtifact(); + // don't resolve jars for reactor projects + if ( hasToResolveJar( art ) ) + { + try + { + artifactResolver.resolve( art, node.getRemoteRepositories(), localRepository ); + } + catch ( ArtifactNotFoundException e ) + { + getLog().debug( e.getMessage(), e ); + getLog().warn( + Messages.getString( "AbstractIdeSupportMojo.artifactdownload", new Object[] { //$NON-NLS-1$ + e.getGroupId(), e.getArtifactId(), e.getVersion(), + e.getMessage() } ) ); + } + catch ( ArtifactResolutionException e ) + { + getLog().debug( e.getMessage(), e ); + getLog().warn( + Messages.getString( "AbstractIdeSupportMojo.artifactresolution", new Object[] { //$NON-NLS-1$ + e.getGroupId(), e.getArtifactId(), e.getVersion(), + e.getMessage() } ) ); + } + } + + boolean includeArtifact = true; + if ( getExcludes() != null ) + { + String artifactFullId = art.getGroupId() + ":" + art.getArtifactId(); + if ( getExcludes().contains( artifactFullId ) ) + { + getLog().info( "excluded: " + artifactFullId ); + includeArtifact = false; + } + } + + if ( includeArtifact + && ( !( getUseProjectReferences() && isAvailableAsAReactorProject( art ) ) || emittedReactorProjectId.add( art.getGroupId() + + '-' + art.getArtifactId() ) ) ) + { + + // the following doesn't work: art.getArtifactHandler().getPackaging() always returns "jar" + // also + // if the packaging specified in pom.xml is different. + + // osgi-bundle packaging is provided by the felix osgi plugin + // eclipse-plugin packaging is provided by this eclipse plugin + // String packaging = art.getArtifactHandler().getPackaging(); + // boolean isOsgiBundle = "osgi-bundle".equals( packaging ) || "eclipse-plugin".equals( + // packaging ); + + // we need to check the manifest, if "Bundle-SymbolicName" is there the artifact can be + // considered + // an osgi bundle + if ("pom".equals(art.getType())) { + continue; + } + File artifactFile = art.getFile(); + MavenProject reactorProject = getReactorProject(art); + if (reactorProject != null) { + artifactFile = reactorProject.getBasedir(); + } + boolean isOsgiBundle = false; + String osgiSymbolicName = null; + try { + osgiSymbolicName = BundleUtil.getBundleSymbolicName(artifactFile); + } catch (IOException e) { + getLog().error("Unable to read jar manifest from " + artifactFile, e); + } + isOsgiBundle = osgiSymbolicName != null; + + IdeDependency dep = + new IdeDependency( art.getGroupId(), art.getArtifactId(), art.getVersion(), + art.getClassifier(), useProjectReference( art ), + Artifact.SCOPE_TEST.equals( art.getScope() ), + Artifact.SCOPE_SYSTEM.equals( art.getScope() ), + Artifact.SCOPE_PROVIDED.equals( art.getScope() ), + art.getArtifactHandler().isAddedToClasspath(), art.getFile(), + art.getType(), isOsgiBundle, osgiSymbolicName, dependencyDepth, + getProjectNameForArifact( art ) ); + // no duplicate entries allowed. System paths can cause this problem. + if ( !dependencies.contains( dep ) ) + { + // [rfeng] Do not add compile/provided dependencies + if (!(pde && (Artifact.SCOPE_COMPILE.equals(art.getScope()) || Artifact.SCOPE_PROVIDED + .equals(art.getScope())))) { + dependencies.add( dep ); + } else { + // Check this compile dependency is an OSGi package supplier + if (!imported.isEmpty()) { + Set exported = Collections.emptySet(); + try { + exported = BundleUtil.getExportedPackages(artifactFile); + } catch (IOException e) { + getLog().error("Unable to read jar manifest from " + art.getFile(), e); + } + boolean matched = false; + for (String p : imported) { + if (exported.contains(p)) { + matched = true; + break; + } + } + if (!matched) { + dependencies.add(dep); + } else { + getLog() + .debug("Compile dependency is skipped as it is added through OSGi dependency: " + art); + } + } else { + dependencies.add(dep); + } + } + } + } + + } + + // @todo a final report with the list of + // missingArtifacts? + + } + + ideDeps = (IdeDependency[]) dependencies.toArray( new IdeDependency[dependencies.size()] ); + } + else + { + ideDeps = new IdeDependency[0]; + } + } + + return ideDeps; + } + + /** + * Find the name of the project as used in eclipse. + * + * @param artifact The artifact to find the eclipse name for. + * @return The name os the eclipse project. + */ + abstract public String getProjectNameForArifact( Artifact artifact ); + + /** + * Returns the list of project artifacts. Also artifacts generated from referenced projects will be added, but with + * the resolved property set to true. + * + * @return list of projects artifacts + * @throws MojoExecutionException if unable to parse dependency versions + */ + private Set getProjectArtifacts() + throws MojoExecutionException + { + // keep it sorted, this should avoid random classpath order in tests + Set artifacts = new TreeSet(); + + for ( Iterator dependencies = getProject().getDependencies().iterator(); dependencies.hasNext(); ) + { + Dependency dependency = (Dependency) dependencies.next(); + + String groupId = dependency.getGroupId(); + String artifactId = dependency.getArtifactId(); + VersionRange versionRange; + try + { + versionRange = VersionRange.createFromVersionSpec( dependency.getVersion() ); + } + catch ( InvalidVersionSpecificationException e ) + { + throw new MojoExecutionException( + Messages.getString( + "AbstractIdeSupportMojo.unabletoparseversion", new Object[] { //$NON-NLS-1$ + dependency.getArtifactId(), + dependency.getVersion(), + dependency.getManagementKey(), e.getMessage() } ), + e ); + } + + String type = dependency.getType(); + if ( type == null ) + { + type = Constants.PROJECT_PACKAGING_JAR; + } + String classifier = dependency.getClassifier(); + boolean optional = dependency.isOptional(); + String scope = dependency.getScope(); + if ( scope == null ) + { + scope = Artifact.SCOPE_COMPILE; + } + + Artifact art = + getArtifactFactory().createDependencyArtifact( groupId, artifactId, versionRange, type, classifier, + scope, optional ); + + if ( scope.equalsIgnoreCase( Artifact.SCOPE_SYSTEM ) ) + { + art.setFile( new File( dependency.getSystemPath() ) ); + } + + List exclusions = new ArrayList(); + for ( Iterator j = dependency.getExclusions().iterator(); j.hasNext(); ) + { + Exclusion e = (Exclusion) j.next(); + exclusions.add( e.getGroupId() + ":" + e.getArtifactId() ); //$NON-NLS-1$ + } + + ArtifactFilter newFilter = new ExcludesArtifactFilter( exclusions ); + + art.setDependencyFilter( newFilter ); + + artifacts.add( art ); + } + + return artifacts; + } + + /** + * Utility method that locates a project producing the given artifact. + * + * @param artifact the artifact a project should produce. + * @return true if the artifact is produced by a reactor projectart. + */ + protected boolean isAvailableAsAReactorProject( Artifact artifact ) + { + return getReactorProject( artifact ) != null; + } + + /** + * Checks the list of reactor projects to see if the artifact is included. + * + * @param artifact the artifact to check if it is in the reactor + * @return the reactor project or null if it is not in the reactor + */ + protected MavenProject getReactorProject( Artifact artifact ) { + if ( reactorProjects != null ) + { + for ( Iterator iter = reactorProjects.iterator(); iter.hasNext(); ) + { + MavenProject reactorProject = (MavenProject) iter.next(); + + if ( reactorProject.getGroupId().equals( artifact.getGroupId() ) + && reactorProject.getArtifactId().equals( artifact.getArtifactId() ) ) + { + if ( reactorProject.getVersion().equals( artifact.getVersion() ) ) + { + return reactorProject; + } + else + { + getLog().info( + "Artifact " + + artifact.getId() + + " already available as a reactor project, but with different version. Expected: " + + artifact.getVersion() + ", found: " + reactorProject.getVersion() ); + } + } + } + } + return null; + } + + /** + * @return an array with all dependencies avalaible in the workspace, to be implemented by the subclasses. + */ + protected IdeDependency[] getWorkspaceArtefacts() + { + return new IdeDependency[0]; + } + + private Map createManagedVersionMap( ArtifactFactory artifactFactory, String projectId, + DependencyManagement dependencyManagement ) + throws MojoExecutionException + { + Map map; + if ( dependencyManagement != null && dependencyManagement.getDependencies() != null ) + { + map = new HashMap(); + for ( Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); ) + { + Dependency d = (Dependency) i.next(); + + try + { + VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); + Artifact artifact = + artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, + d.getType(), d.getClassifier(), d.getScope(), + d.isOptional() ); + map.put( d.getManagementKey(), artifact ); + } + catch ( InvalidVersionSpecificationException e ) + { + throw new MojoExecutionException( Messages.getString( "AbstractIdeSupportMojo.unabletoparseversion", new Object[] { //$NON-NLS-1$ + projectId, d.getVersion(), + d.getManagementKey(), e.getMessage() } ), + e ); + } + } + } + else + { + map = Collections.EMPTY_MAP; + } + return map; + } + + /** + * Resolve source artifacts and download them if downloadSources is true. Source and + * javadocs artifacts will be attached to the IdeDependency Resolve source and javadoc artifacts. The + * resolved artifacts will be downloaded based on the downloadSources and downloadJavadocs + * attributes. Source and + * + * @param deps resolved dependencies + */ + private void resolveSourceAndJavadocArtifacts( IdeDependency[] deps ) + { + final List missingSources = + resolveDependenciesWithClassifier( deps, "sources", getDownloadSources() ); + missingSourceDependencies.addAll( missingSources ); + + final List missingJavadocs = + resolveDependenciesWithClassifier( deps, "javadoc", getDownloadJavadocs() ); + missingJavadocDependencies.addAll( missingJavadocs ); + } + + /** + * Resolve the required artifacts for each of the dependency. sources or javadoc artifacts + * (depending on the classifier) are attached to the dependency. + * + * @param deps resolved dependencies + * @param inClassifier the classifier we are looking for (either sources or javadoc) + * @param includeRemoteRepositories flag whether we should search remote repositories for the artifacts or not + * @return the list of dependencies for which the required artifact was not found + */ + private List resolveDependenciesWithClassifier( IdeDependency[] deps, String inClassifier, + boolean includeRemoteRepositories ) + { + List missingClassifierDependencies = new ArrayList(); + + // if downloadSources is off, just check + // local repository for reporting missing source jars + List remoteRepos = includeRemoteRepositories ? getRemoteArtifactRepositories() : Collections.EMPTY_LIST; + + for ( int j = 0; j < deps.length; j++ ) + { + IdeDependency dependency = deps[j]; + + if ( dependency.isReferencedProject() || dependency.isSystemScoped() ) + { + // artifact not needed + continue; + } + + if ( getLog().isDebugEnabled() ) + { + getLog().debug( + "Searching for sources for " + dependency.getId() + ":" + dependency.getClassifier() + + " at " + dependency.getId() + ":" + inClassifier ); + } + + Artifact baseArtifact = + artifactFactory.createArtifactWithClassifier( dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion(), dependency.getType(), + dependency.getClassifier() ); + baseArtifact = + IdeUtils.resolveArtifact( artifactResolver, baseArtifact, remoteRepos, localRepository, getLog() ); + if (!baseArtifact.isResolved()) { + // base artifact does not exist - no point checking for javadoc/sources + continue; + } + + Artifact artifact = + IdeUtils.createArtifactWithClassifier( dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion(), dependency.getClassifier(), + inClassifier, artifactFactory ); + File notAvailableMarkerFile = IdeUtils.getNotAvailableMarkerFile( localRepository, artifact ); + + if (forceRecheck && notAvailableMarkerFile.exists()) { + if (!notAvailableMarkerFile.delete()) { + getLog().warn( Messages.getString( "AbstractIdeSupportMojo.unabletodeletenotavailablemarkerfile", notAvailableMarkerFile ) ); + } + } + + if ( !notAvailableMarkerFile.exists() ) + { + artifact = + IdeUtils.resolveArtifact( artifactResolver, artifact, remoteRepos, localRepository, getLog() ); + if ( artifact.isResolved() ) + { + if ( "sources".equals( inClassifier ) ) + { + dependency.setSourceAttachment( artifact.getFile() ); + } + else if ( "javadoc".equals( inClassifier ) ) + { + dependency.setJavadocAttachment( artifact.getFile() ); + } + } + else + { + if ( includeRemoteRepositories ) + { + try + { + notAvailableMarkerFile.createNewFile(); + getLog().debug( Messages.getString( "AbstractIdeSupportMojo.creatednotavailablemarkerfile", notAvailableMarkerFile ) ); + } + catch ( IOException e ) + { + getLog().warn( Messages.getString( "AbstractIdeSupportMojo.failedtocreatenotavailablemarkerfile", + notAvailableMarkerFile ) ); + } + } + // add the dependencies to the list + // of those lacking the required + // artifact + missingClassifierDependencies.add( dependency ); + } + } + } + + // return the list of dependencies missing the + // required artifact + return missingClassifierDependencies; + + } + + /** + * Output a message with the list of missing dependencies and info on how turn download on if it was disabled. + */ + private void reportMissingArtifacts() + { + StringBuffer msg = new StringBuffer(); + + if ( !missingSourceDependencies.isEmpty() ) + { + if ( getDownloadSources() ) + { + msg.append( Messages.getString( "AbstractIdeSupportMojo.sourcesnotavailable" ) ); //$NON-NLS-1$ + } + else + { + msg.append( Messages.getString( "AbstractIdeSupportMojo.sourcesnotdownloaded" ) ); //$NON-NLS-1$ + } + + for ( Iterator it = missingSourceDependencies.iterator(); it.hasNext(); ) + { + IdeDependency art = (IdeDependency) it.next(); + msg.append( Messages.getString( "AbstractIdeSupportMojo.sourcesmissingitem", art.getId() ) ); //$NON-NLS-1$ + } + msg.append( "\n" ); //$NON-NLS-1$ + } + + if ( !missingJavadocDependencies.isEmpty() ) + { + if ( getDownloadJavadocs() ) + { + msg.append( Messages.getString( "AbstractIdeSupportMojo.javadocnotavailable" ) ); //$NON-NLS-1$ + } + else + { + msg.append( Messages.getString( "AbstractIdeSupportMojo.javadocnotdownloaded" ) ); //$NON-NLS-1$ + } + + for ( Iterator it = missingJavadocDependencies.iterator(); it.hasNext(); ) + { + IdeDependency art = (IdeDependency) it.next(); + msg.append( Messages.getString( "AbstractIdeSupportMojo.javadocmissingitem", art.getId() ) ); //$NON-NLS-1$ + } + msg.append( "\n" ); //$NON-NLS-1$ + } + getLog().info( msg ); + } + + /** + * @return List of dependencies to exclude from eclipse classpath. + * @since 2.5 + */ + public abstract List getExcludes(); + + /** + * Checks if jar has to be resolved for the given artifact + * + * @param art the artifact to check + * @return true if resolution should happen + */ + protected boolean hasToResolveJar( Artifact art ) + { + return !( getUseProjectReferences() && isAvailableAsAReactorProject( art ) ); + } + + /** + * Checks if a projects reference has to be used for the given artifact + * + * @param art the artifact to check + * @return true if a project reference has to be used. + */ + protected boolean useProjectReference( Artifact art ) + { + return getUseProjectReferences() && isAvailableAsAReactorProject( art ); + } + + /** + * Checks whether the currently running Maven satisfies the specified version (range). + * + * @param version The version range to test for, must not be null. + * @return true if the current Maven version matches the specified version range, false + * otherwise. + */ + protected boolean isMavenVersion( String version ) + { + try + { + VersionRange versionRange = VersionRange.createFromVersionSpec( version ); + ArtifactVersion mavenVersion = runtimeInformation.getApplicationVersion(); + return versionRange.containsVersion( mavenVersion ); + } + catch ( InvalidVersionSpecificationException e ) + { + throw new IllegalArgumentException( e.getMessage() ); + } + } + + // [rfeng] + protected boolean isOSGiBundle() { + File base = project.getBasedir(); + File mf = new File(base, "META-INF/MANIFEST.MF"); + if (mf.isFile()) { + Manifest manifest = null; + try { + InputStream is = new FileInputStream(mf); + manifest = new Manifest(is); + is.close(); + } catch (IOException e) { + // Ignore + } + if (manifest != null) { + String bundleName = manifest.getMainAttributes().getValue("Bundle-SymbolicName"); + if (bundleName != null) { + return true; + } + } + } + return false; + } + +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseClasspathWriter.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseClasspathWriter.java new file mode 100644 index 0000000000..3fec54ba35 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseClasspathWriter.java @@ -0,0 +1,635 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.plugin.eclipse; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.eclipse.Constants; +import org.apache.maven.plugin.eclipse.EclipseSourceDir; +import org.apache.maven.plugin.eclipse.Messages; +import org.apache.maven.plugin.eclipse.writers.AbstractEclipseWriter; +import org.apache.maven.plugin.ide.IdeDependency; +import org.apache.maven.plugin.ide.IdeUtils; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; +import org.codehaus.plexus.util.xml.XMLWriter; + +/** + * Writes eclipse .classpath file. + * + * @author Trygve Laugstøl + * @author Kenney Westerhof + * @author Fabrizio Giustina + * @version $Id: EclipseClasspathWriter.java 750073 2009-03-04 16:55:01Z aheritier $ + */ +public class EclipseClasspathWriter + extends AbstractEclipseWriter +{ + + /** + * + */ + private static final String ORG_ECLIPSE_AJDT_INPATH = "org.eclipse.ajdt.inpath"; + + /** + * + */ + private static final String ORG_ECLIPSE_AJDT_ASPECTPATH = "org.eclipse.ajdt.aspectpath"; + + /** + * + */ + private static final String NAME = "name"; + + /** + * + */ + private static final String VALUE = "value"; + + /** + * + */ + private static final String ATTRIBUTE = "attribute"; + + /** + * + */ + private static final String ATTRIBUTES = "attributes"; + + /** + * Eclipse build path variable M2_REPO + */ + protected static final String M2_REPO = "M2_REPO"; //$NON-NLS-1$ + + /** + * Attribute for sourcepath. + */ + private static final String ATTR_SOURCEPATH = "sourcepath"; //$NON-NLS-1$ + + /** + * Attribute for output. + */ + private static final String ATTR_OUTPUT = "output"; //$NON-NLS-1$ + + /** + * Attribute for path. + */ + private static final String ATTR_PATH = "path"; //$NON-NLS-1$ + + /** + * Attribute for kind - Container (con), Variable (var)..etc. + */ + private static final String ATTR_KIND = "kind"; //$NON-NLS-1$ + + /** + * Attribute value for kind: var + */ + private static final String ATTR_VAR = "var"; //$NON-NLS-1$ + + /** + * Attribute value for kind: lib + */ + private static final String ATTR_LIB = "lib"; //$NON-NLS-1$ + + /** + * Attribute value for kind: src + */ + private static final String ATTR_SRC = "src"; //$NON-NLS-1$ + + /** + * Attribute name for source file includes in a path. + */ + private static final String ATTR_INCLUDING = "including"; + + /** + * Attribute name for source file excludes in a path. + */ + private static final String ATTR_EXCLUDING = "excluding"; + + /** + * Element for classpathentry. + */ + private static final String ELT_CLASSPATHENTRY = "classpathentry"; //$NON-NLS-1$ + + /** + * Element for classpath. + */ + private static final String ELT_CLASSPATH = "classpath"; //$NON-NLS-1$ + + /** + * File name that stores project classpath settings. + */ + private static final String FILE_DOT_CLASSPATH = ".classpath"; //$NON-NLS-1$ + + /** + * @see org.apache.maven.plugin.eclipse.writers.EclipseWriter#write() + */ + public void write() + throws MojoExecutionException + { + + Writer w; + + try + { + w = + new OutputStreamWriter( new FileOutputStream( new File( config.getEclipseProjectDirectory(), + FILE_DOT_CLASSPATH ) ), "UTF-8" ); + } + catch ( IOException ex ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.erroropeningfile" ), ex ); //$NON-NLS-1$ + } + + XMLWriter writer = new PrettyPrintXMLWriter( w ); + + writer.startElement( ELT_CLASSPATH ); + + String defaultOutput = + IdeUtils.toRelativeAndFixSeparator( config.getProjectBaseDir(), config.getBuildOutputDirectory(), false ); + + // ---------------------------------------------------------------------- + // Source roots and resources + // ---------------------------------------------------------------------- + + // List + List specialSources = new ArrayList(); + + // Map> + Map byOutputDir = new HashMap(); + + for ( int j = 0; j < config.getSourceDirs().length; j++ ) + { + EclipseSourceDir dir = config.getSourceDirs()[j]; + + // List + List byOutputDirs = (List) byOutputDir.get( dir.getOutput() ); + if ( byOutputDirs == null ) + { + // ArrayList + byOutputDir.put( dir.getOutput() == null ? defaultOutput : dir.getOutput(), byOutputDirs = + new ArrayList() ); + } + byOutputDirs.add( dir ); + } + + for ( int j = 0; j < config.getSourceDirs().length; j++ ) + { + EclipseSourceDir dir = config.getSourceDirs()[j]; + + log.debug( "Processing " + ( dir.isResource() ? "re" : "" ) + "source " + dir.getPath() + ": output=" + + dir.getOutput() + "; default output=" + defaultOutput ); + + boolean isSpecial = false; + + // handle resource with nested output folders + if ( dir.isResource() ) + { + // Check if the output is a subdirectory of the default output, + // and if the default output has any sources that copy there. + + if ( dir.getOutput() != null // resource output dir is set + && !dir.getOutput().equals( defaultOutput ) // output dir is not default target/classes + && dir.getOutput().startsWith( defaultOutput ) // ... but is nested + && byOutputDir.get( defaultOutput ) != null // ??? + && !( (List) byOutputDir.get( defaultOutput ) ).isEmpty() // ??? + ) + { + // do not specify as source since the output will be nested. Instead, mark + // it as a todo, and handle it with a custom build.xml file later. + + log.debug( "Marking as special to prevent output folder nesting: " + dir.getPath() + " (output=" + + dir.getOutput() + ")" ); + + isSpecial = true; + specialSources.add( dir ); + } + } + + writer.startElement( ELT_CLASSPATHENTRY ); + + writer.addAttribute( ATTR_KIND, "src" ); //$NON-NLS-1$ + writer.addAttribute( ATTR_PATH, dir.getPath() ); + + if ( !isSpecial && dir.getOutput() != null && !defaultOutput.equals( dir.getOutput() ) ) + { + writer.addAttribute( ATTR_OUTPUT, dir.getOutput() ); + } + + String includes = dir.getInclude(); + + if ( !dir.isResource() ) + { + // automatically include java files only: eclipse doesn't have the concept of a source only directory so it + // will try to include non-java files found in maven source dirs + includes = StringUtils.isEmpty( includes ) ? "**/*.java" : includes + "|**/*.java"; + } + + if ( StringUtils.isNotEmpty( includes ) ) + { + writer.addAttribute( ATTR_INCLUDING, includes ); + } + + String excludes = dir.getExclude(); + + if ( dir.isResource() ) + { + // automatically exclude java files: eclipse doesn't have the concept of resource directory so it will + // try to compile any java file found in maven resource dirs + excludes = StringUtils.isEmpty( excludes ) ? "**/*.java" : excludes + "|**/*.java"; + } + + if ( StringUtils.isNotEmpty( excludes ) ) + { + writer.addAttribute( ATTR_EXCLUDING, excludes ); + } + + writer.endElement(); + + } + + /* + // handle the special sources. + if ( !specialSources.isEmpty() ) + { + log.info( "Creating maven-eclipse.xml Ant file to handle resources" ); + + try + { + Writer buildXmlWriter = + new OutputStreamWriter( new FileOutputStream( new File( config.getEclipseProjectDirectory(), + "maven-eclipse.xml" ) ), "UTF-8" ); + PrettyPrintXMLWriter buildXmlPrinter = new PrettyPrintXMLWriter( buildXmlWriter ); + + buildXmlPrinter.startElement( "project" ); + buildXmlPrinter.addAttribute( "default", "copy-resources" ); + + buildXmlPrinter.startElement( "target" ); + buildXmlPrinter.addAttribute( NAME, "init" ); + // initialize filtering tokens here + buildXmlPrinter.endElement(); + + buildXmlPrinter.startElement( "target" ); + buildXmlPrinter.addAttribute( NAME, "copy-resources" ); + buildXmlPrinter.addAttribute( "depends", "init" ); + + for ( Iterator it = specialSources.iterator(); it.hasNext(); ) + { + // TODO: merge source dirs on output path+filtering to reduce + // tags for speed. + EclipseSourceDir dir = (EclipseSourceDir) it.next(); + buildXmlPrinter.startElement( "copy" ); + buildXmlPrinter.addAttribute( "todir", dir.getOutput() ); + buildXmlPrinter.addAttribute( "filtering", "" + dir.isFiltering() ); + + buildXmlPrinter.startElement( "fileset" ); + buildXmlPrinter.addAttribute( "dir", dir.getPath() ); + if ( dir.getInclude() != null ) + { + buildXmlPrinter.addAttribute( "includes", dir.getInclude() ); + } + if ( dir.getExclude() != null ) + { + buildXmlPrinter.addAttribute( "excludes", dir.getExclude() ); + } + buildXmlPrinter.endElement(); + + buildXmlPrinter.endElement(); + } + + buildXmlPrinter.endElement(); + + buildXmlPrinter.endElement(); + + IOUtil.close( buildXmlWriter ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Cannot create " + config.getEclipseProjectDirectory() + + "/maven-eclipse.xml", e ); + } + + log.info( "Creating external launcher file" ); + // now create the launcher + new EclipseAntExternalLaunchConfigurationWriter().init( log, config, "Maven_Ant_Builder.launch", + "maven-eclipse.xml" ).write(); + + // finally add it to the project writer. + + config.getBuildCommands().add( + new BuildCommand( + "org.eclipse.ui.externaltools.ExternalToolBuilder", + "LaunchConfigHandle", + "/" + + EclipseLaunchConfigurationWriter.FILE_DOT_EXTERNAL_TOOL_BUILDERS + + "Maven_Ant_Builder.launch" ) ); + } + */ + + // ---------------------------------------------------------------------- + // The default output + // ---------------------------------------------------------------------- + + writer.startElement( ELT_CLASSPATHENTRY ); + writer.addAttribute( ATTR_KIND, ATTR_OUTPUT ); + writer.addAttribute( ATTR_PATH, defaultOutput ); + writer.endElement(); + + Set addedDependencies = new HashSet(); + // TODO if (..magic property equals orderDependencies..) + + // ---------------------------------------------------------------------- + // Java API dependencies that may complete the classpath container so must + // be declared BEFORE so that container access rules don't fail + // ---------------------------------------------------------------------- + IdeDependency[] depsToWrite = config.getDepsOrdered(); + for ( int j = 0; j < depsToWrite.length; j++ ) + { + IdeDependency dep = depsToWrite[j]; + if ( dep.isJavaApi() ) + { + String depId = getDependencyId( dep ); + if ( !addedDependencies.contains( depId ) ) + { + addDependency( writer, dep ); + addedDependencies.add( depId ); + } + } + } + + // ---------------------------------------------------------------------- + // The dependencies + // ---------------------------------------------------------------------- + for ( int j = 0; j < depsToWrite.length; j++ ) + { + IdeDependency dep = depsToWrite[j]; + + if ( dep.isAddedToClasspath() ) + { + String depId = getDependencyId( dep ); + /* avoid duplicates in the classpath for artifacts with different types (like ejbs or test-jars) */ + if ( !addedDependencies.contains( depId ) ) + { + addDependency( writer, dep ); + addedDependencies.add( depId ); + } + } + } + + // ---------------------------------------------------------------------- + // Container classpath entries + // ---------------------------------------------------------------------- + + for ( Iterator it = config.getClasspathContainers().iterator(); it.hasNext(); ) + { + writer.startElement( ELT_CLASSPATHENTRY ); + writer.addAttribute( ATTR_KIND, "con" ); //$NON-NLS-1$ + writer.addAttribute( ATTR_PATH, (String) it.next() ); + writer.endElement(); // name + } + + writer.endElement(); + + IOUtil.close( w ); + + } + + private String getDependencyId( IdeDependency dep ) + { + String depId = + dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getClassifier() + ":" + dep.getVersion(); + + if ( dep.isReferencedProject() ) + { + // This dependency will be refered as an eclipse project + depId = dep.getEclipseProjectName(); + } + return depId; + } + + protected void addDependency( XMLWriter writer, IdeDependency dep ) + throws MojoExecutionException + { + + String path; + String kind; + String sourcepath = null; + String javadocpath = null; + // [rfeng] Force to non-PDE mode + boolean pdeMode = false; + + if ( dep.isReferencedProject() && !pdeMode ) + { + path = "/" + dep.getEclipseProjectName(); //$NON-NLS-1$ + kind = ATTR_SRC; + } + else if ( dep.isReferencedProject() && pdeMode ) + { + // don't do anything, referenced projects are automatically handled by eclipse in PDE builds + return; + } + else + { + File artifactPath = dep.getFile(); + + if ( artifactPath == null ) + { + log.error( Messages.getString( "EclipsePlugin.artifactpathisnull", dep.getId() ) ); //$NON-NLS-1$ + return; + } + + if ( dep.isSystemScoped() ) + { + path = IdeUtils.toRelativeAndFixSeparator( config.getEclipseProjectDirectory(), artifactPath, false ); + + if ( log.isDebugEnabled() ) + { + log.debug( Messages.getString( "EclipsePlugin.artifactissystemscoped", //$NON-NLS-1$ + new Object[] { dep.getArtifactId(), path } ) ); + } + + kind = ATTR_LIB; + } + else + { + File localRepositoryFile = new File( config.getLocalRepository().getBasedir() ); + + // if the dependency is not provided and the plugin runs in "pde mode", the dependency is + // added to the Bundle-Classpath: + if ( pdeMode && ( dep.isProvided() || dep.isOsgiBundle() ) ) + { + return; + } + else if ( pdeMode && !dep.isProvided() && !dep.isTestDependency() ) + { + // path for link created in .project, not to the actual file + path = dep.getFile().getName(); + + kind = ATTR_LIB; + } + // running in PDE mode and the dependency is provided means, that it is provided by + // the target platform. This case is covered by adding the plugin container + else + { + String fullPath = artifactPath.getPath(); + String relativePath = + IdeUtils.toRelativeAndFixSeparator( localRepositoryFile, new File( fullPath ), false ); + + if ( !new File( relativePath ).isAbsolute() ) + { + path = M2_REPO + "/" //$NON-NLS-1$ + + relativePath; + kind = ATTR_VAR; //$NON-NLS-1$ + } + else + { + path = relativePath; + kind = ATTR_LIB; + } + } + + if ( dep.getSourceAttachment() != null ) + { + if ( ATTR_VAR.equals( kind ) ) + { + sourcepath = + M2_REPO + + "/" //$NON-NLS-1$ + + IdeUtils.toRelativeAndFixSeparator( localRepositoryFile, dep.getSourceAttachment(), + false ); + } + else + { + // source archive must be referenced with the full path, we can't mix a lib with a variable + sourcepath = IdeUtils.getCanonicalPath( dep.getSourceAttachment() ); + } + } + + if ( dep.getJavadocAttachment() != null ) + { + // NB eclipse (3.1) doesn't support variables in javadoc paths, so we need to add the + // full path for the maven repo + javadocpath = + StringUtils.replace( IdeUtils.getCanonicalPath( dep.getJavadocAttachment() ), "\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$ + } + + } + + } + + // Skip aspectj libraries since they are in the container. + if ( ( config.getAjdtVersion() != 0 ) && dep.getArtifactId().toLowerCase().startsWith( "aspectj" ) ) + { + return; + } + + writer.startElement( ELT_CLASSPATHENTRY ); + writer.addAttribute( ATTR_KIND, kind ); + writer.addAttribute( ATTR_PATH, path ); + + if ( sourcepath != null ) + { + writer.addAttribute( ATTR_SOURCEPATH, sourcepath ); + } + + boolean attributeElemOpen = false; + + if ( javadocpath != null ) + { + if ( !attributeElemOpen ) + { + writer.startElement( ATTRIBUTES ); //$NON-NLS-1$ + attributeElemOpen = true; + } + + writer.startElement( ATTRIBUTE ); //$NON-NLS-1$ + writer.addAttribute( VALUE, "jar:" + new File( javadocpath ).toURI() + "!/" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + writer.addAttribute( NAME, "javadoc_location" ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.endElement(); + + } + + if ( Constants.PROJECT_PACKAGING_WAR.equals( this.config.getPackaging() ) && config.getWtpapplicationxml() + && kind.equals( ATTR_VAR ) && !dep.isTestDependency() && !dep.isProvided() + && !dep.isSystemScopedOutsideProject( this.config.getProject() ) ) + { + if ( !attributeElemOpen ) + { + writer.startElement( ATTRIBUTES ); //$NON-NLS-1$ + attributeElemOpen = true; + } + + writer.startElement( ATTRIBUTE ); //$NON-NLS-1$ + writer.addAttribute( VALUE, "/WEB-INF/lib" ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.addAttribute( NAME, "org.eclipse.jst.component.dependency" ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.endElement(); + + } + + if ( dep.isAjdtDependency() && ( config.getAjdtVersion() >= 1.5 ) ) + { + if ( !attributeElemOpen ) + { + writer.startElement( ATTRIBUTES ); //$NON-NLS-1$ + attributeElemOpen = true; + } + + writer.startElement( ATTRIBUTE ); //$NON-NLS-1$ + writer.addAttribute( NAME, ORG_ECLIPSE_AJDT_ASPECTPATH ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.addAttribute( VALUE, Boolean.TRUE.toString() ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.endElement(); + + } + + if ( dep.isAjdtWeaveDependency() && ( config.getAjdtVersion() >= 1.5 ) ) + { + if ( !attributeElemOpen ) + { + writer.startElement( ATTRIBUTES ); //$NON-NLS-1$ + attributeElemOpen = true; + } + + writer.startElement( ATTRIBUTE ); //$NON-NLS-1$ + writer.addAttribute( NAME, ORG_ECLIPSE_AJDT_INPATH ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.addAttribute( VALUE, Boolean.TRUE.toString() ); //$NON-NLS-1$ //$NON-NLS-2$ + writer.endElement(); + + } + + if ( attributeElemOpen ) + { + writer.endElement(); + } + writer.endElement(); + + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseCleanMojo.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseCleanMojo.java new file mode 100644 index 0000000000..397f5e34d6 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseCleanMojo.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.plugin.eclipse; + +import java.io.File; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.eclipse.Constants; +import org.apache.maven.plugin.eclipse.EclipseConfigFile; +import org.apache.maven.plugin.ide.IdeUtils; + +/** + * Deletes the .project, .classpath, .wtpmodules files and .settings folder used by Eclipse. + * + * @goal clean + */ +public class EclipseCleanMojo + extends AbstractMojo +{ + + /** + * Definition file for Eclipse Web Tools project. + */ + private static final String FILE_DOT_WTPMODULES = ".wtpmodules"; //$NON-NLS-1$ + + /** + * Classpath definition file for an Eclipse Java project. + */ + private static final String FILE_DOT_CLASSPATH = ".classpath"; //$NON-NLS-1$ + + /** + * Project definition file for an Eclipse Project. + */ + private static final String FILE_DOT_PROJECT = ".project"; //$NON-NLS-1$ + + /** + * Web Project definition file for Eclipse Web Tools Project (Release 1.0x). + */ + private static final String DIR_DOT_SETTINGS = ".settings"; //$NON-NLS-1$ + + /** + * File name where the WTP component settings will be stored - WTP 1.0 name. + */ + private static final String FILE_DOT_COMPONENT = ".settings/.component"; //$NON-NLS-1$ + + /** + * File name where the WTP component settings will be stored - WTP 1.5 name. + */ + private static final String FILE_DOT_COMPONENT_15 = ".settings/org.eclipse.wst.common.component"; //$NON-NLS-1$ + + /** + * File name where Eclipse Project's Facet configuration will be stored. + */ + private static final String FILE_FACET_CORE_XML = ".settings/org.eclipse.wst.common.project.facet.core.xml"; //$NON-NLS-1$ + + /** + * General project preferences. + */ + private static final String FILE_ECLIPSE_JDT_CORE_PREFS = ".settings/org.eclipse.jdt.core.prefs"; //$NON-NLS-1$ + + /** + * AJDT preferences. + */ + private static final String FILE_AJDT_PREFS = ".settings/org.eclipse.ajdt.ui.prefs"; //$NON-NLS-1$ + + /** + * Packaging for the current project. + * + * @parameter expression="${project.packaging}" + */ + private String packaging; + + /** + * The root directory of the project + * + * @parameter expression="${basedir}" + */ + private File basedir; + + /** + * Skip the operation when true. + * + * @parameter expression="${eclipse.skip}" default-value="false" + */ + private boolean skip; + + /** + * additional generic configuration files for eclipse + * + * @parameter + */ + private EclipseConfigFile[] additionalConfig; + + /** + * @see org.apache.maven.plugin.AbstractMojo#execute() + */ + public void execute() + throws MojoExecutionException + { + if ( skip ) + { + return; + } + + if ( Constants.PROJECT_PACKAGING_POM.equals( this.packaging ) ) + { + return; + } + + delete( new File( basedir, FILE_DOT_PROJECT ) ); + delete( new File( basedir, FILE_DOT_CLASSPATH ) ); + delete( new File( basedir, FILE_DOT_WTPMODULES ) ); + + delete( new File( basedir, FILE_DOT_COMPONENT ) ); + delete( new File( basedir, FILE_DOT_COMPONENT_15 ) ); + delete( new File( basedir, FILE_FACET_CORE_XML ) ); + delete( new File( basedir, FILE_ECLIPSE_JDT_CORE_PREFS ) ); + delete( new File( basedir, FILE_AJDT_PREFS ) ); + + File settingsDir = new File( basedir, DIR_DOT_SETTINGS ); + if ( settingsDir.exists() && settingsDir.isDirectory() && settingsDir.list().length == 0 ) + { + delete( settingsDir ); + } + + if ( additionalConfig != null ) + { + for ( int i = 0; i < additionalConfig.length; i++ ) + { + delete( new File( basedir, additionalConfig[i].getName() ) ); + } + } + + cleanExtras(); + } + + protected void cleanExtras() + throws MojoExecutionException + { + // extension point. + } + + /** + * Delete a file, handling log messages and exceptions + * + * @param f File to be deleted + * @throws MojoExecutionException only if a file exists and can't be deleted + */ + protected void delete( File f ) + throws MojoExecutionException + { + IdeUtils.delete( f, getLog() ); + } + + /** + * Getter for basedir. + * + * @return Returns the basedir. + */ + public File getBasedir() + { + return this.basedir; + } + + /** + * Setter for basedir. + * + * @param basedir The basedir to set. + */ + public void setBasedir( File basedir ) + { + this.basedir = basedir; + } + + /** + * @return the packaging + */ + public String getPackaging() + { + return this.packaging; + } + + /** + * @param packaging the packaging to set + */ + public void setPackaging( String packaging ) + { + this.packaging = packaging; + } + +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipsePlugin.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipsePlugin.java new file mode 100644 index 0000000000..781bc130d9 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipsePlugin.java @@ -0,0 +1,1877 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.plugin.eclipse; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.model.Build; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.Resource; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.eclipse.BuildCommand; +import org.apache.maven.plugin.eclipse.Constants; +import org.apache.maven.plugin.eclipse.EclipseConfigFile; +import org.apache.maven.plugin.eclipse.EclipseSourceDir; +import org.apache.maven.plugin.eclipse.WorkspaceConfiguration; +import org.apache.maven.plugin.eclipse.reader.ReadWorkspaceLocations; +import org.apache.maven.plugin.eclipse.writers.EclipseAjdtWriter; +import org.apache.maven.plugin.eclipse.writers.EclipseManifestWriter; +import org.apache.maven.plugin.eclipse.writers.EclipseSettingsWriter; +import org.apache.maven.plugin.eclipse.writers.EclipseWriterConfig; +import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpApplicationXMLWriter; +import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpComponent15Writer; +import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpComponentWriter; +import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpFacetsWriter; +import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpmodulesWriter; +import org.apache.maven.plugin.ide.IdeDependency; +import org.apache.maven.plugin.ide.IdeUtils; +import org.apache.maven.plugin.ide.JeeUtils; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.resource.ResourceManager; +import org.codehaus.plexus.resource.loader.FileResourceLoader; +import org.codehaus.plexus.resource.loader.ResourceNotFoundException; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.xml.Xpp3Dom; + +/** + * Generates the following eclipse configuration files: + *
      + *
    • .project and .classpath files
    • + *
    • .setting/org.eclipse.jdt.core.prefs with project specific compiler settings
    • + *
    • various configuration files for WTP (Web Tools Project), if the parameter wtpversion is set to a + * valid version (WTP configuration is not generated by default)
    • + *
    + * If this goal is run on a multiproject root, dependencies between modules will be configured as direct project + * dependencies in Eclipse (unless useProjectReferences is set to false). + * + * @author Trygve Laugstøl + * @author Fabrizio Giustina + * @version $Id: EclipsePlugin.java 756392 2009-03-20 09:46:09Z baerrach $ + * @goal eclipse + * @execute phase="generate-resources" + */ +public class EclipsePlugin + extends AbstractIdeSupportMojo +{ + private static final String WEAVE_DEPENDENCY = "weaveDependency"; + + private static final String WEAVE_DEPENDENCIES = "weaveDependencies"; + + private static final String ASPECT_LIBRARY = "aspectLibrary"; + + private static final String ASPECT_LIBRARIES = "aspectLibraries"; + + private static final String ASPECT_DIRECTORY = "aspectDirectory"; + + private static final String TEST_ASPECT_DIRECTORY = "testAspectDirectory"; + + private static final String ASPECTJ_MAVEN_PLUGIN = "aspectj-maven-plugin"; + + private static final String ORG_CODEHAUS_MOJO = "org.codehaus.mojo"; + + private static final String DEFAULT_TEST_ASPECT_DIRECTORY = "src/test/aspect"; + + private static final String DEFAULT_ASPECT_DIRECTORY = "src/main/aspect"; + + private static final String NATURE_WST_FACET_CORE_NATURE = "org.eclipse.wst.common.project.facet.core.nature"; //$NON-NLS-1$ + + private static final String BUILDER_WST_COMPONENT_STRUCTURAL_DEPENDENCY_RESOLVER = + "org.eclipse.wst.common.modulecore.ComponentStructuralBuilderDependencyResolver"; //$NON-NLS-1$ + + protected static final String BUILDER_WST_VALIDATION = "org.eclipse.wst.validation.validationbuilder"; //$NON-NLS-1$ + + private static final String BUILDER_JDT_CORE_JAVA = "org.eclipse.jdt.core.javabuilder"; //$NON-NLS-1$ + + private static final String BUILDER_WST_COMPONENT_STRUCTURAL = + "org.eclipse.wst.common.modulecore.ComponentStructuralBuilder"; //$NON-NLS-1$ + + private static final String BUILDER_WST_FACET = "org.eclipse.wst.common.project.facet.core.builder"; //$NON-NLS-1$ + + private static final String BUILDER_PDE_MANIFEST = "org.eclipse.pde.ManifestBuilder"; //$NON-NLS-1$ + + private static final String BUILDER_PDE_SCHEMA = "org.eclipse.pde.SchemaBuilder"; //$NON-NLS-1$ + + private static final String BUILDER_AJDT_CORE_JAVA = "org.eclipse.ajdt.core.ajbuilder"; //$NON-NLS-1$ + + private static final String NATURE_WST_MODULE_CORE_NATURE = "org.eclipse.wst.common.modulecore.ModuleCoreNature"; //$NON-NLS-1$ + + private static final String NATURE_JDT_CORE_JAVA = "org.eclipse.jdt.core.javanature"; //$NON-NLS-1$ + + private static final String NATURE_JEM_WORKBENCH_JAVA_EMF = "org.eclipse.jem.workbench.JavaEMFNature"; //$NON-NLS-1$ + + private static final String NATURE_PDE_PLUGIN = "org.eclipse.pde.PluginNature"; //$NON-NLS-1$ + + private static final String NATURE_AJDT_CORE_JAVA = "org.eclipse.ajdt.ui.ajnature"; //$NON-NLS-1$ + + protected static final String COMMON_PATH_JDT_LAUNCHING_JRE_CONTAINER = "org.eclipse.jdt.launching.JRE_CONTAINER"; //$NON-NLS-1$ + + protected static final String ASPECTJ_RT_CONTAINER = "org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"; //$NON-NLS-1$ + + protected static final String REQUIRED_PLUGINS_CONTAINER = "org.eclipse.pde.core.requiredPlugins"; //$NON-NLS-1$ + + // warning, order is important for binary search + public static final String[] WTP_SUPPORTED_VERSIONS = new String[] { "1.0", "1.5", "2.0", "R7", "none" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + /** + * Constant for 'artifactId' element in POM.xml. + */ + private static final String POM_ELT_ARTIFACT_ID = "artifactId"; //$NON-NLS-1$ + + /** + * Constant for 'groupId' element in POM.xml. + */ + private static final String POM_ELT_GROUP_ID = "groupId"; //$NON-NLS-1$ + + /** + * List of eclipse project natures. By default the org.eclipse.jdt.core.javanature nature plus the + * needed WTP natures are added. Natures added using this property replace the default list. + * + *
    +     * <projectnatures>
    +     *    <projectnature>org.eclipse.jdt.core.javanature</projectnature>
    +     *    <projectnature>org.eclipse.wst.common.modulecore.ModuleCoreNature</projectnature>
    +     * </projectnatures>
    +     * 
    + * + * @parameter + */ + private List projectnatures; + + /** + * List of artifact to exclude from eclipse classpath, beeing provided by some eclipse classPathContainer + * [MECLIPSE-79] + * + * @since 2.5 + * @parameter + */ + private List excludes; + + /** + * List of eclipse project natures to be added to the default ones. + * + *
    +     * <additionalProjectnatures>
    +     *    <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
    +     * </additionalProjectnatures>
    +     * 
    + * + * @parameter + */ + private List additionalProjectnatures; + + /** + * List of eclipse project facets to be added to the default ones. + * + *
    +     * <additionalProjectFacets>
    +     *    <jst.jsf>1.1<jst.jsf/>
    +     * </additionalProjectFacets>
    +     * 
    + * + * @parameter + */ + private Map additionalProjectFacets; + + /** + * List of eclipse build commands. By default the org.eclipse.jdt.core.javabuilder builder plus the + * needed WTP builders are added. If you specify any configuration for this parameter, only those buildcommands + * specified will be used; the defaults won't be added. Use the additionalBuildCommands parameter for + * that. Configuration example: Old style: + * + *
    +     * <buildcommands>
    +     *    <buildcommand>org.eclipse.wst.common.modulecore.ComponentStructuralBuilder</buildcommand>
    +     *    <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
    +     *    <buildcommand>org.eclipse.wst.common.modulecore.ComponentStructuralBuilderDependencyResolver</buildcommand>
    +     * </buildcommands>
    +     * 
    + * + * For new style, see additionalBuildCommands. + * + * @parameter + */ + private List buildcommands; + + /** + * List of eclipse build commands to be added to the default ones. Old style: + * + *
    +     * <additionalBuildcommands>
    +     *    <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
    +     * </additionalBuildcommands>
    +     * 
    + * + * New style: + * + *
    +     * <additionalBuildcommands>
    +     *    <buildCommand>
    +     *      <name>org.ui.externaltools.ExternalToolBuilder</name>
    +     *      <triggers>auto,full,incremental,</triggers>
    +     *      <arguments>
    +     *        <LaunchConfigHandle>&lt;project&gt;./externalToolBuilders/MavenBuilder.launch</LaunchConfighandle>
    +     *      </arguments>
    +     *    </buildCommand>
    +     * </additionalBuildcommands>
    +     * 
    + * + * Note the difference between buildcommand and + * buildCommand. You can mix and match old and new-style configuration entries. + * + * @parameter + */ + private List additionalBuildcommands; + + /** + * List of container classpath entries. By default the org.eclipse.jdt.launching.JRE_CONTAINER + * classpath container is added. Configuration example: + * + *
    +     * <classpathContainers>
    +     *    <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
    +     *    <classpathContainer>org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v5.5</classpathContainer>
    +     *    <classpathContainer>org.eclipse.jst.j2ee.internal.web.container/artifact</classpathContainer>
    +     * </classpathContainers>
    +     * 
    + * + * @parameter + */ + private List classpathContainers; + + /** + * Enables/disables the downloading of source attachments. Defaults to false. DEPRECATED - use downloadSources + * + * @parameter expression="${eclipse.downloadSources}" + * @deprecated use downloadSources + */ + private boolean eclipseDownloadSources; + + /** + * Eclipse workspace directory. + * + * @parameter expression="${eclipse.projectDir}" alias="outputDir" + */ + private File eclipseProjectDir; + + /** + * When set to false, the plugin will not create sub-projects and instead reference those sub-projects using the + * installed package in the local repository + * + * @parameter expression="${eclipse.useProjectReferences}" default-value="true" + * @required + */ + private boolean useProjectReferences; + + /** + * The default output directory + * + * @parameter expression="${outputDirectory}" alias="outputDirectory" + * default-value="${project.build.outputDirectory}" + * @required + */ + private File buildOutputDirectory; + + /** + * The version of WTP for which configuration files will be generated. The default value is "none" (don't generate + * WTP configuration), supported versions are "R7", "1.0", and "1.5" + * + * @parameter expression="${wtpversion}" default-value="none" + */ + private String wtpversion; + + /** + * JEE context name of the WTP module. ( ex. WEB context name ). + * + * @parameter expression="${wtpContextName}" + */ + private String wtpContextName; + + /** + * Is it an AJDT project? If yes, the plugin adds the necessary natures and build commands to the .project file. + */ + private boolean ajdt; + + /** + * The relative path of the manifest file + * + * @parameter expression="${eclipse.manifest}" default-value="${basedir}/META-INF/MANIFEST.MF" + */ + private File manifest; + + /** + * Allow to configure additional generic configuration files for eclipse that will be written out to disk when + * running eclipse:eclipse. FOr each file you can specify the name and the text content. + * + *
    +     * <plugin>
    +     *  <groupId>org.apache.maven.plugins</groupId>
    +     *  <artifactId>maven-eclipse-plugin</artifactId>
    +     *  <configuration>
    +     *   <additionalConfig>
    +     *    <file>
    +     *      <name>.checkstyle</name>
    +     *      <content>
    +     *        <![CDATA[<fileset-config file-format-version="1.2.0" simple-config="true">
    +     *          <fileset name="all" enabled="true" check-config-name="acme corporate style" local="false">
    +     *              <file-match-pattern match-pattern="." include-pattern="true"/>
    +     *          </fileset>
    +     *          <filter name="NonSrcDirs" enabled="true"/>
    +     *        </fileset-config>]]>
    +     *      </content>
    +     *    </file>
    +     *   </additionalConfig>
    +     *  </configuration>
    +     * </plugin>
    +     * 
    + * + * Instead of the content you can also define (from version 2.5) an url to download the file : + * + *
    +     * <plugin>
    +     *  <groupId>org.apache.maven.plugins</groupId>
    +     *  <artifactId>maven-eclipse-plugin</artifactId>
    +     *  <configuration>
    +     *   <additionalConfig>
    +     *    <file>
    +     *      <name>.checkstyle</name>
    +     *      <url>http://some.place.org/path/to/file</url>
    +     *    </file>
    +     *   </additionalConfig>
    +     *  </configuration>
    +     * 
    + * + * or a location : + * + *
    +     * <plugin>
    +     *  <groupId>org.apache.maven.plugins</groupId>
    +     *  <artifactId>maven-eclipse-plugin</artifactId>
    +     *  <configuration>
    +     *   <additionalConfig>
    +     *    <file>
    +     *     <name>.checkstyle</name>
    +     *     <location>/checkstyle-config.xml</location>
    +     *    </file>
    +     *   </additionalConfig>
    +     *  </configuration>
    +     *  <dependencies>
    +     *   <!-- The file defined in the location is stored in this dependency -->
    +     *   <dependency>
    +     *    <groupId>eclipsetest</groupId>
    +     *    <artifactId>checkstyle-config</artifactId>
    +     *    <version>1.0</version>
    +     *   </dependency>
    +     *  </dependencies>
    +     * </plugin>
    +     * 
    + * + * @parameter + */ + private EclipseConfigFile[] additionalConfig; + + /** + * If set to true, the version number of the artifact is appended to the name of the generated Eclipse + * project. See projectNameTemplate for other options. + * + * @parameter expression="${eclipse.addVersionToProjectName}" default-value="false" + */ + private boolean addVersionToProjectName; + + /** + * If set to true, the groupId of the artifact is appended to the name of the generated Eclipse + * project. See projectNameTemplate for other options. + * + * @parameter expression="${eclipse.addGroupIdToProjectName}" default-value="false" + */ + private boolean addGroupIdToProjectName; + + /** + * Allows configuring the name of the eclipse projects. This property if set wins over addVersionToProjectName and + * addGroupIdToProjectName You can use [groupId], [artifactId] and [version] + * variables. eg. [groupId].[artifactId]-[version] + * + * @parameter expression="${eclipse.projectNameTemplate}" + */ + private String projectNameTemplate; + + /** + * Parsed wtp version. + */ + private float wtpVersionFloat; + + /** + * Not a plugin parameter. Is this a java project? + */ + private boolean isJavaProject; + + /** + * Must the manifest files be written for java projects so that that the jee classpath for wtp is correct. + * + * @parameter expression="${eclipse.wtpmanifest}" default-value="false" + */ + private boolean wtpmanifest; + + /** + * Must the application files be written for ear projects in a separate directory. + * + * @parameter expression="${eclipse.wtpapplicationxml}" default-value="false" + */ + private boolean wtpapplicationxml; + + /** + * What WTP defined server to use for deployment informations. + * + * @parameter expression="${eclipse.wtpdefaultserver}" + */ + private String wtpdefaultserver; + + private WorkspaceConfiguration workspaceConfiguration; + + /** + * ResourceManager for getting additonalConfig files from resources + * + * @component + * @required + * @readonly + */ + private ResourceManager locator; + + /** + * This eclipse workspace is read and all artifacts detected there will be connected as eclipse projects and will + * not be linked to the jars in the local repository. Requirement is that it was created with the similar wtp + * settings as the reactor projects, but the project name template my differ. The pom's in the workspace projects + * may not contain variables in the artefactId, groupId and version tags. + * + * If workspace is not defined, then an attempt to locate it by checking up the directory hierarchy will be made. + * + * @since 2.5 + * @parameter expression="${eclipse.workspace}" + */ + protected File workspace; + + /** + * Limit the use of project references to the current workspace. No project references will be created to projects + * in the reactor when they are not available in the workspace. + * + * @parameter expression="${eclipse.limitProjectReferencesToWorkspace}" default-value="false" + */ + protected boolean limitProjectReferencesToWorkspace; + + /** + * The version of AJDT for which configuration files will be generated. The default value is "1.5", supported + * versions are "none", "1.4", and "1.5". + * + * @parameter expression="${eclipse.ajdtVersion}" default-value="1.5" + */ + private String ajdtVersion; + + protected final boolean isJavaProject() + { + return isJavaProject; + } + + protected final boolean isPdeProject() + { + return pde; + } + + /** + * Getter for buildcommands. + * + * @return Returns the buildcommands. + */ + public final List getBuildcommands() + { + return buildcommands; + } + + /** + * Setter for buildcommands. + * + * @param buildcommands The buildcommands to set. + */ + public final void setBuildcommands( List buildcommands ) + { + this.buildcommands = buildcommands; + } + + /** + * Getter for buildOutputDirectory. + * + * @return Returns the buildOutputDirectory. + */ + public final File getBuildOutputDirectory() + { + return buildOutputDirectory; + } + + /** + * Setter for buildOutputDirectory. + * + * @param buildOutputDirectory The buildOutputDirectory to set. + */ + public final void setBuildOutputDirectory( File buildOutputDirectory ) + { + this.buildOutputDirectory = buildOutputDirectory; + } + + /** + * Getter for classpathContainers. + * + * @return Returns the classpathContainers. + */ + public final List getClasspathContainers() + { + return classpathContainers; + } + + /** + * Setter for classpathContainers. + * + * @param classpathContainers The classpathContainers to set. + */ + public final void setClasspathContainers( List classpathContainers ) + { + this.classpathContainers = classpathContainers; + } + + /** + * Getter for eclipseProjectDir. + * + * @return Returns the eclipseProjectDir. + */ + public final File getEclipseProjectDir() + { + return eclipseProjectDir; + } + + /** + * Setter for eclipseProjectDir. + * + * @param eclipseProjectDir The eclipseProjectDir to set. + */ + public final void setEclipseProjectDir( File eclipseProjectDir ) + { + this.eclipseProjectDir = eclipseProjectDir; + } + + /** + * Getter for projectnatures. + * + * @return Returns the projectnatures. + */ + public final List getProjectnatures() + { + return projectnatures; + } + + /** + * Setter for projectnatures. + * + * @param projectnatures The projectnatures to set. + */ + public final void setProjectnatures( List projectnatures ) + { + this.projectnatures = projectnatures; + } + + /** + * Getter for useProjectReferences. + * + * @return Returns the useProjectReferences. + */ + public final boolean getUseProjectReferences() + { + return useProjectReferences; + } + + /** + * Setter for useProjectReferences. + * + * @param useProjectReferences The useProjectReferences to set. + */ + public final void setUseProjectReferences( boolean useProjectReferences ) + { + this.useProjectReferences = useProjectReferences; + } + + /** + * Getter for wtpversion. + * + * @return Returns the wtpversion. + */ + public final String getWtpversion() + { + return wtpversion; + } + + /** + * Setter for wtpversion. + * + * @param wtpversion The wtpversion to set. + */ + public final void setWtpversion( String wtpversion ) + { + this.wtpversion = wtpversion; + } + + /** + * Getter for additionalBuildcommands. + * + * @return Returns the additionalBuildcommands. + */ + public final List getAdditionalBuildcommands() + { + return additionalBuildcommands; + } + + /** + * Setter for additionalBuildcommands. + * + * @param additionalBuildcommands The additionalBuildcommands to set. + */ + public final void setAdditionalBuildcommands( List additionalBuildcommands ) + { + this.additionalBuildcommands = additionalBuildcommands; + } + + /** + * Getter for additionalProjectnatures. + * + * @return Returns the additionalProjectnatures. + */ + public final List getAdditionalProjectnatures() + { + return additionalProjectnatures; + } + + /** + * Setter for additionalProjectnatures. + * + * @param additionalProjectnatures The additionalProjectnatures to set. + */ + public final void setAdditionalProjectnatures( List additionalProjectnatures ) + { + this.additionalProjectnatures = additionalProjectnatures; + } + + /** + * Getter for addVersionToProjectName. + */ + public final boolean isAddVersionToProjectName() + { + return addVersionToProjectName; + } + + /** + * Setter for addVersionToProjectName. + */ + public final void setAddVersionToProjectName( boolean addVersionToProjectName ) + { + this.addVersionToProjectName = addVersionToProjectName; + } + + /** + * Getter for addGroupIdToProjectName. + */ + public final boolean isAddGroupIdToProjectName() + { + return addGroupIdToProjectName; + } + + /** + * Setter for addGroupIdToProjectName. + */ + public final void setAddGroupIdToProjectName( boolean addGroupIdToProjectName ) + { + this.addGroupIdToProjectName = addGroupIdToProjectName; + } + + /** + * Getter for projectNameTemplate + * + * @return projectNameTemplate + */ + public final String getProjectNameTemplate() + { + return projectNameTemplate; + } + + /** + * Setter for projectNameTemplate. + * + * @param projectNameTemplate projectNameTemplate + */ + public final void setProjectNameTemplate( String projectNameTemplate ) + { + this.projectNameTemplate = projectNameTemplate; + } + + /** + * @see org.apache.maven.plugin.Mojo#execute() + */ + public final boolean setup() + throws MojoExecutionException + { + boolean ready = true; + + checkDeprecations(); + setProjectNameTemplate( IdeUtils.calculateProjectNameTemplate( getProjectNameTemplate(), isAddVersionToProjectName(), + isAddGroupIdToProjectName(), getLog() ) ); + ajdt = enableAjdt( executedProject ) && !ajdtVersion.equals( "none" ); + ready = validate(); + + // TODO: Why are we using project in some places, and executedProject in others?? + ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler(); + + // ear projects don't contain java sources + // pde projects are always java projects + isJavaProject = + pde + || ( Constants.LANGUAGE_JAVA.equals( artifactHandler.getLanguage() ) && !Constants.PROJECT_PACKAGING_EAR.equals( packaging ) ); + + setupExtras(); + + parseConfigurationOptions(); + + // defaults + if ( projectnatures == null ) + { + fillDefaultNatures( packaging ); + } + + if ( additionalProjectnatures != null ) + { + projectnatures.addAll( additionalProjectnatures ); + } + + if ( buildcommands == null ) + { + fillDefaultBuilders( packaging ); + } + else + { + convertBuildCommandList( buildcommands ); + } + + if ( additionalBuildcommands != null ) + { + convertBuildCommandList( additionalBuildcommands ); + buildcommands.addAll( additionalBuildcommands ); + } + + if ( classpathContainers == null ) + { + fillDefaultClasspathContainers( packaging ); + } + else + { + verifyClasspathContainerListIsComplete(); + } + locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() ); + locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) ); + + // ready to start + return ready; + } + + /** + * Convert any Strings in the commands List to BuildCommands. The conversion happens + * in situ. + * + * @param commands a list of commands to convert into BuildCommand + */ + protected final void convertBuildCommandList( List commands ) + { + if ( commands != null ) + { + for ( ListIterator i = commands.listIterator(); i.hasNext(); ) + { + Object command = i.next(); + + if ( command instanceof String ) + { + command = new BuildCommand( (String) command ); + i.set( command ); + } + } + } + } + + private void parseConfigurationOptions() + { + if ( "R7".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$ + { + wtpVersionFloat = 0.7f; + } + else if ( "1.0".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$ + { + wtpVersionFloat = 1.0f; + } + else if ( "1.5".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$ + { + wtpVersionFloat = 1.5f; + } + else if ( "2.0".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$ + { + wtpVersionFloat = 2.0f; + } + if ( !"none".equalsIgnoreCase( wtpversion ) ) + { + getLog().info( Messages.getString( "EclipsePlugin.wtpversion", wtpversion ) ); + } + } + + /** + * Extension point for subclasses. + *

    + * Called during setup. + * + * @throws MojoExecutionException mojo failures. + */ + protected void setupExtras() + throws MojoExecutionException + { + // extension point. + } + + private void verifyClasspathContainerListIsComplete() + { + boolean containsJREContainer = false; + // Check if classpathContainer contains a JRE (default, alternate or + // Execution Environment) + for ( Iterator iter = classpathContainers.iterator(); iter.hasNext(); ) + { + Object classPathContainer = iter.next(); + if ( classPathContainer != null + && classPathContainer.toString().startsWith( COMMON_PATH_JDT_LAUNCHING_JRE_CONTAINER ) ) + { + containsJREContainer = true; + break; + } + } + if ( !containsJREContainer ) + { + getLog().warn( Messages.getString( "EclipsePlugin.missingjrecontainer" ) ); //$NON-NLS-1$ + classpathContainers.add( 0, COMMON_PATH_JDT_LAUNCHING_JRE_CONTAINER ); + } + } + + private boolean validate() + throws MojoExecutionException + { + // validate sanity of the current m2 project + if ( Arrays.binarySearch( WTP_SUPPORTED_VERSIONS, wtpversion ) < 0 ) + { + throw new MojoExecutionException( + Messages.getString( "EclipsePlugin.unsupportedwtp", new Object[] { //$NON-NLS-1$ + wtpversion, + StringUtils.join( WTP_SUPPORTED_VERSIONS, " " ) } ) ); //$NON-NLS-1$ + } + + assertNotEmpty( executedProject.getGroupId(), POM_ELT_GROUP_ID ); + assertNotEmpty( executedProject.getArtifactId(), POM_ELT_ARTIFACT_ID ); + + if ( executedProject.getFile() == null || !executedProject.getFile().exists() ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.missingpom" ) ); //$NON-NLS-1$ + } + + if ( "pom".equals( packaging ) && eclipseProjectDir == null ) //$NON-NLS-1$ + { + getLog().info( Messages.getString( "EclipsePlugin.pompackaging" ) ); //$NON-NLS-1$ + return false; + } + + if ( "eclipse-plugin".equals( packaging ) ) + { + pde = true; + } + + // [rfeng] Set PDE to false if the project is not a bundle + if(!isOSGiBundle()) { + pde = false; + } + + if ( eclipseProjectDir == null ) + { + eclipseProjectDir = executedProject.getFile().getParentFile(); + } + + if ( !eclipseProjectDir.exists() && !eclipseProjectDir.mkdirs() ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantcreatedir", eclipseProjectDir ) ); //$NON-NLS-1$ + } + + if ( !eclipseProjectDir.equals( executedProject.getFile().getParentFile() ) ) + { + if ( !eclipseProjectDir.isDirectory() ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.notadir", eclipseProjectDir ) ); //$NON-NLS-1$ + } + eclipseProjectDir = new File( eclipseProjectDir, executedProject.getArtifactId() ); + if ( !eclipseProjectDir.isDirectory() && !eclipseProjectDir.mkdirs() ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantcreatedir", eclipseProjectDir ) ); //$NON-NLS-1$ + } + } + + validateExtras(); + + return true; + } + + /** + * Extension point for subclasses. + *

    + * Called during setup and used to validate that the configuration is sane. + * + * @throws MojoExecutionException mojo failures. + */ + protected void validateExtras() throws MojoExecutionException + { + // provided for extension. + } + + private void checkDeprecations() + { + if ( eclipseDownloadSources ) + { + // deprecated warning + getLog().warn( Messages.getString( "EclipsePlugin.deprecatedpar", new Object[] { //$NON-NLS-1$ + "eclipse.downloadSources", //$NON-NLS-1$ + "downloadSources" } ) ); //$NON-NLS-1$ + downloadSources = true; + } + + checkDeprecationsExtras(); + } + + /** + * Extension point for subclasses. + *

    + * Check for any extra deprecations and log warnings. Called during setup + */ + protected void checkDeprecationsExtras() + { + // provided for extension. + } + + public final void writeConfiguration( IdeDependency[] deps ) + throws MojoExecutionException + { + EclipseWriterConfig config = createEclipseWriterConfig( deps ); + + if ( wtpmanifest && isJavaProject() ) + { + EclipseManifestWriter.addManifestResource( getLog(), config ); + } + // NOTE: This could change the config! + writeConfigurationExtras( config ); + + if ( wtpVersionFloat == 0.7f ) + { + new EclipseWtpmodulesWriter().init( getLog(), config ).write(); + } + + if ( wtpVersionFloat >= 1.0f ) + { + new EclipseWtpFacetsWriter().init( getLog(), config ).write(); + } + if ( wtpVersionFloat == 1.0f ) + { + new EclipseWtpComponentWriter().init( getLog(), config ).write(); + } + if ( wtpVersionFloat >= 1.5 ) + { + new EclipseWtpComponent15Writer().init( getLog(), config ).write(); + } + + new EclipseSettingsWriter().init( getLog(), config ).write(); + + if ( isJavaProject ) + { + new EclipseClasspathWriter().init( getLog(), config ).write(); + if ( ajdt && ajdtVersion.equals( "1.4" ) ) + { + new EclipseAjdtWriter().init( getLog(), config ).write(); + } + } + + if ( wtpapplicationxml ) + { + new EclipseWtpApplicationXMLWriter().init( getLog(), config ).write(); + } + + // [rfeng] + /* + if ( pde ) + { + this.getLog().info( "The Maven Eclipse plugin runs in 'pde'-mode." ); + new EclipseOSGiManifestWriter().init( getLog(), config ).write(); + } + */ + // [rfeng] + + // NOTE: This one MUST be after EclipseClasspathwriter, and possibly others, + // since currently EclipseClasspathWriter does some magic to detect nested + // output folders and modifies the configuration by adding new (Ant) builders. + // So the .project file must be written AFTER those have run! + new EclipseProjectWriter().init( getLog(), config ).write(); + + writeAdditionalConfig(); + + getLog().info( Messages.getString( "EclipsePlugin.wrote", new Object[] { //$NON-NLS-1$ + config.getEclipseProjectName(), eclipseProjectDir.getAbsolutePath() } ) ); + } + + private void writeAdditionalConfig() + throws MojoExecutionException + { + if ( additionalConfig != null ) + { + for ( int j = 0; j < additionalConfig.length; j++ ) + { + EclipseConfigFile file = additionalConfig[j]; + File projectRelativeFile = new File( eclipseProjectDir, file.getName() ); + if ( projectRelativeFile.isDirectory() ) + { + // just ignore? + getLog().warn( Messages.getString( "EclipsePlugin.foundadir", //$NON-NLS-1$ + projectRelativeFile.getAbsolutePath() ) ); + } + + try + { + projectRelativeFile.getParentFile().mkdirs(); + if ( file.getContent() == null ) + { + InputStream inStream; + if ( file.getLocation() != null ) + { + inStream = locator.getResourceAsInputStream( file.getLocation() ); + } + else + { + inStream = file.getURL().openConnection().getInputStream(); + } + OutputStream outStream = new FileOutputStream( projectRelativeFile ); + try + { + IOUtil.copy( inStream, outStream ); + } + finally + { + inStream.close(); + outStream.close(); + } + } + else + { + FileUtils.fileWrite( projectRelativeFile.getAbsolutePath(), file.getContent() ); + } + } + catch ( IOException e ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantwritetofile", //$NON-NLS-1$ + projectRelativeFile.getAbsolutePath() ) ); + } + catch ( ResourceNotFoundException e ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantfindresource", //$NON-NLS-1$ + file.getLocation() ) ); + } + + } + } + } + + /** + * Create the EclipseWriterConfig for the specified dependencies. + * + * @param deps the project dependencies + * @return a configured EclipseWriterConfig + * @throws MojoExecutionException mojo failures. + */ + protected final EclipseWriterConfig createEclipseWriterConfig( IdeDependency[] deps ) + throws MojoExecutionException + { + File projectBaseDir = executedProject.getFile().getParentFile(); + + // build a list of UNIQUE source dirs (both src and resources) to be + // used in classpath and wtpmodules + EclipseSourceDir[] sourceDirs = buildDirectoryList( executedProject, eclipseProjectDir, buildOutputDirectory ); + + EclipseWriterConfig config = new EclipseWriterConfig(); + + config.setWorkspaceConfiguration( getWorkspaceConfiguration() ); + + config.setProjectNameTemplate( getProjectNameTemplate() ); + + String projectName = IdeUtils.getProjectName( config.getProjectNameTemplate(), project ); + + config.setEclipseProjectName( projectName ); + + config.setWtpapplicationxml( wtpapplicationxml ); + + config.setWtpVersion( wtpVersionFloat ); + + float ajdtVersionFloat; + try + { + ajdtVersionFloat = Float.parseFloat( ajdtVersion ); + } + catch ( NumberFormatException e ) + { + ajdtVersionFloat = 0.0f; + } + + config.setAjdtVersion( ajdtVersionFloat ); + + Set convertedBuildCommands = new LinkedHashSet(); + + if ( buildcommands != null ) + { + for ( Iterator it = buildcommands.iterator(); it.hasNext(); ) + { + Object cmd = it.next(); + + if ( cmd instanceof BuildCommand ) + { + convertedBuildCommands.add( cmd ); + } + else + { + convertedBuildCommands.add( new BuildCommand( (String) cmd ) ); + } + } + } + + if ( ajdt ) + { + buildAjdtWeaveDeps( deps ); + buildAspectjDeps( deps ); + } + + config.setBuildCommands( new LinkedList( convertedBuildCommands ) ); + + config.setBuildOutputDirectory( buildOutputDirectory ); + config.setClasspathContainers( classpathContainers ); + config.setDeps( deps ); + config.setEclipseProjectDirectory( eclipseProjectDir ); + config.setLocalRepository( localRepository ); + config.setOSGIManifestFile( manifest ); + config.setPde( pde ); + config.setProject( project ); + config.setProjectBaseDir( projectBaseDir ); + config.setProjectnatures( projectnatures ); + config.setProjectFacets( additionalProjectFacets ); + config.setSourceDirs( sourceDirs ); + config.setAddVersionToProjectName( isAddVersionToProjectName() ); + config.setPackaging( packaging ); + + collectWarContextRootsFromReactorEarConfiguration( config ); + + return config; + } + + /** + * If this is a war module peek into the reactor an search for an ear module that defines the context root of this + * module. + * + * @param config config to save the context root. + */ + private void collectWarContextRootsFromReactorEarConfiguration( EclipseWriterConfig config ) + { + if ( reactorProjects != null && wtpContextName == null + && Constants.PROJECT_PACKAGING_WAR.equals( project.getPackaging() ) ) + { + for ( Iterator iter = reactorProjects.iterator(); iter.hasNext(); ) + { + MavenProject reactorProject = (MavenProject) iter.next(); + + if ( Constants.PROJECT_PACKAGING_EAR.equals( reactorProject.getPackaging() ) ) + { + Xpp3Dom[] warDefinitions = + IdeUtils.getPluginConfigurationDom( reactorProject, JeeUtils.ARTIFACT_MAVEN_EAR_PLUGIN, + new String[] { "modules", "webModule" } ); + for ( int index = 0; index < warDefinitions.length; index++ ) + { + Xpp3Dom groupId = warDefinitions[index].getChild( "groupId" ); + Xpp3Dom artifactId = warDefinitions[index].getChild( "artifactId" ); + Xpp3Dom contextRoot = warDefinitions[index].getChild( "contextRoot" ); + if ( groupId != null && artifactId != null && contextRoot != null && groupId.getValue() != null + && artifactId.getValue() != null && contextRoot.getValue() != null ) + { + getLog().info( + "Found context root definition for " + groupId.getValue() + ":" + + artifactId.getValue() + " " + contextRoot.getValue() ); + if ( project.getArtifactId().equals( artifactId.getValue() ) + && project.getGroupId().equals( groupId.getValue() ) ) + { + config.setContextName( contextRoot.getValue() ); + } + } + else + { + getLog().info( + "Found incomplete ear configuration in " + reactorProject.getGroupId() + ":" + + reactorProject.getGroupId() + " found " + + warDefinitions[index].toString() ); + } + } + } + } + } + if ( config.getContextName() == null && Constants.PROJECT_PACKAGING_WAR.equals( project.getPackaging() ) ) + { + if ( wtpContextName == null ) + { + config.setContextName( project.getArtifactId() ); + } + else + { + config.setContextName( wtpContextName ); + } + } + } + + /** + * Write any extra configuration information for the Eclipse project. This is an extension point, called before the + * main configurations are written.
    NOTE: This could change the config! + * + * @param config + * @throws MojoExecutionException + */ + protected void writeConfigurationExtras( EclipseWriterConfig config ) + throws MojoExecutionException + { + // extension point. + } + + private void assertNotEmpty( String string, String elementName ) + throws MojoExecutionException + { + if ( string == null ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.missingelement", elementName ) ); //$NON-NLS-1$ + } + } + + /** + * Fill getProjectnatures() with values. + *

    + * Subclasses should call super and then calculate their own additions and insert them via + * getProjectnatures().addAll(). + * + * @param packaging the pom's packaging + */ + protected void fillDefaultNatures( String packaging ) + { + projectnatures = new ArrayList(); + + if ( wtpVersionFloat >= 1.0f ) + { + projectnatures.add( NATURE_WST_FACET_CORE_NATURE ); // WTP 1.0 nature + } + + if ( isJavaProject ) + { + if ( ajdt ) + { + projectnatures.add( NATURE_AJDT_CORE_JAVA ); + } + + projectnatures.add( NATURE_JDT_CORE_JAVA ); + } + + if ( wtpVersionFloat >= 0.7f ) + { + projectnatures.add( NATURE_WST_MODULE_CORE_NATURE ); // WTP 0.7/1.0 nature + + if ( isJavaProject ) + { + projectnatures.add( NATURE_JEM_WORKBENCH_JAVA_EMF ); // WTP 0.7/1.0 nature + } + } + + if ( pde ) + { + projectnatures.add( NATURE_PDE_PLUGIN ); + } + + } + + /** + * Fill getClasspathContainers() with values. + *

    + * Subclasses should call super and then calculate their own additions and insert them via + * getClasspathContainers().addAll(). + * + * @param packaging the pom's packaging + */ + protected void fillDefaultClasspathContainers( String packaging ) + { + classpathContainers = new ArrayList(); + + if ( getWorkspaceConfiguration().getDefaultClasspathContainer() != null ) + { + getLog().info( + "Adding default classpath container: " + + getWorkspaceConfiguration().getDefaultClasspathContainer() ); + classpathContainers.add( getWorkspaceConfiguration().getDefaultClasspathContainer() ); + } + if ( pde ) + { + classpathContainers.add( REQUIRED_PLUGINS_CONTAINER ); + } + + if ( ajdt ) + { + classpathContainers.add( ASPECTJ_RT_CONTAINER ); + } + } + + /** + * Fill getBuildcommands() with values. + *

    + * Subclasses should call super and then calculate their own additions and insert them via + * getBuildcommands().addAll(). + * + * @param packaging the pom's packaging + */ + protected void fillDefaultBuilders( String packaging ) + { + buildcommands = new ArrayList(); + + if ( wtpVersionFloat == 0.7f ) + { + buildcommands.add( new BuildCommand( BUILDER_WST_COMPONENT_STRUCTURAL ) ); // WTP 0.7 builder + } + + if ( isJavaProject ) + { + if ( ajdt ) + { + buildcommands.add( new BuildCommand( BUILDER_AJDT_CORE_JAVA ) ); + } + else + { + buildcommands.add( new BuildCommand( BUILDER_JDT_CORE_JAVA ) ); + } + } + + if ( wtpVersionFloat >= 1.5f ) + { + buildcommands.add( new BuildCommand( BUILDER_WST_FACET ) ); // WTP 1.5 builder + } + + if ( wtpVersionFloat >= 0.7f ) + { + buildcommands.add( new BuildCommand( BUILDER_WST_VALIDATION ) ); // WTP 0.7/1.0 builder + } + + if ( wtpVersionFloat == 0.7f ) + { + // WTP 0.7 builder + buildcommands.add( new BuildCommand( BUILDER_WST_COMPONENT_STRUCTURAL_DEPENDENCY_RESOLVER ) ); + } + + if ( pde ) + { + buildcommands.add( new BuildCommand( BUILDER_PDE_MANIFEST ) ); + buildcommands.add( new BuildCommand( BUILDER_PDE_SCHEMA ) ); + } + } + + public final EclipseSourceDir[] buildDirectoryList( MavenProject project, File basedir, File buildOutputDirectory ) + throws MojoExecutionException + { + File projectBaseDir = project.getFile().getParentFile(); + + String mainOutput = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, buildOutputDirectory, false ); + + // If using the standard output location, don't mix the test output into it. + String testOutput = null; + boolean useStandardOutputDir = + buildOutputDirectory.equals( new File( project.getBuild().getOutputDirectory() ) ); + if ( useStandardOutputDir ) + { + getLog().debug( + "testOutput toRelativeAndFixSeparator " + projectBaseDir + " , " + + project.getBuild().getTestOutputDirectory() ); + testOutput = + IdeUtils.toRelativeAndFixSeparator( projectBaseDir, + new File( project.getBuild().getTestOutputDirectory() ), false ); + getLog().debug( "testOutput after toRelative : " + testOutput ); + } + + Set mainDirectories = new LinkedHashSet(); + + extractSourceDirs( mainDirectories, project.getCompileSourceRoots(), basedir, projectBaseDir, false, null ); + + extractResourceDirs( mainDirectories, project.getBuild().getResources(), basedir, projectBaseDir, false, + mainOutput ); + + Set testDirectories = new LinkedHashSet(); + + extractSourceDirs( testDirectories, project.getTestCompileSourceRoots(), basedir, projectBaseDir, true, + testOutput ); + + extractResourceDirs( testDirectories, project.getBuild().getTestResources(), basedir, projectBaseDir, true, + testOutput ); + + // avoid duplicated entries + Set directories = new LinkedHashSet(); + + // NOTE: Since MNG-3118, test classes come before main classes + boolean testBeforeMain = isMavenVersion( "[2.0.8,)" ); + + if ( testBeforeMain ) + { + directories.addAll( testDirectories ); + directories.removeAll( mainDirectories ); + directories.addAll( mainDirectories ); + } + else + { + directories.addAll( mainDirectories ); + directories.addAll( testDirectories ); + } + if ( ajdt ) + extractAspectDirs( directories, project, basedir, projectBaseDir, testOutput ); + return (EclipseSourceDir[]) directories.toArray( new EclipseSourceDir[directories.size()] ); + } + + private void extractSourceDirs( Set directories, List sourceRoots, File basedir, File projectBaseDir, boolean test, + String output ) + throws MojoExecutionException + { + for ( Iterator it = sourceRoots.iterator(); it.hasNext(); ) + { + + File sourceRootFile = new File( (String) it.next() ); + + if ( sourceRootFile.isDirectory() ) + { + String sourceRoot = + IdeUtils.toRelativeAndFixSeparator( projectBaseDir, sourceRootFile, + !projectBaseDir.equals( basedir ) ); + + directories.add( new EclipseSourceDir( sourceRoot, output, false, test, null, null, false ) ); + } + } + } + + final void extractResourceDirs( Set directories, List resources, File basedir, File workspaceProjectBaseDir, + boolean test, final String output ) + throws MojoExecutionException + { + for ( Iterator it = resources.iterator(); it.hasNext(); ) + { + Resource resource = (Resource) it.next(); + + getLog().debug( "Processing resource dir: " + resource.getDirectory() ); + + String includePattern = null; + String excludePattern = null; + + if ( resource.getIncludes().size() != 0 ) + { + includePattern = StringUtils.join( resource.getIncludes().iterator(), "|" ); + } + + if ( resource.getExcludes().size() != 0 ) + { + excludePattern = StringUtils.join( resource.getExcludes().iterator(), "|" ); + } + + // TODO: figure out how to merge if the same dir is specified twice + // with different in/exclude patterns. + + File resourceDirectory = new File( /* basedir, */resource.getDirectory() ); + + if ( !resourceDirectory.exists() || !resourceDirectory.isDirectory() ) + { + getLog().debug( "Resource dir: " + resourceDirectory + " either missing or not a directory." ); + continue; + } + + String resourceDir = + IdeUtils.toRelativeAndFixSeparator( workspaceProjectBaseDir, resourceDirectory, + !workspaceProjectBaseDir.equals( basedir ) ); + String thisOutput = output; + if ( thisOutput != null ) + { + // sometimes thisOutput is already an absolute path + File outputFile = new File( thisOutput ); + if ( !outputFile.isAbsolute() ) + { + outputFile = new File( workspaceProjectBaseDir, thisOutput ); + } + // create output dir if it doesn't exist + outputFile.mkdirs(); + + if ( !StringUtils.isEmpty( resource.getTargetPath() ) ) + { + outputFile = new File( outputFile, resource.getTargetPath() ); + // create output dir if it doesn't exist + outputFile.mkdirs(); + } + + getLog().debug( + "Making relative and fixing separator: { " + workspaceProjectBaseDir + ", " + + outputFile + ", false }." ); + thisOutput = IdeUtils.toRelativeAndFixSeparator( workspaceProjectBaseDir, outputFile, false ); + } + + getLog().debug( + "Adding eclipse source dir: { " + resourceDir + ", " + thisOutput + ", true, " + test + + ", " + includePattern + ", " + excludePattern + " }." ); + + directories.add( new EclipseSourceDir( resourceDir, thisOutput, true, test, includePattern, excludePattern, + resource.isFiltering() ) ); + } + } + + private void extractAspectDirs( Set directories, MavenProject project, File basedir, File projectBaseDir, + String testOutput ) + throws MojoExecutionException + { + Xpp3Dom configuration = getAspectjConfiguration( project ); + if ( configuration != null ) + { + String aspectDirectory = DEFAULT_ASPECT_DIRECTORY; + Xpp3Dom aspectDirectoryElement = configuration.getChild( ASPECT_DIRECTORY ); + if ( aspectDirectoryElement != null ) + { + aspectDirectory = aspectDirectoryElement.getValue(); + } + + File aspectDirectoryFile = new File( basedir, aspectDirectory ); + if ( aspectDirectoryFile.exists() && aspectDirectoryFile.isDirectory() ) + { + String sourceRoot = + IdeUtils.toRelativeAndFixSeparator( projectBaseDir, aspectDirectoryFile, + !projectBaseDir.equals( basedir ) ); + + directories.add( new EclipseSourceDir( sourceRoot, null, false, false, null, null, false ) ); + } + + String testAspectDirectory = DEFAULT_TEST_ASPECT_DIRECTORY; + Xpp3Dom testAspectDirectoryElement = configuration.getChild( TEST_ASPECT_DIRECTORY ); + if ( testAspectDirectoryElement != null ) + { + testAspectDirectory = testAspectDirectoryElement.getValue(); + } + + File testAspectDirectoryFile = new File( basedir, testAspectDirectory ); + if ( testAspectDirectoryFile.exists() && testAspectDirectoryFile.isDirectory() ) + { + String sourceRoot = + IdeUtils.toRelativeAndFixSeparator( projectBaseDir, testAspectDirectoryFile, + !projectBaseDir.equals( basedir ) ); + + directories.add( new EclipseSourceDir( sourceRoot, testOutput, false, true, null, null, false ) ); + } + } + } + + private boolean enableAjdt( MavenProject project ) + { + boolean enable = false; + List buildPlugins = project.getBuildPlugins(); + for ( Iterator it = buildPlugins.iterator(); it.hasNext(); ) + { + Plugin plugin = (Plugin) it.next(); + if ( plugin.getGroupId().equals( ORG_CODEHAUS_MOJO ) + && plugin.getArtifactId().equals( ASPECTJ_MAVEN_PLUGIN ) ) + { + enable = true; + break; + } + } + + return enable; + } + + private Xpp3Dom getAspectjConfiguration( MavenProject project ) + { + Xpp3Dom configuration = null; + List buildPlugins = project.getBuildPlugins(); + for ( Iterator it = buildPlugins.iterator(); it.hasNext(); ) + { + Plugin plugin = (Plugin) it.next(); + if ( plugin.getGroupId().equals( ORG_CODEHAUS_MOJO ) + && plugin.getArtifactId().equals( ASPECTJ_MAVEN_PLUGIN ) ) + { + configuration = (Xpp3Dom) plugin.getConfiguration(); + break; + } + } + + return configuration; + } + + private void buildAspectjDeps( IdeDependency[] deps ) + throws MojoExecutionException + { + Xpp3Dom configuration = getAspectjConfiguration( executedProject ); + if ( configuration != null ) + { + Xpp3Dom aspectLibrariesParent = configuration.getChild( ASPECT_LIBRARIES ); + if ( aspectLibrariesParent != null ) + { + Xpp3Dom[] aspectLibraries = aspectLibrariesParent.getChildren( ASPECT_LIBRARY ); + outerLoop: for ( int i = 0; i < aspectLibraries.length; i++ ) + { + String artifactId = aspectLibraries[i].getChild( POM_ELT_ARTIFACT_ID ).getValue(); + String groupId = aspectLibraries[i].getChild( POM_ELT_GROUP_ID ).getValue(); + for ( int j = 0; j < deps.length; j++ ) + { + if ( deps[j].getArtifactId().equals( artifactId ) && deps[j].getGroupId().equals( groupId ) ) + { + deps[j].setAjdtDependency( true ); + continue outerLoop; + } + } + + throw new MojoExecutionException( "AspectLibrary is not a dependency of project" ); + } + } + } + } + + private void buildAjdtWeaveDeps( IdeDependency[] deps ) + throws MojoExecutionException + { + Xpp3Dom configuration = getAspectjConfiguration( executedProject ); + if ( configuration != null ) + { + Xpp3Dom weaveDependenciesParent = configuration.getChild( WEAVE_DEPENDENCIES ); + if ( weaveDependenciesParent != null ) + { + Xpp3Dom[] weaveDependencies = weaveDependenciesParent.getChildren( WEAVE_DEPENDENCY ); + outerLoop: for ( int i = 0; i < weaveDependencies.length; i++ ) + { + String artifactId = weaveDependencies[i].getChild( POM_ELT_ARTIFACT_ID ).getValue(); + String groupId = weaveDependencies[i].getChild( POM_ELT_GROUP_ID ).getValue(); + for ( int j = 0; j < deps.length; j++ ) + { + if ( deps[j].getArtifactId().equals( artifactId ) && deps[j].getGroupId().equals( groupId ) ) + { + deps[j].setAjdtWeaveDependency( true ); + continue outerLoop; + } + } + + throw new MojoExecutionException( "WeaveDependency is not a dependency of project" ); + } + } + } + } + + /** + * {@inheritDoc} + */ + public String getProjectNameForArifact( Artifact artifact ) + { + IdeDependency[] workspaceArtefacts = getWorkspaceArtefacts(); + for ( int index = 0; workspaceArtefacts != null && index < workspaceArtefacts.length; index++ ) + { + IdeDependency workspaceArtefact = workspaceArtefacts[index]; + if ( workspaceArtefact.isAddedToClasspath() + && workspaceArtefact.getGroupId().equals( artifact.getGroupId() ) + && workspaceArtefact.getArtifactId().equals( artifact.getArtifactId() ) ) + { + if ( workspaceArtefact.getVersion().equals( artifact.getVersion() ) ) + { + return workspaceArtefact.getEclipseProjectName(); + } + } + } + MavenProject reactorProject = getReactorProject( artifact ); + if ( reactorProject != null ) { + return IdeUtils.getProjectName( getProjectNameTemplateForMavenProject( reactorProject ), artifact ); + } + return IdeUtils.getProjectName( getProjectNameTemplate(), artifact ); + } + + /** + * @param mavenProject the project to get the projectNameTemplate configuration from + * @return the projectNameTemplate configuration from the specified MavenProject + */ + private String getProjectNameTemplateForMavenProject( MavenProject mavenProject ) + { + String projectNameTemplate = null; + boolean addVersionToProjectName = false; + boolean addGroupIdToProjectName = false; + + Build build = mavenProject.getBuild(); + if ( build != null ) + { + Plugin plugin = (Plugin) build.getPluginsAsMap().get( "org.apache.maven.plugins:maven-eclipse-plugin" ); + if ( plugin != null ) + { + Xpp3Dom config = (Xpp3Dom) plugin.getConfiguration(); + if ( config != null ) + { + Xpp3Dom projectNameTemplateNode = config.getChild( "projectNameTemplate" ); + if ( projectNameTemplateNode != null ) + { + projectNameTemplate = projectNameTemplateNode.getValue(); + } + Xpp3Dom addVersionToProjectNameNode = config.getChild( "addVersionToProjectName" ); + addVersionToProjectName = addVersionToProjectNameNode != null; + Xpp3Dom addGroupIdToProjectNameNode = config.getChild( "addGroupIdToProjectName" ); + addGroupIdToProjectName = addGroupIdToProjectNameNode != null; + } + } + } + return IdeUtils.calculateProjectNameTemplate(projectNameTemplate, addVersionToProjectName, addGroupIdToProjectName, getLog()); + } + + /** + * {@inheritDoc} + */ + protected final IdeDependency[] getWorkspaceArtefacts() + { + return getWorkspaceConfiguration().getWorkspaceArtefacts(); + } + + public final WorkspaceConfiguration getWorkspaceConfiguration() + { + if ( workspaceConfiguration == null ) + { + workspaceConfiguration = new WorkspaceConfiguration(); + locateWorkspace(); + getLog().info( Messages.getString( "EclipsePlugin.workspace", workspace ) ); + workspaceConfiguration.setWorkspaceDirectory( workspace ); + + new ReadWorkspaceLocations().init( getLog(), workspaceConfiguration, project, wtpdefaultserver ); + } + return workspaceConfiguration; + } + + /** + * If workspace is not defined, then attempt to locate it by checking up the directory hierarchy. + */ + private void locateWorkspace() + { + if ( workspace == null ) + { + File currentWorkingDirectory = new File( "." ).getAbsoluteFile(); + while ( currentWorkingDirectory != null ) + { + File metadataDirectory = new File( currentWorkingDirectory, ".metadata" ); + logger.debug( "Checking for eclipse workspace at " + currentWorkingDirectory ); + if ( metadataDirectory.exists() && metadataDirectory.isDirectory() ) + { + logger.debug( " Found workspace at " + currentWorkingDirectory ); + workspace = currentWorkingDirectory; + return; + } + currentWorkingDirectory = currentWorkingDirectory.getParentFile(); + } + } + } + + public final List getExcludes() + { + return excludes; + } + + /** + * Utility method that locates a project in the workspace for the given artifact. + * + * @param artifact the artifact a project should produce. + * @return true if the artifact is produced by a reactor projectart. + */ + private boolean isAvailableAsAWorkspaceProject( Artifact artifact ) + { + IdeDependency[] workspaceArtefacts = getWorkspaceArtefacts(); + for ( int index = 0; workspaceArtefacts != null && index < workspaceArtefacts.length; index++ ) + { + IdeDependency workspaceArtefact = workspaceArtefacts[index]; + if ( workspaceArtefact.getGroupId().equals( artifact.getGroupId() ) + && workspaceArtefact.getArtifactId().equals( artifact.getArtifactId() ) ) + { + if ( workspaceArtefact.getVersion().equals( artifact.getVersion() ) ) + { + workspaceArtefact.setAddedToClasspath( true ); + getLog().debug( "Using workspace project: " + workspaceArtefact.getEclipseProjectName() ); + return true; + } + else + { + getLog().info( + "Artifact " + + artifact.getId() + + " already available as a workspace project, but with different version. Expected: " + + artifact.getVersion() + ", found: " + workspaceArtefact.getVersion() ); + } + } + } + return false; + } + + /** + * Checks if jar has to be resolved for the given artifact + * + * @param art the artifact to check + * @return true if resolution should happen + */ + protected final boolean hasToResolveJar( Artifact art ) + { + return !( getUseProjectReferences() && isAvailableAsAReactorProject( art ) ) + || ( limitProjectReferencesToWorkspace && !( getUseProjectReferences() && isAvailableAsAWorkspaceProject( art ) ) ); + } + + /** + * Checks if a projects reference has to be used for the given artifact + * + * @param art the artifact to check + * @return true if a project reference has to be used. + */ + protected final boolean useProjectReference( Artifact art ) + { + boolean isReactorProject = getUseProjectReferences() && isAvailableAsAReactorProject( art ); + boolean isWorkspaceProject = getUseProjectReferences() && isAvailableAsAWorkspaceProject( art ); + return ( isReactorProject && !limitProjectReferencesToWorkspace ) || // default + ( limitProjectReferencesToWorkspace && isWorkspaceProject ) || // limitProjectReferencesToWorkspace + ( !isReactorProject && isWorkspaceProject ); // default + workspace projects + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseProjectWriter.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseProjectWriter.java new file mode 100644 index 0000000000..14d8a8becd --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/EclipseProjectWriter.java @@ -0,0 +1,357 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.plugin.eclipse; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.model.Resource; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.eclipse.BuildCommand; +import org.apache.maven.plugin.eclipse.Messages; +import org.apache.maven.plugin.eclipse.writers.AbstractEclipseWriter; +import org.apache.maven.plugin.ide.IdeDependency; +import org.apache.maven.plugin.ide.IdeUtils; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; +import org.codehaus.plexus.util.xml.XMLWriter; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.Xpp3DomBuilder; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +/** + * Writes eclipse .project file. + * + * @author Trygve Laugstøl + * @author Kenney Westerhof + * @author Fabrizio Giustina + * @version $Id: EclipseProjectWriter.java 728546 2008-12-21 22:56:51Z bentmann $ + */ +public class EclipseProjectWriter + extends AbstractEclipseWriter +{ + private static final String ELT_NAME = "name"; //$NON-NLS-1$ + + private static final String ELT_BUILD_COMMAND = "buildCommand"; //$NON-NLS-1$ + + private static final String ELT_BUILD_SPEC = "buildSpec"; //$NON-NLS-1$ + + private static final String ELT_NATURE = "nature"; //$NON-NLS-1$ + + private static final String ELT_NATURES = "natures"; //$NON-NLS-1$ + + private static final String FILE_DOT_PROJECT = ".project"; //$NON-NLS-1$ + + /** + * Constant for links to files. + */ + private static final int LINK_TYPE_FILE = 1; + + /** + * Constant for links to directories. + */ + private static final int LINK_TYPE_DIRECTORY = 2; + + /** + * @see org.apache.tuscany.sca.maven.plugin.eclipse.writers.EclipseWriter#write() + */ + public void write() + throws MojoExecutionException + { + + Set projectnatures = new LinkedHashSet(); + Set buildCommands = new LinkedHashSet(); + + File dotProject = new File( config.getEclipseProjectDirectory(), FILE_DOT_PROJECT ); + + if ( dotProject.exists() ) + { + + log.info( Messages.getString( "EclipsePlugin.keepexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$ + + // parse existing file in order to keep manually-added entries + Reader reader = null; + try + { + reader = new InputStreamReader( new FileInputStream( dotProject ), "UTF-8" ); + Xpp3Dom dom = Xpp3DomBuilder.build( reader ); + + Xpp3Dom naturesElement = dom.getChild( ELT_NATURES ); + if ( naturesElement != null ) + { + Xpp3Dom[] existingNatures = naturesElement.getChildren( ELT_NATURE ); + for ( int j = 0; j < existingNatures.length; j++ ) + { + // adds all the existing natures + projectnatures.add( existingNatures[j].getValue() ); + } + } + + Xpp3Dom buildSpec = dom.getChild( ELT_BUILD_SPEC ); + if ( buildSpec != null ) + { + Xpp3Dom[] existingBuildCommands = buildSpec.getChildren( ELT_BUILD_COMMAND ); + for ( int j = 0; j < existingBuildCommands.length; j++ ) + { + Xpp3Dom buildCommandName = existingBuildCommands[j].getChild( ELT_NAME ); + if ( buildCommandName != null ) + { + buildCommands.add( new BuildCommand( existingBuildCommands[j] ) ); + } + } + } + } + catch ( XmlPullParserException e ) + { + log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$ + } + catch ( IOException e ) + { + log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$ + } + finally + { + IOUtil.close( reader ); + } + } + + // adds new entries after the existing ones + for ( Iterator iter = config.getProjectnatures().iterator(); iter.hasNext(); ) + { + projectnatures.add( iter.next() ); + } + + for ( Iterator iter = config.getBuildCommands().iterator(); iter.hasNext(); ) + { + buildCommands.add( (BuildCommand) iter.next() ); + } + + Writer w; + + try + { + w = new OutputStreamWriter( new FileOutputStream( dotProject ), "UTF-8" ); + } + catch ( IOException ex ) + { + throw new MojoExecutionException( Messages.getString( "EclipsePlugin.erroropeningfile" ), ex ); //$NON-NLS-1$ + } + + XMLWriter writer = new PrettyPrintXMLWriter( w ); + + writer.startElement( "projectDescription" ); //$NON-NLS-1$ + + writer.startElement( ELT_NAME ); + writer.writeText( config.getEclipseProjectName() ); + writer.endElement(); + + // TODO: this entire element might be dropped if the comment is null. + // but as the maven1 eclipse plugin does it, it's better to be safe than sorry + // A eclipse developer might want to look at this. + writer.startElement( "comment" ); //$NON-NLS-1$ + + if ( config.getProject().getDescription() != null ) + { + writer.writeText( config.getProject().getDescription() ); + } + + writer.endElement(); + + writer.startElement( "projects" ); //$NON-NLS-1$ + + // referenced projects should not be added for plugins + if ( !config.isPde() ) + { + List duplicates = new ArrayList(); + for ( int j = 0; j < config.getDepsOrdered().length; j++ ) + { + IdeDependency dep = config.getDepsOrdered()[j]; + // Avoid duplicates entries when same project is refered using multiple types + // (ejb, test-jar ...) + if ( dep.isReferencedProject() && !duplicates.contains( dep.getEclipseProjectName() ) ) + { + writer.startElement( "project" ); //$NON-NLS-1$ + writer.writeText( dep.getEclipseProjectName() ); + writer.endElement(); + duplicates.add( dep.getEclipseProjectName() ); + } + } + } + + writer.endElement(); // projects + + writer.startElement( ELT_BUILD_SPEC ); + + for ( Iterator it = buildCommands.iterator(); it.hasNext(); ) + { + ( (BuildCommand) it.next() ).print( writer ); + } + + writer.endElement(); // buildSpec + + writer.startElement( ELT_NATURES ); + + for ( Iterator it = projectnatures.iterator(); it.hasNext(); ) + { + writer.startElement( ELT_NATURE ); + writer.writeText( (String) it.next() ); + writer.endElement(); // name + } + + writer.endElement(); // natures + + /* + boolean addLinks = !config.getProjectBaseDir().equals( config.getEclipseProjectDirectory() ); + + if ( addLinks || ( config.isPde() && config.getDepsOrdered().length > 0 ) ) + { + writer.startElement( "linkedResources" ); //$NON-NLS-1$ + + if ( addLinks ) + { + + addFileLink( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(), + config.getProject().getFile() ); + + addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(), + config.getProject().getCompileSourceRoots() ); + addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(), + config.getProject().getBuild().getResources() ); + + addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(), + config.getProject().getTestCompileSourceRoots() ); + addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(), + config.getProject().getBuild().getTestResources() ); + + } + + if ( config.isPde() ) + { + for ( int j = 0; j < config.getDepsOrdered().length; j++ ) + { + IdeDependency dep = config.getDepsOrdered()[j]; + + if ( dep.isAddedToClasspath() && !dep.isProvided() && !dep.isReferencedProject() && + !dep.isTestDependency() && !dep.isOsgiBundle() ) + { + String name = dep.getFile().getName(); + addLink( writer, name, StringUtils.replace( IdeUtils.getCanonicalPath( dep.getFile() ), "\\", + "/" ), LINK_TYPE_FILE ); + } + } + } + + writer.endElement(); // linkedResources + } + */ + + writer.endElement(); // projectDescription + + IOUtil.close( w ); + } + + private void addFileLink( XMLWriter writer, File projectBaseDir, File basedir, File file ) + throws MojoExecutionException + { + if ( file.isFile() ) + { + String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, file, true ); + String location = IdeUtils.getCanonicalPath( file ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$ + + addLink( writer, name, location, LINK_TYPE_FILE ); + } + else + { + log.warn( Messages.getString( "EclipseProjectWriter.notafile", file ) ); //$NON-NLS-1$ + } + } + + private void addSourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots ) + throws MojoExecutionException + { + for ( Iterator it = sourceRoots.iterator(); it.hasNext(); ) + { + String sourceRootString = (String) it.next(); + File sourceRoot = new File( sourceRootString ); + + if ( sourceRoot.isDirectory() ) + { + String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, sourceRoot, true ); + String location = IdeUtils.getCanonicalPath( sourceRoot ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$ + + addLink( writer, name, location, LINK_TYPE_DIRECTORY ); + } + } + } + + private void addResourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots ) + throws MojoExecutionException + { + for ( Iterator it = sourceRoots.iterator(); it.hasNext(); ) + { + String resourceDirString = ( (Resource) it.next() ).getDirectory(); + File resourceDir = new File( resourceDirString ); + + if ( resourceDir.isDirectory() ) + { + String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, resourceDir, true ); + String location = IdeUtils.getCanonicalPath( resourceDir ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$ + + addLink( writer, name, location, LINK_TYPE_DIRECTORY ); + } + } + } + + /** + * @param writer + * @param name + * @param location + */ + private void addLink( XMLWriter writer, String name, String location, int type ) + { + writer.startElement( "link" ); //$NON-NLS-1$ + + writer.startElement( ELT_NAME ); + writer.writeText( name ); + writer.endElement(); // name + + writer.startElement( "type" ); //$NON-NLS-1$ + writer.writeText( Integer.toString( type ) ); + writer.endElement(); // type + + writer.startElement( "location" ); //$NON-NLS-1$ + + writer.writeText( location ); + + writer.endElement(); // location + + writer.endElement(); // link + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/Messages.java b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/Messages.java new file mode 100644 index 0000000000..5916f50f80 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/java/org/apache/tuscany/maven/plugin/eclipse/Messages.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.plugin.eclipse; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * @author Fabrizio Giustina + * @version $Id: Messages.java 728546 2008-12-21 22:56:51Z bentmann $ + */ +public class Messages +{ + + private static final String BUNDLE_NAME = "org.apache.tuscany.maven.plugin.eclipse.messages"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle( BUNDLE_NAME ); + + private Messages() + { + } + + public static String getString( String key ) + { + try + { + return RESOURCE_BUNDLE.getString( key ); + } + catch ( MissingResourceException e ) + { + return '!' + key + '!'; + } + } + + public static String getString( String key, Object[] params ) + { + try + { + return MessageFormat.format( RESOURCE_BUNDLE.getString( key ), params ); + } + catch ( MissingResourceException e ) + { + return '!' + key + '!'; + } + } + + public static String getString( String key, Object param ) + { + return getString( key, new Object[] { param } ); + } +} diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/LICENSE.txt b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/LICENSE.txt new file mode 100644 index 0000000000..6e529a25c4 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/LICENSE.txt @@ -0,0 +1,205 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/NOTICE.txt b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/NOTICE.txt new file mode 100644 index 0000000000..db5ab284d5 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/bundle/plugin/NOTICE.txt @@ -0,0 +1,5 @@ +Copyright (c) 2005 - 2009 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + diff --git a/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/plugin/eclipse/messages.properties b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/plugin/eclipse/messages.properties new file mode 100644 index 0000000000..35332a2058 --- /dev/null +++ b/maven-plugins/tags/tuscany-bundle-plugin-1.0.8/src/main/resources/org/apache/tuscany/maven/plugin/eclipse/messages.properties @@ -0,0 +1,81 @@ +EclipsePlugin.missingpom=There must be a POM in the current working directory for the Eclipse plugin to work. +EclipsePlugin.pompackaging=Not running eclipse plugin goal for pom project +EclipsePlugin.notadir=Not a directory: "{0}" +EclipsePlugin.cantcreatedir=Can't create directory "{0}" +EclipsePlugin.erroropeningfile=Exception while opening file. +EclipsePlugin.cantwritetofile=Unable to write to file: {0} +EclipsePlugin.cantfindresource=Unable to resolve resource location: {0} +EclipsePlugin.cantreadfile=Unable to read file: {0} +EclipsePlugin.keepexisting=File {0} already exists.\n Additional settings will be preserved, run mvn eclipse:clean if you want old settings to be removed. +EclipsePlugin.cantparseexisting=Unable to parse existing file: {0}. Settings will not be preserved. +EclipsePlugin.wrote=Wrote Eclipse project for "{0}" to {1}. +EclipsePlugin.missingelement=Missing element from the project descriptor: "{0}" +EclipsePlugin.artifactpathisnull=The artifact path was null. Artifact id: {0} +EclipsePlugin.artifactissystemscoped=The artifact has scope 'system'. Artifact id: {0}. System path: {1} +EclipsePlugin.unsupportedwtp=Unsupported WTP version: {0}. This plugin currently supports only the following versions: {1}. +EclipsePlugin.wtpversion=Adding support for WTP version {0}. +EclipsePlugin.missingjrecontainer=You did specify a list of classpath containers without the base org.eclipse.jdt.launching.JRE_CONTAINER.\n If you specify custom classpath containers you should also add org.eclipse.jdt.launching.JRE_CONTAINER to the list +EclipsePlugin.deprecatedpar=Plugin parameter "{0}" is deprecated, please use "{1}" +EclipsePlugin.foundadir={0} is a directory, ignoring. +EclipsePlugin.workspace=Using Eclipse Workspace: {0} +EclipsePlugin.cantcanonicalize=Can't canonicalize system path: {0} +EclipsePlugin.unchangedmanifest=Not writing Manifest file as it is unchanged: {0} +EclipsePlugin.invalidvminworkspace=Workspace defines a VM that does not contain a valid jre/lib/rt.jar: {0} + +EclipseSettingsWriter.wrotesettings=Wrote settings to {0} +EclipseSettingsWriter.cannotcreatesettings=Cannot create settings file +EclipseSettingsWriter.errorwritingsettings=Error writing settings file +EclipseSettingsWriter.usingdefaults=Not writing settings - defaults suffice + +EclipseProjectWriter.notafile=Not adding a file link to {0}; it is not a file + +EclipseCleanMojo.failedtodelete=Failed to delete {0} file: {0} +EclipseCleanMojo.nofilefound=No {0} file found +EclipseCleanMojo.deletingFile=Deleting file: {0} +EclipseCleanMojo.deletingDirectory=Deleting directory: {0} + +EclipseOSGiManifestWriter.nomanifestfile=The references manifest file doesn't exist, plugin dependencies will not be updated: {0} + +Rad6LibCopier.cantdeletefile=Failed to delete file: {0} + +MyEclipseSpringBeansWriter.baseDirDoesNotExist=The (basedir) path declared in the project's dependencies doesn't exist: {0} + +EclipseToMavenMojo.eclipseDirectoryPrompt=Eclipse directory? +EclipseToMavenMojo.errorreadingfromstandardinput=Unable to read from standard input +EclipseToMavenMojo.directoydoesnotexist=Directory {0} doesn't exists +EclipseToMavenMojo.plugindirectorydoesnotexist=Plugin directory {0} doesn't exists +EclipseToMavenMojo.remoterepositorydeployto=Will deploy artifacts to remote repository {0} +EclipseToMavenMojo.processingfile=Processing file {0} +EclipseToMavenMojo.processingplugin=Processing {0} of {1} +EclipseToMavenMojo.skippingfile=Skipping file {0} +EclipseToMavenMojo.unabletoresolveversionrange=Unable to resolve version range for dependency {0} in project {1} +EclipseToMavenMojo.unabletoaccessjar=Unable to access jar {0} +EclipseToMavenMojo.plugindoesnothavemanifest=Plugin {0} does not have a manifest; skipping.. +EclipseToMavenMojo.unabletoreadbundlefrommanifest=Unable to read bundle name/version from manifest, skipping... +EclipseToMavenMojo.errorprocessingplugin=Error processing plugin {0} +EclipseToMavenMojo.errorwritingtemporarypom=Error writing temporary pom file: {0} +EclipseToMavenMojo.errordeployartifacttorepository=Unable to deploy artifact to repository. +EclipseToMavenMojo.errorinstallartifacttorepository=Unable to install artifact to repository. +EclipseToMavenMojo.errorgettingjarfileforplugin=Error getting the jar file for plugin {0} +EclipseToMavenMojo.invalidsyntaxforrepository=Invalid syntax for repository. +EclipseToMavenMojo.invalidremoterepositorysyntax=Invalid syntax for remote repository. Use "id::layout::url". +EclipseToMavenMojo.cannotfindrepositorylayout=Cannot find repository layout: {0} +EclipseToMavenMojo.missingversionforbundle=Missing version for bundle {0}, assuming any version > 0 + +AbstractIdeSupportMojo.sourcesnotavailable=\n Sources for some artifacts are not available.\n List of artifacts without a source archive: +AbstractIdeSupportMojo.sourcesnotdownloaded=\n Sources for some artifacts are not available.\n Please run the same goal with the -DdownloadSources=true parameter in order to check remote repositories for sources.\n List of artifacts without a source archive: +AbstractIdeSupportMojo.sourcesmissingitem=\n o {0} +AbstractIdeSupportMojo.javadocnotavailable=\n Javadoc for some artifacts is not available.\n List of artifacts without a javadoc archive: +AbstractIdeSupportMojo.javadocnotdownloaded=\n Javadoc for some artifacts is not available.\n Please run the same goal with the -DdownloadJavadocs=true parameter in order to check remote repositories for javadoc.\n List of artifacts without a javadoc archive: +AbstractIdeSupportMojo.javadocmissingitem=\n o {0} +AbstractIdeSupportMojo.artifactresolution=An error occurred during dependency resolution of the following artifact:\n {0}:{1}:{2}\nCaused by: {3} +AbstractIdeSupportMojo.artifactdownload=An error occurred during dependency resolution.\n Failed to retrieve {0}:{1}-{2}\nCaused by: {3} +AbstractIdeSupportMojo.unabletoparseversion={0}: unable to parse version '{1}' for dependency '{2}': {3} +AbstractIdeSupportMojo.failedtocreatenotavailablemarkerfile=Error creating not available file {0} +AbstractIdeSupportMojo.creatednotavailablemarkerfile=Not available marker file created: {0} +AbstractIdeSupportMojo.unabletodeletenotavailablemarkerfile=Unable to delete marker file: {0} + +IdeUtils.errorresolving=Error resolving {0} artifact. Artifact id: {1} (Message: {2}) + +RemoveCacheMojo.checking=Checking cache for not available markers +RemoveCacheMojo.complete=Done -- cgit v1.2.3