summaryrefslogtreecommitdiffstats
path: root/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin')
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java72
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java37
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java61
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java613
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java1231
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java219
-rw-r--r--maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java152
7 files changed, 2385 insertions, 0 deletions
diff --git a/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactAggregation.java
new file mode 100644
index 0000000000..9abbe1ebd7
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/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<ArtifactMember> artifactMembers = new ArrayList<ArtifactMember>();
+ private transient List<Artifact> artifacts = new ArrayList<Artifact>();
+
+ public List<Artifact> 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<ArtifactMember> getArtifactMembers() {
+ return artifactMembers;
+ }
+
+ public void setArtifactMembers(List<ArtifactMember> 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/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactManifest.java
new file mode 100644
index 0000000000..f6eca87c8e
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/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/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ArtifactMember.java
new file mode 100644
index 0000000000..834ee7825e
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/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/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java
new file mode 100644
index 0000000000..6f7f6d245c
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/BundleUtil.java
@@ -0,0 +1,613 @@
+/*
+ * 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.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$
+ */
+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
+ */
+ 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<File> 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<File> 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<String> exportedPackages = new HashSet<String>();
+ 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";
+ }
+ exportedPackages.removeAll(getSystemPackages(env));
+
+ // Generate export-package and import-package declarations
+ StringBuffer exports = new StringBuffer();
+ StringBuffer imports = new StringBuffer();
+ Set<String> pkgs = new HashSet<String>();
+ for (String export : exportedPackages) {
+ String packageName = packageName(export);
+ if (!pkgs.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 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<String> 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<String> 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<String> getSystemPackages(String env) throws IOException {
+ Set<String> sysPackages = new HashSet<String>();
+ 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
+ */
+ private static void addExportedPackages(File file, Set<String> packages) throws IOException {
+ if (!file.exists()) {
+ return;
+ }
+
+ // Read the export-package declaration and get a list of the packages available in a JAR
+ Set<String> existingPackages = null;
+ String exports = null;
+ if (file.isDirectory()) {
+ File mf = new File(file, "META-INF/MANIFEST.MF");
+ if (mf.isFile()) {
+ Manifest manifest = new Manifest(new FileInputStream(mf));
+ exports = manifest.getMainAttributes().getValue(EXPORT_PACKAGE);
+ }
+ } else {
+ JarFile jar = new JarFile(file, false);
+ Manifest manifest = jar.getManifest();
+ exports = manifest.getMainAttributes().getValue(EXPORT_PACKAGE);
+ jar.close();
+ existingPackages = new HashSet<String>();
+ addAllPackages(file, existingPackages, "");
+ }
+ if (exports == null) {
+ return;
+ }
+
+ // Parse the export-package declaration, and extract the individual packages
+ StringBuffer buffer = new StringBuffer();
+ boolean q = false;
+ for (int i = 0, n = exports.length(); i < n; i++) {
+ char c = exports.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();
+ if (existingPackages == null || existingPackages.contains(packageName(export))) {
+ packages.add(stripExport(export));
+ }
+ buffer = new StringBuffer();
+ continue;
+ }
+ }
+ buffer.append(c);
+ }
+ if (buffer.length() != 0) {
+
+ // Add the exported package to the set, after making sure it really exists in
+ // the JAR
+ String export = buffer.toString();
+ if (existingPackages == null || existingPackages.contains(packageName(export))) {
+ packages.add(stripExport(export));
+ }
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ 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/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java
new file mode 100644
index 0000000000..52821e5214
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ModuleBundlesBuildMojo.java
@@ -0,0 +1,1231 @@
+/*
+ * 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.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-<version>.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;
+
+ /**
+ * @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="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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ private static final String ASL_HEADER =
+ "<!--" + "\n * Licensed to the Apache Software Foundation (ASF) under one"
+ + "\n * or more contributor license agreements. See the NOTICE file"
+ + "\n * distributed with this work for additional information"
+ + "\n * regarding copyright ownership. The ASF licenses this file"
+ + "\n * to you under the Apache License, Version 2.0 (the"
+ + "\n * \"License\"); you may not use this file except in compliance"
+ + "\n * with the License. You may obtain a copy of the License at"
+ + "\n * "
+ + "\n * http://www.apache.org/licenses/LICENSE-2.0"
+ + "\n * "
+ + "\n * Unless required by applicable law or agreed to in writing,"
+ + "\n * software distributed under the License is distributed on an"
+ + "\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY"
+ + "\n * KIND, either express or implied. See the License for the"
+ + "\n * specific language governing permissions and limitations"
+ + "\n * under the License."
+ + "\n-->";
+
+ /**
+ * Group the artifacts by distribution poms
+ */
+ private class ProjectSet {
+ // Distribution projects
+ private Map<String, MavenProject> projects;
+ // Key: the pom artifact id
+ // Value: the names for the artifacts
+ private Map<String, Set<String>> nameMap = new HashMap<String, Set<String>>();
+
+ private Map<String, String> artifactToNameMap = new HashMap<String, String>();
+
+ public ProjectSet(List<MavenProject> projects) {
+ super();
+ this.projects = new HashMap<String, MavenProject>();
+ 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<String> names = nameMap.get(p.getArtifactId());
+ if (names == null) {
+ names = new HashSet<String>();
+ 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<File> jarFiles = new HashSet<File>();
+ 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<Artifact> 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<String> excludedFileNames = new HashSet<String>();
+ if (excludeDirectories != null) {
+ for (File f : excludeDirectories) {
+ if (f.isDirectory()) {
+ for (String n : f.list()) {
+ excludedFileNames.add(n);
+ }
+ }
+ }
+ }
+ Set<String> includedGroupIds = new HashSet<String>();
+ if (includeGroupIds != null) {
+ for (String g : includeGroupIds) {
+ includedGroupIds.add(g);
+ }
+ }
+ Set<String> excludedGroupIds = new HashSet<String>();
+ if (excludeGroupIds != null) {
+ for (String g : excludeGroupIds) {
+ excludedGroupIds.add(g);
+ }
+ }
+
+ // Find all the distribution poms
+ List<MavenProject> poms = new ArrayList<MavenProject>();
+ 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;
+ }
+
+ // Only consider JAR and WAR files
+ if (!"jar".equals(artifact.getType()) && !"bundle".equals(artifact.getType())
+ && !"war".equals(artifact.getType())) {
+ 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);
+
+ String symbolicName = null;
+ if (customizedMF == null) {
+ String version = BundleUtil.osgiVersion(artifact.getVersion());
+
+ Set<File> jarFiles = new HashSet<File>();
+ jarFiles.add(artifactFile);
+ symbolicName = (artifact.getGroupId() + "." + artifact.getArtifactId());
+ mf =
+ BundleUtil.libraryManifest(jarFiles,
+ symbolicName,
+ symbolicName,
+ version,
+ null,
+ this.eclipseBuddyPolicy,
+ this.executionEnvironment);
+ } else {
+ mf = customizedMF;
+ symbolicName = BundleUtil.getBundleSymbolicName(mf);
+ if (symbolicName == null) {
+ throw new MojoExecutionException("Invalid customized MANIFEST.MF for " + artifact);
+ }
+ setBundleClassPath(mf, artifactFile);
+ }
+ 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, 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<File> jarFiles = new HashSet<File>();
+ 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();
+ bundleSymbolicNames.add(artifact, symbolicName);
+ bundleLocations.add(artifact, dir.getName());
+ if (isServiceProvider(mf)) {
+ serviceProviders.add(artifact, symbolicName);
+ }
+ }
+ }
+
+ if (generateGatewayBundle) {
+ generateGatewayBundle(serviceProviders);
+ }
+
+ // 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);
+ }
+
+ } catch (Exception e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+
+ }
+
+ private Set<Artifact> getDependencyArtifacts(MavenProject project) throws DependencyTreeBuilderException,
+ ArtifactResolutionException, ArtifactNotFoundException {
+ Log log = getLog();
+ Set<Artifact> artifacts = new HashSet<Artifact>();
+ 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<String>(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<String, Set<String>> e : jarNames.nameMap.entrySet()) {
+ Set<String> 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("<project name=\"tuscany." + name + "\">");
+ ps.println(" <property name=\"tuscany.distro\" value=\"" + name + "\"/>");
+ ps.println(" <property name=\"tuscany.manifest\" value=\"" + new File(feature, manifestJarName)
+ .getCanonicalPath()
+ + "\"/>");
+ ps.println(" <path id=\"" + "tuscany.path" + "\">");
+ ps.println(" <fileset dir=\"" + root.getCanonicalPath() + "\">");
+ for (String jar : jars) {
+ ps.println(" <include name=\"" + jar + "\"/>");
+ }
+ ps.println(" </fileset>");
+ ps.println(" </path>");
+ ps.println("</project>");
+ }
+ }
+
+ private void generateManifestJar(ProjectSet jarNames, File root, Log log) throws FileNotFoundException, IOException {
+ for (Map.Entry<String, Set<String>> e : jarNames.nameMap.entrySet()) {
+ MavenProject pom = jarNames.getProject(e.getKey());
+ Set<String> 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<String, Set<String>> e : bundleLocations.nameMap.entrySet()) {
+ Set<String> locations = new HashSet<String>(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")) {
+ 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 generatePDETarget(ProjectSet bundleSymbolicNames, File root, Log log) throws FileNotFoundException,
+ IOException {
+ for (Map.Entry<String, Set<String>> e : bundleSymbolicNames.nameMap.entrySet()) {
+ Set<String> bundles = new HashSet<String>(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 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<String> ids, String[] features) {
+ ps.println(XML_PI);
+ ps.println("<?pde version=\"3.2\"?>");
+ ps.println(ASL_HEADER);
+
+ ps.println("<target name=\"Eclipse Target - " + pom + "\">");
+
+ if (executionEnvironment != null) {
+ ps.println(" <targetJRE>");
+ ps.println(" <execEnv>" + executionEnvironment + "</execEnv>");
+ ps.println(" </targetJRE>");
+ }
+
+ if (useDefaultLocation) {
+ ps.println(" <location useDefault=\"true\"/>");
+ } else {
+ ps.println(" <location path=\"" + targetDirectory + "\"/>");
+ }
+
+ // ps.println("<content useAllPlugins=\"true\">");
+ ps.println(" <content>");
+ ps.println(" <plugins>");
+ for (String id : ids) {
+ ps.println(" <plugin id=\"" + id + "\"/>");
+ }
+ ps.println(" </plugins>");
+ ps.println(" <features>");
+ if (features != null) {
+ for (String f : features) {
+ ps.println(" <feature id=\"" + f + "\"/>");
+ }
+ }
+ ps.println(" </features>");
+ if (useDefaultLocation) {
+ ps.println(" <extraLocations>");
+ // Not sure why the extra path needs to the plugins folder
+ ps.println(" <location path=\"" + targetDirectory + "\"/>");
+ ps.println(" </extraLocations>");
+ }
+ ps.println(" </content>");
+
+ ps.println("</target>");
+
+ }
+
+ private void writePDE35Target(PrintStream ps, String pom, Set<String> ids, String[] features) {
+ ps.println(XML_PI);
+ ps.println("<?pde version=\"3.5\"?>");
+ ps.println(ASL_HEADER);
+
+ ps.println("<target name=\"Eclipse PDE 3.5 Target - " + pom + "\">");
+
+ if (executionEnvironment != null) {
+ ps
+ .println(" <targetJRE path=\"" + "org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/"
+ + executionEnvironment
+ + "\"/>");
+ }
+
+ ps.println("<locations>");
+ if (ids.size() > 0) {
+ ps.println(" <location path=\"" + targetDirectory + "\" type=\"Directory\">");
+ ps.println(" <includeBundles>");
+ for (String id : ids) {
+ ps.println(" <plugin id=\"" + id + "\"/>");
+ }
+ ps.println(" </includeBundles>");
+ ps.println(" </location>");
+ }
+
+ /*
+ if (useDefaultLocation) {
+ ps.println(" <location path=\"${eclipse_home}\" type=\"Profile\"/>");
+ }
+ */
+
+ /*
+ if (features != null) {
+ for (String f : features) {
+ ps.println(" <location id=\"" + f + "\" path=\"\" type=\"Feature\"/>");
+ }
+ }
+ */
+
+ ps.println("</locations>");
+ ps.println("</target>");
+
+ }
+
+ private static void writePluginXML(PrintStream ps) {
+ ps.println(XML_PI);
+ ps.println("<?pde version=\"3.2\"?>");
+ ps.println(ASL_HEADER);
+ ps.println("<plugin>");
+ ps.println("<extension point = \"org.eclipse.pde.core.targets\">");
+ ps.println("<target");
+ ps.println("id=\"org.apache.tuscany.sca.target\"");
+ ps.println("name=\"Apache Tuscany Eclipse Target\"");
+ ps.println("path=\"tuscany.target\"/>");
+ ps.println("</extension>");
+ ps.println("</plugin>");
+ }
+}
diff --git a/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/OSGIArtifactVersion.java
new file mode 100644
index 0000000000..d87ae0cb9f
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/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/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java b/maven-plugins/tags/maven-bundle-plugin-1.0.4/src/main/java/org/apache/tuscany/maven/bundle/plugin/ThirdPartyBundleBuildMojo.java
new file mode 100644
index 0000000000..880f1379e0
--- /dev/null
+++ b/maven-plugins/tags/maven-bundle-plugin-1.0.4/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<File> jarFiles = new HashSet<File>();
+ 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);
+ }
+
+ }
+
+}