You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by da...@apache.org on 2011/03/16 16:16:54 UTC
svn commit: r1082164 - in /aries/trunk/spi-fly:
spi-fly-core/src/main/java/org/apache/aries/spifly/ spi-fly-static/
spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/
spi-fly-static/src/test/java/org/apache/aries/spifly/statictool/
Author: davidb
Date: Wed Mar 16 15:16:50 2011
New Revision: 1082164
URL: http://svn.apache.org/viewvc?rev=1082164&view=rev
Log:
Work in progress for Spi Fly
The beginnings of a static weaver.
Added:
aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java
aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/DirTree.java
Modified:
aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ClientWeavingHook.java
aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/WeavingData.java
aries/trunk/spi-fly/spi-fly-static/pom.xml
aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/Main.java
aries/trunk/spi-fly/spi-fly-static/src/test/java/org/apache/aries/spifly/statictool/MainTest.java
Modified: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ClientWeavingHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ClientWeavingHook.java?rev=1082164&r1=1082163&r2=1082164&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ClientWeavingHook.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ClientWeavingHook.java Wed Mar 16 15:16:50 2011
@@ -18,25 +18,23 @@
*/
package org.apache.aries.spifly;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.Set;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
-import org.apache.aries.spifly.HeaderParser.PathElement;
import org.apache.aries.spifly.api.SpiFlyConstants;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.Version;
+import org.osgi.framework.BundleEvent;
import org.osgi.framework.hooks.weaving.WeavingHook;
import org.osgi.framework.hooks.weaving.WovenClass;
import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.BundleTracker;
public class ClientWeavingHook implements WeavingHook {
private final String addedImport;
+ private final Map<Bundle, WeavingData []> bundleWeavingData = new ConcurrentHashMap<Bundle, WeavingData[]>();
ClientWeavingHook(BundleContext context) {
Bundle b = context.getBundle();
@@ -46,16 +44,46 @@ public class ClientWeavingHook implement
addedImport = Util.class.getPackage().getName() +
";bundle-symbolic-name=" + bsn +
";bundle-version=" + bver;
+
+ // TODO move to activator ? and bt.close()!
+ BundleTracker<Object> bt = new BundleTracker<Object>(context, Bundle.INSTALLED, null) {
+ @Override
+ public Object addingBundle(Bundle bundle, BundleEvent event) {
+ String consumerHeader = bundle.getHeaders().get(SpiFlyConstants.SPI_CONSUMER_HEADER);
+ if (consumerHeader != null) {
+ WeavingData[] wd = ConsumerHeaderProcessor.processHeader(consumerHeader);
+ bundleWeavingData.put(bundle, wd);
+
+ for (WeavingData w : wd) {
+ Activator.activator.registerConsumerBundle(bundle, w.getArgRestrictions(), w.getAllowedBundles());
+ }
+ }
+
+ return super.addingBundle(bundle, event);
+ }
+
+ @Override
+ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+ removedBundle(bundle, event, object);
+ addingBundle(bundle, event);
+ }
+
+ @Override
+ public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+ bundleWeavingData.remove(bundle);
+ }
+ };
+ bt.open();
}
@Override
public void weave(WovenClass wovenClass) {
Bundle consumerBundle = wovenClass.getBundleWiring().getBundle();
- String consumerHeader = consumerBundle.getHeaders().get(SpiFlyConstants.SPI_CONSUMER_HEADER);
- if (consumerHeader != null) {
+ WeavingData[] wd = bundleWeavingData.get(consumerBundle);
+ if (wd != null) {
Activator.activator.log(LogService.LOG_DEBUG, "Weaving class " + wovenClass.getClassName());
- WeavingData[] wd = processHeader(consumerBundle, consumerHeader);
+// WeavingData[] wd = ConsumerHeaderProcessor.processHeader(consumerBundle, consumerHeader);
ClassReader cr = new ClassReader(wovenClass.getBytes());
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -66,147 +94,4 @@ public class ClientWeavingHook implement
wovenClass.getDynamicImports().add(addedImport);
}
}
-
- /**
- * Parses headers of the following syntax:
- * <ul>
- * <li><tt>org.acme.MyClass#myMethod</tt> - apply the weaving to all overloads of <tt>myMethod()</tt>
- * in <tt>MyClass</tt>
- * <li><tt>org.acme.MyClass#myMethod(java.lang.String, java.util.List)</tt> - apply the weaving only
- * to the <tt>myMethod(String, List)</tt> overload in <tt>MyClass</tt>
- * <li><tt>org.acme.MyClass#myMethod()</tt> - apply the weaving only to the noarg overload of
- * <tt>myMethod()</tt>
- * <li><b>true</b> - equivalend to <tt>java.util.ServiceLoader#load(java.lang.Class)</tt>
- * </ul>
- * Additionally, it registers the consumer's contraints with the consumer registry in the activator, if the
- * consumer is only constrained to a certain set of bundles.<p/>
- *
- * The following attributes are supported:
- * <ul>
- * <li><tt>bundle</tt> - restrict wiring to the bundle with the specifies Symbolic Name. The attribute value
- * is a list of bundle identifiers separated by a '|' sign. The bundle identifier starts with the Symbolic name
- * and can optionally contain a version suffix. E.g. bundle=impl2:version=1.2.3 or bundle=impl2|impl4.
- * <li><tt>bundleId</tt> - restrict wiring to the bundle with the specified bundle ID. Typically used when
- * the service should be forceably picked up from the system bundle (<tt>bundleId=0</tt>). Multiple bundle IDs
- * can be specified separated by a '|' sign.
- * </ul>
- *
- * @param consumerBundle the consuming bundle.
- * @param consumerHeader the <tt>SPI-Consumer</tt> header.
- * @return an instance of the {@link WeavingData} class.
- */
- private WeavingData[] processHeader(Bundle consumerBundle, String consumerHeader) {
- Set<WeavingData> weavingData = new HashSet<WeavingData>();
-
- for (PathElement element : HeaderParser.parseHeader(consumerHeader)) {
- List<BundleDescriptor> allowedBundles = new ArrayList<BundleDescriptor>();
- String name = element.getName().trim();
-
- String className;
- String methodName;
- MethodRestriction methodRestriction;
-
- int hashIdx = name.indexOf('#');
- if (hashIdx > 0) {
- className = name.substring(0, hashIdx);
- int braceIdx = name.substring(hashIdx).indexOf('(');
- if (braceIdx > 0) {
- methodName = name.substring(hashIdx + 1, hashIdx + braceIdx);
- ArgRestrictions argRestrictions = new ArgRestrictions();
- int closeIdx = name.substring(hashIdx).indexOf(')');
- if (closeIdx > 0) {
- String classes = name.substring(hashIdx + braceIdx + 1, hashIdx + closeIdx).trim();
- if (classes.length() > 0) {
- if (classes.indexOf('[') > 0) {
- int argNumber = 0;
- for (String s : classes.split(",")) {
- int idx = s.indexOf('[');
- int end = s.indexOf(']', idx);
- if (idx > 0 && end > idx) {
- argRestrictions.addRestriction(argNumber, s.substring(0, idx), s.substring(idx + 1, end));
- } else {
- argRestrictions.addRestriction(argNumber, s);
- }
- argNumber++;
- }
- } else {
- String[] classNames = classes.split(",");
- for (int i = 0; i < classNames.length; i++) {
- argRestrictions.addRestriction(i, classNames[i]);
- }
- }
- } else {
- argRestrictions = null;
- }
- }
- methodRestriction = new MethodRestriction(methodName, argRestrictions);
- } else {
- methodName = name.substring(hashIdx + 1);
- methodRestriction = new MethodRestriction(methodName);
- }
- } else {
- if ("*".equalsIgnoreCase(name)) {
- className = ServiceLoader.class.getName();
- methodName = "load";
- ArgRestrictions argRestrictions = new ArgRestrictions();
- argRestrictions.addRestriction(0, Class.class.getName());
- methodRestriction = new MethodRestriction(methodName, argRestrictions);
- } else {
- throw new IllegalArgumentException("Must at least specify class name and method name: " + name);
- }
- }
- ConsumerRestriction restriction = new ConsumerRestriction(className, methodRestriction);
-
- Set<ConsumerRestriction> restrictions = new HashSet<ConsumerRestriction>();
- restrictions.add(restriction);
-
- String bsn = element.getAttribute("bundle");
- if (bsn != null) {
- bsn = bsn.trim();
- if (bsn.length() > 0) {
- for (String s : bsn.split("\\|")) {
- int colonIdx = s.indexOf(':');
- if (colonIdx > 0) {
- String sn = s.substring(0, colonIdx);
- String versionSfx = s.substring(colonIdx + 1);
- if (versionSfx.startsWith("version=")) {
- allowedBundles.add(new BundleDescriptor(sn,
- Version.parseVersion(versionSfx.substring("version=".length()))));
- } else {
- allowedBundles.add(new BundleDescriptor(sn));
- }
- } else {
- allowedBundles.add(new BundleDescriptor(s));
- }
- }
- }
- }
-
- String bid = element.getAttribute("bundleId");
- if (bid != null) {
- bid = bid.trim();
- if (bid.length() > 0) {
- for (String s : bid.split("\\|")) {
- for (Bundle b : consumerBundle.getBundleContext().getBundles()) {
- if (("" + b.getBundleId()).equals(s)) {
- allowedBundles.add(new BundleDescriptor(b.getSymbolicName()));
- break;
- }
- }
- }
- }
- }
-
- // TODO fix log message
- // Activator.activator.log(LogService.LOG_INFO, "Weaving " + className + "#" + methodName + " from bundle " +
- // consumerBundle.getSymbolicName() + " to " + (allowedBundles.size() == 0 ? " any provider" : allowedBundles));
-
- Activator.activator.registerConsumerBundle(consumerBundle, restrictions,
- allowedBundles.size() == 0 ? null : allowedBundles);
- String[] argClasses = restriction.getMethodRestriction(methodName).getArgClasses();
-
- weavingData.add(new WeavingData(className, methodName, argClasses));
- }
- return weavingData.toArray(new WeavingData [weavingData.size()]);
- }
}
Added: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java?rev=1082164&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java (added)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java Wed Mar 16 15:16:50 2011
@@ -0,0 +1,174 @@
+/**
+ * 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.aries.spifly;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.apache.aries.spifly.HeaderParser.PathElement;
+import org.osgi.framework.Version;
+
+public class ConsumerHeaderProcessor {
+ /**
+ * Parses headers of the following syntax:
+ * <ul>
+ * <li><tt>org.acme.MyClass#myMethod</tt> - apply the weaving to all overloads of <tt>myMethod()</tt>
+ * in <tt>MyClass</tt>
+ * <li><tt>org.acme.MyClass#myMethod(java.lang.String, java.util.List)</tt> - apply the weaving only
+ * to the <tt>myMethod(String, List)</tt> overload in <tt>MyClass</tt>
+ * <li><tt>org.acme.MyClass#myMethod()</tt> - apply the weaving only to the noarg overload of
+ * <tt>myMethod()</tt>
+ * <li><b>true</b> - equivalent to <tt>java.util.ServiceLoader#load(java.lang.Class)</tt>
+ * </ul>
+ * Additionally, it registers the consumer's constraints with the consumer registry in the activator, if the
+ * consumer is only constrained to a certain set of bundles.<p/>
+ *
+ * The following attributes are supported:
+ * <ul>
+ * <li><tt>bundle</tt> - restrict wiring to the bundle with the specifies Symbolic Name. The attribute value
+ * is a list of bundle identifiers separated by a '|' sign. The bundle identifier starts with the Symbolic name
+ * and can optionally contain a version suffix. E.g. bundle=impl2:version=1.2.3 or bundle=impl2|impl4.
+ * <li><tt>bundleId</tt> - restrict wiring to the bundle with the specified bundle ID. Typically used when
+ * the service should be forceably picked up from the system bundle (<tt>bundleId=0</tt>). Multiple bundle IDs
+ * can be specified separated by a '|' sign.
+ * </ul>
+ *
+ * @param consumerBundle the consuming bundle.
+ * @param consumerHeader the <tt>SPI-Consumer</tt> header.
+ * @return an instance of the {@link WeavingData} class.
+ */
+ public static WeavingData[] processHeader(/* Bundle consumerBundle, */String consumerHeader) {
+ Set<WeavingData> weavingData = new HashSet<WeavingData>();
+
+ for (PathElement element : HeaderParser.parseHeader(consumerHeader)) {
+ List<BundleDescriptor> allowedBundles = new ArrayList<BundleDescriptor>();
+ String name = element.getName().trim();
+
+ String className;
+ String methodName;
+ MethodRestriction methodRestriction;
+
+ int hashIdx = name.indexOf('#');
+ if (hashIdx > 0) {
+ className = name.substring(0, hashIdx);
+ int braceIdx = name.substring(hashIdx).indexOf('(');
+ if (braceIdx > 0) {
+ methodName = name.substring(hashIdx + 1, hashIdx + braceIdx);
+ ArgRestrictions argRestrictions = new ArgRestrictions();
+ int closeIdx = name.substring(hashIdx).indexOf(')');
+ if (closeIdx > 0) {
+ String classes = name.substring(hashIdx + braceIdx + 1, hashIdx + closeIdx).trim();
+ if (classes.length() > 0) {
+ if (classes.indexOf('[') > 0) {
+ int argNumber = 0;
+ for (String s : classes.split(",")) {
+ int idx = s.indexOf('[');
+ int end = s.indexOf(']', idx);
+ if (idx > 0 && end > idx) {
+ argRestrictions.addRestriction(argNumber, s.substring(0, idx), s.substring(idx + 1, end));
+ } else {
+ argRestrictions.addRestriction(argNumber, s);
+ }
+ argNumber++;
+ }
+ } else {
+ String[] classNames = classes.split(",");
+ for (int i = 0; i < classNames.length; i++) {
+ argRestrictions.addRestriction(i, classNames[i]);
+ }
+ }
+ } else {
+ argRestrictions = null;
+ }
+ }
+ methodRestriction = new MethodRestriction(methodName, argRestrictions);
+ } else {
+ methodName = name.substring(hashIdx + 1);
+ methodRestriction = new MethodRestriction(methodName);
+ }
+ } else {
+ if ("*".equalsIgnoreCase(name)) {
+ className = ServiceLoader.class.getName();
+ methodName = "load";
+ ArgRestrictions argRestrictions = new ArgRestrictions();
+ argRestrictions.addRestriction(0, Class.class.getName());
+ methodRestriction = new MethodRestriction(methodName, argRestrictions);
+ } else {
+ throw new IllegalArgumentException("Must at least specify class name and method name: " + name);
+ }
+ }
+ ConsumerRestriction restriction = new ConsumerRestriction(className, methodRestriction);
+
+ Set<ConsumerRestriction> restrictions = new HashSet<ConsumerRestriction>();
+ restrictions.add(restriction);
+
+ String bsn = element.getAttribute("bundle");
+ if (bsn != null) {
+ bsn = bsn.trim();
+ if (bsn.length() > 0) {
+ for (String s : bsn.split("\\|")) {
+ int colonIdx = s.indexOf(':');
+ if (colonIdx > 0) {
+ String sn = s.substring(0, colonIdx);
+ String versionSfx = s.substring(colonIdx + 1);
+ if (versionSfx.startsWith("version=")) {
+ allowedBundles.add(new BundleDescriptor(sn,
+ Version.parseVersion(versionSfx.substring("version=".length()))));
+ } else {
+ allowedBundles.add(new BundleDescriptor(sn));
+ }
+ } else {
+ allowedBundles.add(new BundleDescriptor(s));
+ }
+ }
+ }
+ }
+
+ // TODO this cannot be done this way with static weaving...
+ /*
+ String bid = element.getAttribute("bundleId");
+ if (bid != null) {
+ bid = bid.trim();
+ if (bid.length() > 0) {
+ for (String s : bid.split("\\|")) {
+ for (Bundle b : consumerBundle.getBundleContext().getBundles()) {
+ if (("" + b.getBundleId()).equals(s)) {
+ allowedBundles.add(new BundleDescriptor(b.getSymbolicName()));
+ break;
+ }
+ }
+ }
+ }
+ }
+ */
+
+// Activator.activator.registerConsumerBundle(consumerBundle, restrictions,
+// allowedBundles.size() == 0 ? null : allowedBundles);
+ // TODO this can be done in the WeavingData itself?
+ String[] argClasses = restriction.getMethodRestriction(methodName).getArgClasses();
+
+ weavingData.add(new WeavingData(className, methodName, argClasses, restrictions,
+ allowedBundles.size() == 0 ? null : allowedBundles));
+ }
+ return weavingData.toArray(new WeavingData [weavingData.size()]);
+ }
+}
Modified: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/WeavingData.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/WeavingData.java?rev=1082164&r1=1082163&r2=1082164&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/WeavingData.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/WeavingData.java Wed Mar 16 15:16:50 2011
@@ -19,6 +19,8 @@
package org.apache.aries.spifly;
import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
/** Contains information needed for the byte code weaver.
*/
@@ -26,6 +28,8 @@ public class WeavingData {
private final String className;
private final String methodName;
private final String[] argClasses;
+ private final Set<ConsumerRestriction> argRestrictions;
+ private final List<BundleDescriptor> allowedBundles;
/**
* Constructor.
@@ -34,11 +38,16 @@ public class WeavingData {
* @param argClasses The overload (class names of the signature) of the call
* that needs to be woven. If <code>null</code> then all overloads of the method
* need to be woven.
+ * @param argRestrictions
+ * @param allowedBundles
*/
- public WeavingData(String className, String methodName, String[] argClasses) {
+ public WeavingData(String className, String methodName, String[] argClasses, Set<ConsumerRestriction> argRestrictions, List<BundleDescriptor> allowedBundles) {
+ // TODO can we infer argClasses from restrictions?
this.className = className;
this.methodName = methodName;
this.argClasses = argClasses;
+ this.argRestrictions = argRestrictions;
+ this.allowedBundles = allowedBundles;
}
public String getClassName() {
@@ -49,10 +58,18 @@ public class WeavingData {
return methodName;
}
+ public List<BundleDescriptor> getAllowedBundles() {
+ return allowedBundles;
+ }
+
public String[] getArgClasses() {
return argClasses;
- }
+ }
+ public Set<ConsumerRestriction> getArgRestrictions() {
+ return argRestrictions;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@@ -88,7 +105,5 @@ public class WeavingData {
} else if (!methodName.equals(other.methodName))
return false;
return true;
- }
-
-
+ }
}
Modified: aries/trunk/spi-fly/spi-fly-static/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static/pom.xml?rev=1082164&r1=1082163&r2=1082164&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static/pom.xml (original)
+++ aries/trunk/spi-fly/spi-fly-static/pom.xml Wed Mar 16 15:16:50 2011
@@ -35,6 +35,12 @@
<dependencies>
<dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>3.3.1</version>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.aries.spifly</groupId>
<artifactId>org.apache.aries.spifly.core</artifactId>
<version>${pom.version}</version>
Added: aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/DirTree.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/DirTree.java?rev=1082164&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/DirTree.java (added)
+++ aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/DirTree.java Wed Mar 16 15:16:50 2011
@@ -0,0 +1,51 @@
+/**
+ * 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.aries.spifly.statictool;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DirTree {
+ List<File> fileList = new ArrayList<File>();
+
+ public DirTree(File f) {
+ String[] names = f.list();
+
+ if (names == null) {
+ fileList.add(f);
+ return;
+ }
+
+ for (String name : names) {
+ File curFile = new File(f, name);
+
+ if (curFile.isDirectory()) {
+ fileList.addAll(new DirTree(curFile).getFiles());
+ } else {
+ fileList.add(curFile);
+ }
+ }
+ fileList.add(f);
+ }
+
+ public List<File> getFiles() {
+ return fileList;
+ }
+}
Modified: aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/Main.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/Main.java?rev=1082164&r1=1082163&r2=1082164&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/Main.java (original)
+++ aries/trunk/spi-fly/spi-fly-static/src/main/java/org/apache/aries/spifly/statictool/Main.java Wed Mar 16 15:16:50 2011
@@ -20,15 +20,23 @@ package org.apache.aries.spifly.staticto
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.OutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
+import org.apache.aries.spifly.ConsumerHeaderProcessor;
import org.apache.aries.spifly.Streams;
+import org.apache.aries.spifly.TCCLSetterVisitor;
+import org.apache.aries.spifly.WeavingData;
+import org.apache.aries.spifly.api.SpiFlyConstants;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
public class Main {
public static void usage() {
@@ -45,11 +53,45 @@ public class Main {
private static void weaveJar(String jarPath) throws IOException {
File jarFile = new File(jarPath);
- File tempdir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis());
- unJar(jarFile, tempdir);
+ File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis());
+ Manifest manifest = unJar(jarFile, tempDir);
+ String consumerHeader = manifest.getMainAttributes().getValue(SpiFlyConstants.SPI_CONSUMER_HEADER);
+ if (consumerHeader != null) {
+ weaveDir(tempDir, consumerHeader);
+ // jar(tempDir, newJar);
+ }
+ // finally - clean up
+ }
+
+ private static void weaveDir(File dir, String consumerHeader) throws IOException {
+ DirTree dt = new DirTree(dir);
+ for (File f : dt.getFiles()) {
+ if (!f.getName().endsWith(".class"))
+ continue;
+
+ WeavingData[] wd = ConsumerHeaderProcessor.processHeader(consumerHeader);
+ InputStream is = new FileInputStream(f);
+ byte[] b;
+ try {
+ ClassReader cr = new ClassReader(is);
+ ClassWriter cw = new ClassWriter(0);
+ ClassVisitor cv = new TCCLSetterVisitor(cw, null, wd);
+ cr.accept(cv, 0);
+ b = cw.toByteArray();
+ } finally {
+ is.close();
+ }
+
+ OutputStream os = new FileOutputStream(f);
+ try {
+ os.write(b);
+ } finally {
+ os.close();
+ }
+ }
}
- static void unJar(File jarFile, File tempDir) throws IOException {
+ static Manifest unJar(File jarFile, File tempDir) throws IOException {
ensureDirectory(tempDir);
JarInputStream jis = new JarInputStream(new FileInputStream(jarFile));
@@ -93,6 +135,55 @@ public class Main {
}
jis.close();
+ return manifest;
+ }
+
+ static void jar(File jarFile, File rootFile, Manifest manifest) throws IOException {
+ JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest);
+ try {
+ addToJarRecursively(jos, rootFile.getAbsoluteFile(), rootFile.getAbsolutePath());
+ } finally {
+ jos.close();
+ }
+ }
+
+ static void addToJarRecursively(JarOutputStream jar, File source, String rootDirectory) throws IOException {
+ String sourceName = source.getAbsolutePath().replace("\\", "/");
+ sourceName = sourceName.substring(rootDirectory.length());
+
+ if (sourceName.startsWith("/")) {
+ sourceName = sourceName.substring(1);
+ }
+
+ if ("META-INF/MANIFEST.MF".equals(sourceName))
+ return;
+
+ if (source.isDirectory()) {
+ /* Is there any point in adding a directory beyond just taking up space?
+ if (!sourceName.isEmpty()) {
+ if (!sourceName.endsWith("/")) {
+ sourceName += "/";
+ }
+ JarEntry entry = new JarEntry(sourceName);
+ jar.putNextEntry(entry);
+ jar.closeEntry();
+ }
+ */
+ for (File nested : source.listFiles()) {
+ addToJarRecursively(jar, nested, rootDirectory);
+ }
+ return;
+ }
+
+ JarEntry entry = new JarEntry(sourceName);
+ jar.putNextEntry(entry);
+ InputStream is = new FileInputStream(source);
+ try {
+ Streams.pump(is, jar);
+ } finally {
+ jar.closeEntry();
+ is.close();
+ }
}
private static void ensureDirectory(File outDir) throws IOException {
Modified: aries/trunk/spi-fly/spi-fly-static/src/test/java/org/apache/aries/spifly/statictool/MainTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static/src/test/java/org/apache/aries/spifly/statictool/MainTest.java?rev=1082164&r1=1082163&r2=1082164&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static/src/test/java/org/apache/aries/spifly/statictool/MainTest.java (original)
+++ aries/trunk/spi-fly/spi-fly-static/src/test/java/org/apache/aries/spifly/statictool/MainTest.java Wed Mar 16 15:16:50 2011
@@ -23,20 +23,22 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.util.jar.Manifest;
import org.apache.aries.spifly.Streams;
import org.junit.Assert;
import org.junit.Test;
+import org.junit.internal.ArrayComparisonFailure;
public class MainTest {
@Test
- public void testUnJar() throws Exception {
+ public void testUnJarReJar() throws Exception {
URL jarURL = getClass().getResource("/testjar.jar");
File jarFile = new File(jarURL.getFile());
File tempDir = new File(System.getProperty("java.io.tmpdir") + "/testjar_" + System.currentTimeMillis());
try {
- Main.unJar(jarFile, tempDir);
+ Manifest manifest = Main.unJar(jarFile, tempDir);
assertStreams(new File(tempDir, "META-INF/MANIFEST.MF"),
"jar:" + jarURL + "!/META-INF/MANIFEST.MF");
@@ -51,14 +53,43 @@ public class MainTest {
"jar:" + jarURL + "!/dir/dir 2/b.txt");
Assert.assertTrue(new File(tempDir, "dir/dir.3").exists());
+
+ // Create a second jar from the exploded directory
+ File copiedFile = new File(jarFile.getAbsolutePath() + ".copy");
+ Main.jar(copiedFile, tempDir, manifest);
+ URL copyURL = copiedFile.toURI().toURL();
+
+ assertStreams("jar:" + copyURL + "!/META-INF/MANIFEST.MF",
+ "jar:" + jarURL + "!/META-INF/MANIFEST.MF");
+
+ assertStreams("jar:" + copyURL + "!/A text File with no content",
+ "jar:" + jarURL + "!/A text File with no content");
+ assertStreams("jar:" + copyURL + "!/dir/Main.class",
+ "jar:" + jarURL + "!/dir/Main.class");
+ assertStreams("jar:" + copyURL + "!/dir/dir 2/a.txt",
+ "jar:" + jarURL + "!/dir/dir 2/a.txt");
+ assertStreams("jar:" + copyURL + "!/dir/dir 2/b.txt",
+ "jar:" + jarURL + "!/dir/dir 2/b.txt");
} finally {
deleteTree(tempDir);
}
}
-
+
+
+ private void assertStreams(String url1, String url2) throws Exception {
+ InputStream is1 = new URL(url1).openStream();
+ InputStream is2 = new URL(url2).openStream();
+ assertStreams(is1, is2);
+ }
+
private void assertStreams(File file, String url) throws Exception {
InputStream is1 = new FileInputStream(file);
InputStream is2 = new URL(url).openStream();
+ assertStreams(is1, is2);
+ }
+
+ private void assertStreams(InputStream is1, InputStream is2)
+ throws IOException, ArrayComparisonFailure {
try {
byte[] bytes1 = Streams.suck(is1);
byte[] bytes2 = Streams.suck(is2);