blob: 4ac0a054ad228ea252c8725c12cc8b281589a23a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.virgo.bundlor.support.contributors;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import org.osgi.framework.Constants;
import org.eclipse.virgo.bundlor.ClassPath;
import org.eclipse.virgo.bundlor.ClassPathEntry;
import org.eclipse.virgo.bundlor.support.ArtifactAnalyzer;
import org.eclipse.virgo.bundlor.support.ManifestContributor;
import org.eclipse.virgo.bundlor.support.partialmanifest.PartialManifest;
import org.eclipse.virgo.util.parser.manifest.ManifestContents;
public class BundleClassPathArtifactAnalyzer implements ArtifactAnalyzer, ManifestContributor {
private final List<String> bundleClassPaths = new ArrayList<String>();
private final List<ArtifactAnalyzer> artifactAnalyzers;
private final Object monitor = new Object();
public BundleClassPathArtifactAnalyzer(List<ArtifactAnalyzer> artifactAnalyzers) {
this.artifactAnalyzers = artifactAnalyzers;
}
public void analyse(InputStream artifact, String artefactName, PartialManifest partialManifest) throws Exception {
synchronized (this.monitor) {
this.bundleClassPaths.add(artefactName.replace('\\', '/'));
JarInputStream in = null;
try {
in = new JarInputStream(artifact);
analyzeEntries(new JarInputStreamClassPath(in), partialManifest);
} finally {
if (in != null) {
in.close();
}
}
}
}
public boolean canAnalyse(String artefactName) {
return artefactName.endsWith(".jar");
}
public void contribute(ManifestContents manifest) {
if (bundleClassPaths.size() > 0) {
StringBuilder sb = new StringBuilder(".");
for (String bundleClassPath : bundleClassPaths) {
sb.append(String.format(",%s", bundleClassPath));
}
manifest.getMainAttributes().put(Constants.BUNDLE_CLASSPATH, sb.toString());
}
}
private void analyzeEntries(ClassPath classPath, PartialManifest partialManifest) {
for (ClassPathEntry classPathEntry : classPath) {
if (!classPathEntry.isDirectory()) {
analyzeEntry(classPathEntry, partialManifest);
}
}
}
private void analyzeEntry(ClassPathEntry classPathEntry, PartialManifest partialManifest) {
for (ArtifactAnalyzer artifactAnalyzer : this.artifactAnalyzers) {
if (artifactAnalyzer.canAnalyse(classPathEntry.getName())) {
InputStream inputStream = classPathEntry.getInputStream();
try {
artifactAnalyzer.analyse(inputStream, classPathEntry.getName(), partialManifest);
} catch (Exception e) {
// Swallow exception to allow other analyzers to proceed
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Nothing to do
}
}
}
}
}
}
private static class JarInputStreamClassPath implements ClassPath {
private final JarInputStream jarInputStream;
public JarInputStreamClassPath(JarInputStream jarInputStream) {
this.jarInputStream = jarInputStream;
}
public Iterator<ClassPathEntry> iterator() {
return new JarInputStreamClassPathIterator(this.jarInputStream);
}
public ClassPathEntry getEntry(String name) {
throw new UnsupportedOperationException();
}
public void close() {
try {
this.jarInputStream.close();
} catch (IOException e) {
// Nothing to do here
}
}
private static class JarInputStreamClassPathIterator implements Iterator<ClassPathEntry> {
private final JarInputStream jarInputStream;
private volatile ClassPathEntry nextEntry;
private final Object monitor = new Object();
public JarInputStreamClassPathIterator(JarInputStream jarInputStream) {
this.jarInputStream = jarInputStream;
}
public boolean hasNext() {
synchronized (this.monitor) {
try {
if (this.nextEntry == null) {
JarEntry entry = jarInputStream.getNextJarEntry();
if (entry != null) {
this.nextEntry = new JarInputStreamClassPathEntry(this.jarInputStream, entry);
}
}
return this.nextEntry != null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public ClassPathEntry next() {
synchronized (this.monitor) {
ClassPathEntry entry = this.nextEntry;
this.nextEntry = null;
return entry;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
private static class JarInputStreamClassPathEntry implements ClassPathEntry {
private static final String UTF_8 = "UTF-8";
private final byte[] contents;
private final JarEntry entry;
public JarInputStreamClassPathEntry(JarInputStream jarInputStream, JarEntry entry) {
this.contents = getEntryContents(jarInputStream);
this.entry = entry;
}
public InputStream getInputStream() {
return new ByteArrayInputStream(this.contents);
}
public String getName() {
return this.entry.getName();
}
public Reader getReader() {
return new InputStreamReader(getInputStream(), Charset.forName(UTF_8));
}
public boolean isDirectory() {
return this.entry.isDirectory();
}
public String toString() {
return getName();
}
private byte[] getEntryContents(JarInputStream jarInputStream) {
ByteArrayOutputStream contents = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[8192];
int length = 0;
while ((length = jarInputStream.read(buffer)) != -1) {
contents.write(buffer, 0, length);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return contents.toByteArray();
}
}
}