blob: 868fb365922e39c99c35e62093fd73e5e7e34697 [file] [log] [blame]
/**
*
* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable.
*
* 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.
*/
package org.apache.xbean.osgi;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
/**
* @author Dain Sundstrom
* @version $Id$
* @since 2.0
*/
public class MavenBundleManager {
private final BundleContext bundleContext;
private final File localRepository;
public MavenBundleManager(BundleContext bundleContext, File localRepository) {
this.bundleContext = bundleContext;
this.localRepository = localRepository;
}
public Project loadProject(Artifact artifact) {
if (artifact instanceof Project) {
return (Project) artifact;
} else {
return new Project(artifact.getGroupId(),
artifact.getArtifactId(),
artifact.getVersion(),
artifact.getType(),
Collections.EMPTY_SET);
}
}
public Project loadProject(String groupId, String artifactId, String version) {
return new Project(groupId, artifactId, version, "jar", Collections.EMPTY_SET);
}
public Bundle installBundle(String groupId, String artifactId, String version) throws Exception {
return installBundle(loadProject(groupId, artifactId, version));
}
public Bundle installBundle(Artifact artifact) throws Exception {
String symbolicName = artifact.getGroupId() + "." + artifact.getArtifactId();
String bundleVersion = coerceToOsgiVersion(artifact.getVersion());
// check if we already loaded this bundle
Bundle[] bundles = bundleContext.getBundles();
for (int i = 0; i < bundles.length; i++) {
Bundle bundle = bundles[i];
if (symbolicName.equals(bundle.getSymbolicName()) &&
bundleVersion.equals(bundle.getHeaders().get(Constants.BUNDLE_VERSION))) {
return bundle;
}
}
// load the project object model for this artiface
Project project = loadProject(artifact);
// build an OSGi manifest for the project
Manifest manifest = createOsgiManifest(project);
// create a jar in memory for the manifest
ByteArrayOutputStream out = new ByteArrayOutputStream();
JarOutputStream jarOut = new JarOutputStream(out, manifest);
jarOut.close();
out.close();
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
// install the in memory jar
Bundle bundle = bundleContext.installBundle(symbolicName, in);
// install bundles for all of the dependencies
for (Iterator iterator = project.getDependencies().iterator(); iterator.hasNext();) {
Artifact dependency = (Artifact) iterator.next();
installBundle(dependency);
}
return bundle;
}
public Manifest createOsgiManifest(Project project) throws IOException {
String groupId = project.getGroupId();
String artifactId = project.getArtifactId();
String version = project.getVersion();
String jar = groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/" + project.getJar();
StringBuffer requireBundle = new StringBuffer();
for (Iterator iterator = project.getDependencies().iterator(); iterator.hasNext();) {
Artifact dependency = (Artifact) iterator.next();
if (requireBundle.length() > 0) requireBundle.append(',');
requireBundle.append(dependency.getGroupId()).append('.').append(dependency.getArtifactId());
requireBundle.append(";visibility:=reexport;bundle-version:=").append(coerceToOsgiVersion(dependency.getVersion()));
}
String jarPath = new File(localRepository, jar).getAbsolutePath();
StringBuffer exports = createExportList(jarPath);
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
attributes.putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
attributes.putValue(Constants.BUNDLE_VENDOR, groupId);
attributes.putValue(Constants.BUNDLE_NAME, artifactId);
attributes.putValue(Constants.BUNDLE_VERSION, coerceToOsgiVersion(version));
attributes.putValue(Constants.BUNDLE_SYMBOLICNAME, groupId + "." + artifactId);
attributes.putValue("Eclipse-AutoStart", "true");
attributes.putValue(Constants.BUNDLE_CLASSPATH, ".,external:" + jarPath);
attributes.putValue(Constants.EXPORT_PACKAGE, exports.toString());
if (requireBundle != null && requireBundle.length() > 0) {
attributes.putValue(Constants.REQUIRE_BUNDLE, requireBundle.toString());
}
return manifest;
}
private static String coerceToOsgiVersion(String version) {
int partsFound = 0;
String[] versionParts = new String[] { "0", "0", "0"};
StringBuffer qualifier = new StringBuffer();
for (StringTokenizer stringTokenizer = new StringTokenizer(version, ".-"); stringTokenizer.hasMoreTokens();) {
String part = stringTokenizer.nextToken();
if (partsFound < 4) {
try {
Integer.parseInt(part);
versionParts[partsFound++] = part;
} catch (NumberFormatException e) {
partsFound = 4;
qualifier.append(coerceToOsgiQualifier(part));
}
} else {
if (qualifier.length() > 0) qualifier.append("_");
qualifier.append(coerceToOsgiQualifier(part));
}
}
StringBuffer osgiVersion = new StringBuffer();
osgiVersion.append(versionParts[0]).append(".").append(versionParts[1]).append(".").append(versionParts[2]);
if (qualifier.length() > 0) {
osgiVersion.append(".").append(qualifier);
}
return osgiVersion.toString();
}
private static String coerceToOsgiQualifier(String qualifier) {
char[] chars = qualifier.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (!Character.isLetterOrDigit(c) && c != '_' && c != '-') {
chars[i] = '_';
}
}
return new String(chars);
}
private static StringBuffer createExportList(String jarPath) throws IOException {
Set packages = new HashSet();
FileInputStream in = null;
try {
in = new FileInputStream(jarPath);
JarInputStream jarIn = new JarInputStream(in);
for (JarEntry jarEntry = jarIn.getNextJarEntry(); jarEntry != null; jarEntry = jarIn.getNextJarEntry()) {
String packageName = jarEntry.getName();
if (!jarEntry.isDirectory()) {
int index = packageName.lastIndexOf("/");
// we can't export the default package
if (index > 0) {
packageName = packageName.substring(0, index);
if (!packageName.equals("META-INF")) {
packageName = packageName.replace('/', '.');
packages.add(packageName);
}
}
}
}
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
StringBuffer exports = new StringBuffer();
for (Iterator iterator = packages.iterator(); iterator.hasNext();) {
String packageName = (String) iterator.next();
if (exports.length() > 0) exports.append(";");
exports.append(packageName);
}
return exports;
}
}