Latest pre-release bnd code
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1387568 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/WorkspaceRepository.java b/bundleplugin/src/main/java/aQute/bnd/build/WorkspaceRepository.java
index 88ead98..ce5cb66 100644
--- a/bundleplugin/src/main/java/aQute/bnd/build/WorkspaceRepository.java
+++ b/bundleplugin/src/main/java/aQute/bnd/build/WorkspaceRepository.java
@@ -32,6 +32,8 @@
foundVersion.put(version, file);
}
}
+
+ jar.close();
}
}
}
@@ -49,7 +51,7 @@
return new File[0];
}
- public File get(String bsn, String range, Strategy strategy, Map<String,String> properties) throws Exception {
+ private File get(String bsn, String range, Strategy strategy, Map<String,String> properties) throws Exception {
File[] files = get(bsn, range);
if (files.length == 0) {
@@ -114,6 +116,8 @@
names.add(bsn);
}
}
+
+ jar.close();
}
}
}
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java b/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
index 09c5f25..f9c396e 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
@@ -29,18 +29,35 @@
final static Pattern PROPERTY_PATTERN = Pattern
.compile("\\s*([^=\\s:]+)\\s*(?::\\s*(Boolean|Byte|Character|Short|Integer|Long|Float|Double|String)\\s*)?=(.*)");
- public static final Version V1_0 = new Version("1.0.0"); // "1.1.0"
+ public static final Version V1_0 = new Version("1.0.0"); // "1.0.0"
public static final Version V1_1 = new Version("1.1.0"); // "1.1.0"
- public static final Version V1_2 = new Version("1.2.0"); // "1.1.0"
- static Pattern BINDNAME = Pattern.compile("(set|add|bind)?(.*)");
- static Pattern BINDDESCRIPTOR = Pattern
- .compile("\\(((L([^;]+);)(Ljava/util/Map;)?|Lorg/osgi/framework/ServiceReference;)\\)V");
+ public static final Version V1_2 = new Version("1.2.0"); // "1.2.0"
+// public static final Version V1_3 = new Version("1.3.0"); // "1.3.0"
- static Pattern LIFECYCLEDESCRIPTOR = Pattern
- .compile("\\(((Lorg/osgi/service/component/ComponentContext;)|(Lorg/osgi/framework/BundleContext;)|(Ljava/util/Map;))*\\)V");
- static Pattern REFERENCEBINDDESCRIPTOR = Pattern
+ public static final String FELIX_1_2 = "http://felix.apache.org/xmlns/scr/v1.2.0-felix";
+
+ static Pattern BINDNAME = Pattern.compile("(set|add|bind)?(.*)");
+
+ static Pattern BINDDESCRIPTORDS10 = Pattern
+ .compile("\\(((L([^;]+);)|Lorg/osgi/framework/ServiceReference;)\\)V");
+ static Pattern BINDDESCRIPTORDS11 = Pattern
+ .compile("\\(((L([^;]+);)(Ljava/util/Map;)?|Lorg/osgi/framework/ServiceReference;)\\)V");
+ static Pattern BINDDESCRIPTORDS13 = Pattern
+ .compile("\\(((L([^;]+);)(Ljava/util/Map;)?|Lorg/osgi/framework/ServiceReference;)\\)Ljava/util/Map;");
+ static Pattern REFERENCEBINDDESCRIPTOR = Pattern
.compile("\\(Lorg/osgi/framework/ServiceReference;\\)V");
+ static Pattern LIFECYCLEDESCRIPTORDS10 = Pattern
+ .compile("\\((Lorg/osgi/service/component/ComponentContext;)\\)V");
+ static Pattern LIFECYCLEDESCRIPTORDS11 = Pattern
+ .compile("\\(((Lorg/osgi/service/component/ComponentContext;)|(Lorg/osgi/framework/BundleContext;)|(Ljava/util/Map;))*\\)V");
+ static Pattern LIFECYCLEDESCRIPTORDS13 = Pattern
+ .compile("\\(((Lorg/osgi/service/component/ComponentContext;)|(Lorg/osgi/framework/BundleContext;)|(Ljava/util/Map;))*\\)Ljava/util/Map;");
+ static Pattern DEACTIVATEDESCRIPTORDS11 = Pattern
+ .compile("\\(((Lorg/osgi/service/component/ComponentContext;)|(Lorg/osgi/framework/BundleContext;)|(Ljava/util/Map;)|(Ljava/lang/Integer;)|(I))*\\)V");
+ static Pattern DEACTIVATEDESCRIPTORDS13 = Pattern
+ .compile("\\(((Lorg/osgi/service/component/ComponentContext;)|(Lorg/osgi/framework/BundleContext;)|(Ljava/util/Map;)|(Ljava/lang/Integer;)|(I))*\\)Ljava/util/Map;");
+
ComponentDef component = new ComponentDef();
Clazz clazz;
@@ -50,18 +67,22 @@
Analyzer analyzer;
MultiMap<String,String> methods = new MultiMap<String,String>();
TypeRef extendsClass;
- boolean inherit;
+ final boolean inherit;
boolean baseclass = true;
+
+ final boolean felixExtensions;
- AnnotationReader(Analyzer analyzer, Clazz clazz, boolean inherit) {
+ AnnotationReader(Analyzer analyzer, Clazz clazz, boolean inherit, boolean felixExtensions) {
this.analyzer = analyzer;
this.clazz = clazz;
this.inherit = inherit;
+ this.felixExtensions = felixExtensions;
}
public static ComponentDef getDefinition(Clazz c, Analyzer analyzer) throws Exception {
boolean inherit = Processor.isTrue(analyzer.getProperty("-dsannotations-inherit"));
- AnnotationReader r = new AnnotationReader(analyzer, c, inherit);
+ boolean felixExtensions = Processor.isTrue(analyzer.getProperty("-ds-felix-extensions"));
+ AnnotationReader r = new AnnotationReader(analyzer, c, inherit, felixExtensions);
return r.getDef();
}
@@ -112,15 +133,36 @@
if (methods.containsKey(value)) {
for (String descriptor : methods.get(value)) {
- Matcher matcher = BINDDESCRIPTOR.matcher(descriptor);
+ Matcher matcher = BINDDESCRIPTORDS10.matcher(descriptor);
if (matcher.matches()) {
String type = matcher.group(2);
- if (rdef.service.equals(Clazz.objectDescriptorToFQN(type)) || type.equals("Ljava/util/Map;")
+ if (rdef.service.equals(Clazz.objectDescriptorToFQN(type))
|| type.equals("Lorg/osgi/framework/ServiceReference;")) {
return value;
}
}
+ matcher = BINDDESCRIPTORDS11.matcher(descriptor);
+ if (matcher.matches()) {
+ String type = matcher.group(2);
+ if (rdef.service.equals(Clazz.objectDescriptorToFQN(type))
+ || type.equals("Lorg/osgi/framework/ServiceReference;")) {
+ rdef.updateVersion(V1_1);
+ return value;
+ }
+ }
+ matcher = BINDDESCRIPTORDS13.matcher(descriptor);
+ if (felixExtensions && matcher.matches()) {
+ String type = matcher.group(2);
+ if (rdef.service.equals(Clazz.objectDescriptorToFQN(type))
+ || type.equals("Lorg/osgi/framework/ServiceReference;")) {
+ rdef.updateVersion(V1_2);
+ if (component.xmlns == null) {
+ component.xmlns = FELIX_1_2;
+ }
+ return value;
+ }
+ }
}
analyzer.error(
"A related method to %s from the reference %s has no proper prototype for class %s. Expected void %s(%s s [,Map m] | ServiceReference r)",
@@ -153,27 +195,66 @@
/**
*
*/
- protected void doDeactivate() {
- if (!LIFECYCLEDESCRIPTOR.matcher(method.getDescriptor().toString()).matches())
+ protected void doActivate() {
+ String methodDescriptor = method.getDescriptor().toString();
+ if ("activate".equals(method.getName()) && LIFECYCLEDESCRIPTORDS10.matcher(methodDescriptor).matches()) {
+ component.activate = method.getName();
+ } else if (LIFECYCLEDESCRIPTORDS11.matcher(methodDescriptor).matches()) {
+ component.activate = method.getName();
+ component.updateVersion(V1_1);
+ } else if (felixExtensions && LIFECYCLEDESCRIPTORDS13.matcher(methodDescriptor).matches()) {
+ component.activate = method.getName();
+ component.updateVersion(V1_2);
+ if (component.xmlns == null) {
+ component.xmlns = FELIX_1_2;
+ }
+ } else
analyzer.error(
- "Deactivate method for %s does not have an acceptable prototype, only Map, ComponentContext, or BundleContext is allowed. Found: %s",
+ "Activate method for %s does not have an acceptable prototype, only Map, ComponentContext, or BundleContext is allowed. Found: %s",
clazz, method.getDescriptor());
- else {
+
+ }
+
+ /**
+ *
+ */
+ protected void doDeactivate() {
+ String methodDescriptor = method.getDescriptor().toString();
+ if ( "deactivate".equals(method.getName()) && LIFECYCLEDESCRIPTORDS10.matcher(methodDescriptor).matches()) {
+ component.deactivate = method.getName();
+ } else if (DEACTIVATEDESCRIPTORDS11.matcher(methodDescriptor).matches()) {
component.deactivate = method.getName();
- }
+ component.updateVersion(V1_1);
+ } else if (felixExtensions && DEACTIVATEDESCRIPTORDS13.matcher(methodDescriptor).matches()) {
+ component.deactivate = method.getName();
+ component.updateVersion(V1_2);
+ if (component.xmlns == null) {
+ component.xmlns = FELIX_1_2;
+ }
+ } else
+ analyzer.error(
+ "Deactivate method for %s does not have an acceptable prototype, only Map, ComponentContext, BundleContext, int, or Integer is allowed. Found: %s",
+ clazz, method.getDescriptor());
}
/**
*
*/
protected void doModified() {
- if (!LIFECYCLEDESCRIPTOR.matcher(method.getDescriptor().toString()).matches())
+ if (LIFECYCLEDESCRIPTORDS11.matcher(method.getDescriptor().toString()).matches()) {
+ component.modified = method.getName();
+ component.updateVersion(V1_1);
+ } else if (felixExtensions && LIFECYCLEDESCRIPTORDS13.matcher(method.getDescriptor().toString()).matches()) {
+ component.modified = method.getName();
+ component.updateVersion(V1_2);
+ if (component.xmlns == null) {
+ component.xmlns = FELIX_1_2;
+ }
+ } else
+
analyzer.error(
"Modified method for %s does not have an acceptable prototype, only Map, ComponentContext, or BundleContext is allowed. Found: %s",
clazz, method.getDescriptor());
- else {
- component.modified = method.getName();
- }
}
/**
@@ -202,13 +283,29 @@
} else {
// We have to find the type of the current method to
// link it to the referenced service.
- Matcher m = BINDDESCRIPTOR.matcher(method.getDescriptor().toString());
+ String methodDescriptor = method.getDescriptor().toString();
+ Matcher m = BINDDESCRIPTORDS10.matcher(methodDescriptor);
if (m.matches()) {
def.service = Descriptors.binaryToFQN(m.group(3));
- } else
- throw new IllegalArgumentException(
- "Cannot detect the type of a Component Reference from the descriptor: "
- + method.getDescriptor());
+ } else {
+ m = BINDDESCRIPTORDS11.matcher(methodDescriptor);
+ if (m.matches()) {
+ def.service = Descriptors.binaryToFQN(m.group(3));
+ def.updateVersion(V1_1);
+ } else {
+ m = BINDDESCRIPTORDS13.matcher(methodDescriptor);
+ if (felixExtensions && m.matches()) {
+ def.service = Descriptors.binaryToFQN(m.group(3));
+ def.updateVersion(V1_2);
+ if (component.xmlns == null) {
+ component.xmlns = FELIX_1_2;
+ }
+ } else
+ throw new IllegalArgumentException(
+ "Cannot detect the type of a Component Reference from the descriptor: "
+ + method.getDescriptor());
+ }
+ }
}
// Check if we have a target, this must be a filter
@@ -227,19 +324,6 @@
}
/**
- *
- */
- protected void doActivate() {
- if (!LIFECYCLEDESCRIPTOR.matcher(method.getDescriptor().toString()).matches())
- analyzer.error(
- "Activate method for %s does not have an acceptable prototype, only Map, ComponentContext, or BundleContext is allowed. Found: %s",
- clazz, method.getDescriptor());
- else {
- component.activate = method.getName();
- }
- }
-
- /**
* @param annotation
* @throws Exception
*/
@@ -249,7 +333,6 @@
if (component.implementation != null)
return;
- component.version = V1_0;
component.implementation = clazz.getClassName();
component.name = comp.name();
component.factory = comp.factory();
@@ -263,8 +346,10 @@
if (annotation.get("servicefactory") != null)
component.servicefactory = comp.servicefactory();
- if (annotation.get("configurationPid") != null)
+ if (annotation.get("configurationPid") != null) {
component.configurationPid = comp.configurationPid();
+ component.updateVersion(V1_2);
+ }
if (annotation.get("xmlns") != null)
component.xmlns = comp.xmlns();
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java b/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
index b368f0b..8c4b090 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
@@ -50,11 +50,8 @@
*/
void prepare(Analyzer analyzer) throws Exception {
- for (ReferenceDef ref : references.values()) {
- ref.prepare(analyzer);
- if (ref.version.compareTo(version) > 0)
- version = ref.version;
- }
+ prepareVersion(analyzer);
+
if (implementation == null) {
analyzer.error("No Implementation defined for component " + name);
@@ -72,11 +69,6 @@
} else if (servicefactory != null && servicefactory)
analyzer.warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
- if (configurationPolicy != null)
- version = ReferenceDef.max(version, AnnotationReader.V1_1);
- if (configurationPid != null)
- version = ReferenceDef.max(version, AnnotationReader.V1_2);
-
for (Map.Entry<String,List<String>> kvs : property.entrySet()) {
Tag property = new Tag("property");
String name = kvs.getKey();
@@ -110,6 +102,21 @@
propertyTags.add(property);
}
}
+
+ private void prepareVersion(Analyzer analyzer) throws Exception {
+
+ for (ReferenceDef ref : references.values()) {
+ ref.prepare(analyzer);
+ updateVersion(ref.version);
+ }
+ if (configurationPolicy != null)
+ updateVersion(AnnotationReader.V1_1);
+ if (configurationPid != null)
+ updateVersion(AnnotationReader.V1_2);
+ if (modified != null)
+ updateVersion(AnnotationReader.V1_1);
+
+ }
void sortReferences() {
Map<String, ReferenceDef> temp = new TreeMap<String,ReferenceDef>(references);
@@ -147,10 +154,10 @@
if (factory != null)
component.addAttribute("factory", factory);
- if (activate != null)
+ if (activate != null && version != AnnotationReader.V1_0)
component.addAttribute("activate", activate);
- if (deactivate != null)
+ if (deactivate != null && version != AnnotationReader.V1_0)
component.addAttribute("deactivate", deactivate);
if (modified != null)
@@ -220,4 +227,16 @@
}
return v;
}
+
+ void updateVersion(Version version) {
+ this.version = max(this.version, version);
+ }
+
+ static <T extends Comparable<T>> T max(T a, T b) {
+ int n = a.compareTo(b);
+ if (n >= 0)
+ return a;
+ return b;
+ }
+
}
\ No newline at end of file
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java b/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
index f57b7cb..d69b0aa 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
@@ -169,7 +169,7 @@
properties(cd, info, name);
reference(info, impl, cd, bindmethods);
//compute namespace after references, an updated method means ds 1.2.
- cd.xmlns = getNamespace(info, cd, lifecycleMethods);
+ getNamespace(info, cd, lifecycleMethods);
cd.prepare(analyzer);
return cd.getTag();
@@ -194,36 +194,39 @@
* @param descriptors TODO
* @return
*/
- private String getNamespace(Map<String, String> info, ComponentDef cd, Map<String,MethodDef> descriptors) {
+ private void getNamespace(Map<String, String> info, ComponentDef cd, Map<String,MethodDef> descriptors) {
String namespace = info.get(COMPONENT_NAMESPACE);
if (namespace != null) {
- return namespace;
+ cd.xmlns = namespace;
}
String version = info.get(COMPONENT_VERSION);
if (version != null) {
try {
Version v = new Version(version);
- return NAMESPACE_STEM + "/v" + v;
+ cd.updateVersion(v);
} catch (Exception e) {
error("version: specified on component header but not a valid version: "
+ version);
- return null;
+ return;
}
}
for (String key : info.keySet()) {
if (SET_COMPONENT_DIRECTIVES_1_2.contains(key)) {
- return NAMESPACE_STEM + "/v1.2.0";
+ cd.updateVersion(AnnotationReader.V1_2);
+ return;
}
}
for (ReferenceDef rd: cd.references.values()) {
if (rd.updated != null) {
- return NAMESPACE_STEM + "/v1.2.0";
+ cd.updateVersion(AnnotationReader.V1_2);
+ return;
}
}
//among other things this picks up any specified lifecycle methods
for (String key : info.keySet()) {
if (SET_COMPONENT_DIRECTIVES_1_1.contains(key)) {
- return NAMESPACE_STEM + "/v1.1.0";
+ cd.updateVersion(AnnotationReader.V1_1);
+ return;
}
}
for (String lifecycle: LIFECYCLE_METHODS) {
@@ -231,10 +234,10 @@
MethodDef test = descriptors.get(lifecycle);
if (descriptors.containsKey(lifecycle) && (!(test.isPublic() || test.isProtected()) ||
rateLifecycle(test, "deactivate".equals(lifecycle)? allowedDeactivate: allowed) > 1)) {
- return NAMESPACE_STEM + "/v1.1.0";
+ cd.updateVersion(AnnotationReader.V1_1);
+ return;
}
}
- return null;
}
/**
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java b/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
index cb4d489..255eef1 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
@@ -34,7 +34,7 @@
analyzer.error("No name for a reference");
if ((updated != null && !updated.equals("-")) || policyOption != null)
- version = max(version, AnnotationReader.V1_2);
+ updateVersion(AnnotationReader.V1_2);
if (target != null) {
String error = Verifier.validateFilter(target);
@@ -81,16 +81,14 @@
return ref;
}
- static <T extends Comparable<T>> T max(T a, T b) {
- int n = a.compareTo(b);
- if (n >= 0)
- return a;
- return b;
- }
-
@Override
public String toString() {
return name;
}
+
+ void updateVersion(Version version) {
+ this.version = ComponentDef.max(this.version, version);
+ }
+
}
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
index 860fe08..d6be831 100755
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
@@ -35,6 +35,7 @@
import aQute.bnd.osgi.Descriptors.PackageRef;
import aQute.bnd.osgi.Descriptors.TypeRef;
import aQute.bnd.service.*;
+import aQute.bnd.version.*;
import aQute.bnd.version.Version;
import aQute.lib.base64.*;
import aQute.lib.collections.*;
@@ -463,7 +464,7 @@
// This should not really happen. The code should never throw
// exceptions in normal situations. So if it happens we need more
// information. So to help diagnostics. We do a full property dump
- throw new IllegalStateException("Calc manifest failed, state=\n"+getFlattenedProperties(), e);
+ throw new IllegalStateException("Calc manifest failed, state=\n" + getFlattenedProperties(), e);
}
}
@@ -1925,7 +1926,12 @@
Matcher m = Verifier.VERSIONRANGE.matcher(version);
if (m.matches()) {
- return version;
+ try {
+ VersionRange vr = new VersionRange(version);
+ return version;
+ } catch( Exception e) {
+ // ignore
+ }
}
m = fuzzyVersionRange.matcher(version);
@@ -1945,6 +1951,15 @@
String micro = removeLeadingZeroes(m.group(5));
String qualifier = m.group(7);
+ if (qualifier == null) {
+ if (!isInteger(minor)) {
+ qualifier = minor;
+ minor = "0";
+ } else if (!isInteger(micro)) {
+ qualifier = micro;
+ micro = "0";
+ }
+ }
if (major != null) {
result.append(major);
if (minor != null) {
@@ -1971,6 +1986,20 @@
return version;
}
+ /**
+ * TRhe cleanup version got confused when people used numeric dates like
+ * 201209091230120 as qualifiers. These are too large for Integers. This
+ * method checks if the all digit string fits in an integer.
+ * <pre>
+ * maxint = 2,147,483,647 = 10 digits
+ * </pre>
+ * @param integer
+ * @return if this fits in an integer
+ */
+ private static boolean isInteger(String minor) {
+ return minor.length() < 10 || (minor.length() == 10 && minor.compareTo("2147483647") < 0);
+ }
+
private static String removeLeadingZeroes(String group) {
if (group == null)
return null;
@@ -2329,15 +2358,19 @@
// We assume the user knows what he is
// doing and inserted a literal. So
// we ignore any not matched literals
- if (instruction.isLiteral()) {
+ // #252, we should not be negated to make it a constant
+ if (instruction.isLiteral() && !instruction.isNegated()) {
result.merge(getPackageRef(instruction.getLiteral()), true, instructions.get(instruction));
i.remove();
continue;
}
// Not matching a negated instruction looks
- // like an error ...
+ // like an error ... Though so, but
+ // in the second phase of Export-Package
+ // the !package will never match anymore.
if (instruction.isNegated()) {
+ i.remove();
continue;
}
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/CommandResource.java b/bundleplugin/src/main/java/aQute/bnd/osgi/CommandResource.java
index 0e73945..19c1a21 100644
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/CommandResource.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/CommandResource.java
@@ -21,7 +21,6 @@
public void write(OutputStream out) throws IOException, Exception {
StringBuilder errors = new StringBuilder();
StringBuilder stdout = new StringBuilder();
- try {
domain.trace("executing command %s", command);
Command cmd = new Command("sh");
cmd.setCwd(wd);
@@ -40,12 +39,8 @@
osw.append(stdout);
osw.flush();
if (result != 0) {
- domain.error("executing command failed %s %s", command, stdout + "\n" + errors);
+ throw new Exception("executing command failed" + command + "\n"+ stdout + "\n" + errors);
}
- }
- catch (Exception e) {
- domain.error("executing command failed %s %s", command, e.getMessage());
- }
}
@Override
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Domain.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Domain.java
index 153674e..1b17aaf 100644
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Domain.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Domain.java
@@ -167,6 +167,7 @@
public Parameters getIncludeResource() {
Parameters ic = getParameters(INCLUDE_RESOURCE);
ic.putAll(getParameters(INCLUDERESOURCE));
+ ic.putAll(getParameters(WAB));
return ic;
}
diff --git a/bundleplugin/src/main/java/aQute/lib/converter/Converter.java b/bundleplugin/src/main/java/aQute/lib/converter/Converter.java
index a227d71..72b380c 100644
--- a/bundleplugin/src/main/java/aQute/lib/converter/Converter.java
+++ b/bundleplugin/src/main/java/aQute/lib/converter/Converter.java
@@ -22,7 +22,8 @@
}
boolean fatal = true;
- Map<Type,Hook> hooks = new HashMap<Type,Converter.Hook>();
+ Map<Type,Hook> hooks;
+ List<Hook> allHooks;
public <T> T convert(Class<T> type, Object o) throws Exception {
// Is it a compatible type?
@@ -44,11 +45,21 @@
return null; // compatible with any
}
- Hook hook = hooks.get(type);
- if (hook != null) {
- Object value = hook.convert(type, o);
- if (value != null)
- return value;
+ if (allHooks != null) {
+ for (Hook hook : allHooks) {
+ Object r = hook.convert(type, o);
+ if (r != null)
+ return r;
+ }
+ }
+
+ if (hooks != null) {
+ Hook hook = hooks.get(type);
+ if (hook != null) {
+ Object value = hook.convert(type, o);
+ if (value != null)
+ return value;
+ }
}
Class< ? > actualType = o.getClass();
@@ -243,22 +254,23 @@
f.set(instance, value);
}
catch (Exception ee) {
-
+
// We cannot find the key, so try the __extra field
Field f = resultType.getField("__extra");
Map<String,Object> extra = (Map<String,Object>) f.get(instance);
- if ( extra == null) {
+ if (extra == null) {
extra = new HashMap<String,Object>();
f.set(instance, extra);
}
- extra.put(key, convert(Object.class,e.getValue()));
-
+ extra.put(key, convert(Object.class, e.getValue()));
+
}
}
return instance;
}
catch (Exception e) {
- return error("No conversion found for " + o.getClass() + " to " + type + ", error " + e + " on key " + key);
+ return error("No conversion found for " + o.getClass() + " to " + type + ", error " + e + " on key "
+ + key);
}
}
@@ -441,7 +453,16 @@
}
public Converter hook(Type type, Hook hook) {
- this.hooks.put(type, hook);
+ if (type != null) {
+ if (hooks == null)
+ hooks = new HashMap<Type,Converter.Hook>();
+ this.hooks.put(type, hook);
+ } else {
+ if (allHooks == null)
+ allHooks = new ArrayList<Converter.Hook>();
+ allHooks.add(hook);
+ }
+
return this;
}
diff --git a/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java b/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
index 7fa7bb3..08e5d02 100644
--- a/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
+++ b/bundleplugin/src/main/java/aQute/lib/deployer/FileRepo.java
@@ -294,15 +294,15 @@
protected File putArtifact(File tmpFile, byte[] digest) throws Exception {
assert (tmpFile != null);
- Jar jar = new Jar(tmpFile);
+ Jar tmpJar = new Jar(tmpFile);
try {
dirty = true;
- String bsn = jar.getBsn();
+ String bsn = tmpJar.getBsn();
if (bsn == null)
throw new IllegalArgumentException("No bsn set in jar: " + tmpFile);
- String versionString = jar.getVersion();
+ String versionString = tmpJar.getVersion();
if (versionString == null)
versionString = "0";
else if (!Verifier.isVersion(versionString))
@@ -322,9 +322,12 @@
reporter.trace("updating %s ", file.getAbsolutePath());
+ // An open jar on file will fail rename on windows
+ tmpJar.close();
+
IO.rename(tmpFile, file);
- fireBundleAdded(jar, file);
+ fireBundleAdded(file);
afterPut(file, bsn, version, Hex.toHexString(digest));
// TODO like to beforeGet rid of the latest option. This is only
@@ -338,7 +341,7 @@
return file;
}
finally {
- jar.close();
+ tmpJar.close();
}
}
@@ -676,18 +679,25 @@
exec(beforeGet, root.getAbsolutePath(), bsn, version);
}
- protected void fireBundleAdded(Jar jar, File file) {
+ protected void fireBundleAdded(File file) {
if (registry == null)
return;
List<RepositoryListenerPlugin> listeners = registry.getPlugins(RepositoryListenerPlugin.class);
+ Jar jar = null;
for (RepositoryListenerPlugin listener : listeners) {
try {
+ if (jar == null)
+ jar = new Jar(file);
listener.bundleAdded(this, jar, file);
}
catch (Exception e) {
if (reporter != null)
reporter.warning("Repository listener threw an unexpected exception: %s", e);
}
+ finally {
+ if (jar != null)
+ jar.close();
+ }
}
}
@@ -699,34 +709,53 @@
* @param target
*/
void exec(String line, Object... args) {
- if (line == null)
+ if (line == null) {
return;
+ }
try {
- if (args != null)
+ if (args != null) {
for (int i = 0; i < args.length; i++) {
- if (i == 0)
- line = line.replaceAll("\\$\\{@\\}", args[0].toString());
- line = line.replaceAll("\\$" + i, args[i].toString());
+ if (i == 0) {
+ // replaceAll backslash magic ensures windows paths
+ // remain intact
+ line = line.replaceAll("\\$\\{@\\}", args[0].toString().replaceAll("\\\\", "\\\\\\\\"));
+ }
+ // replaceAll backslash magic ensures windows paths remain
+ // intact
+ line = line.replaceAll("\\$" + i, args[i].toString().replaceAll("\\\\", "\\\\\\\\"));
}
-
- if (shell == null) {
- shell = System.getProperty("os.name").toLowerCase().indexOf("win") > 0 ? "cmd.exe" : "sh";
}
- Command cmd = new Command(shell);
+ // purge remaining placeholders
+ line = line.replaceAll("\\s*\\$[0-9]\\s*", "");
- if (path != null) {
- cmd.inherit();
- String oldpath = cmd.var("PATH");
- path = path.replaceAll("\\s*,\\s*", File.pathSeparator);
- path = path.replaceAll("\\$\\{@\\}", oldpath);
- cmd.var("PATH", path);
- }
-
- cmd.setCwd(getRoot());
+ int result = 0;
StringBuilder stdout = new StringBuilder();
StringBuilder stderr = new StringBuilder();
- int result = cmd.execute(line, stdout, stderr);
+ if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) {
+
+ // FIXME ignoring possible shell setting stdin approach used
+ // below does not work in windows
+ Command cmd = new Command("cmd.exe /C " + line);
+ cmd.setCwd(getRoot());
+ result = cmd.execute(stdout, stderr);
+
+ } else {
+ if (shell == null) {
+ shell = "sh";
+ }
+ Command cmd = new Command(shell);
+ cmd.setCwd(getRoot());
+
+ if (path != null) {
+ cmd.inherit();
+ String oldpath = cmd.var("PATH");
+ path = path.replaceAll("\\s*,\\s*", File.pathSeparator);
+ path = path.replaceAll("\\$\\{@\\}", oldpath);
+ cmd.var("PATH", path);
+ }
+ result = cmd.execute(line, stdout, stderr);
+ }
if (result != 0) {
reporter.error("Command %s failed with %s %s %s", line, result, stdout, stderr);
}
diff --git a/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java b/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
index 7622ae7..349b381 100644
--- a/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
+++ b/bundleplugin/src/main/java/aQute/lib/json/ByteArrayHandler.java
@@ -3,15 +3,18 @@
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
+import java.util.regex.*;
+import aQute.lib.base64.*;
import aQute.lib.hex.*;
/**
- *
* Will now use hex for encoding byte arrays
- *
*/
public class ByteArrayHandler extends Handler {
+ Pattern ENCODING = Pattern
+ .compile("((:?[\\dA-Za-z][\\dA-Za-z])*)|((:?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)+={1,3})");
+
@Override
void encode(Encoder app, Object object, Map<Object,Type> visited) throws IOException, Exception {
StringHandler.string(app, Hex.toHexString((byte[]) object));
@@ -31,6 +34,47 @@
@Override
Object decode(Decoder dec, String s) throws Exception {
- return Hex.toByteArray(s);
+ boolean hex = true;
+ StringBuilder sb = new StringBuilder(s);
+ for (int i = sb.length() - 1; i >= 0; i--) {
+ char c = sb.charAt(i);
+ if (Character.isWhitespace(c))
+ sb.delete(i, i + 1);
+ else {
+ switch (c) {
+ case '0' :
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ case '8' :
+ case '9' :
+ case 'A' :
+ case 'B' :
+ case 'C' :
+ case 'D' :
+ case 'E' :
+ case 'F' :
+ case 'a' :
+ case 'b' :
+ case 'c' :
+ case 'd' :
+ case 'e' :
+ case 'f' :
+ break;
+
+ default :
+ hex = false;
+ break;
+ }
+ }
+ }
+ if ( hex)
+ return Hex.toByteArray(sb.toString());
+ else
+ return Base64.decodeBase64(sb.toString());
}
}