You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by mc...@apache.org on 2009/07/13 12:06:50 UTC
svn commit: r793527 [2/7] - in /felix/trunk/bundleplugin: ./
src/main/java/aQute/ src/main/java/aQute/bnd/
src/main/java/aQute/bnd/build/ src/main/java/aQute/bnd/help/
src/main/java/aQute/bnd/make/ src/main/java/aQute/bnd/service/
src/main/java/aQute/b...
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/Make.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/Make.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/Make.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/Make.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,101 @@
+package aQute.bnd.make;
+
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.bnd.service.*;
+import aQute.lib.osgi.*;
+
+public class Make {
+ Builder builder;
+ Map<Instruction, Map<String, String>> make;
+
+ public Make(Builder builder) {
+ this.builder = builder;
+ // builder.getPlugins().add(new MakeBnd());
+ // builder.getPlugins().add(new MakeCopy());
+ }
+
+ public Resource process(String source) {
+ Map<Instruction, Map<String, String>> make = getMakeHeader();
+ builder.trace("make " + source);
+
+ for (Map.Entry<Instruction, Map<String, String>> entry : make
+ .entrySet()) {
+ Instruction instr = (Instruction) entry.getKey();
+ Matcher m = instr.getMatcher(source);
+ if (m.matches() || instr.isNegated()) {
+ Map<String, String> arguments = replace(m, entry.getValue());
+ List<MakePlugin> plugins = builder.getPlugins(MakePlugin.class);
+ for (MakePlugin plugin : plugins) {
+ try {
+ Resource resource = plugin.make(builder,
+ source, arguments);
+ if (resource != null) {
+ builder.trace("Made " + source + " from args "
+ + arguments + " with " + plugin);
+ return resource;
+ }
+ } catch (Exception e) {
+ builder.error("Plugin " + plugin
+ + " generates error when use in making "
+ + source + " with args " + arguments, e);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private Map<String, String> replace(Matcher m, Map<String, String> value) {
+ Map<String, String> newArgs = Processor.newMap();
+ for (Map.Entry<String, String> entry : value.entrySet()) {
+ String s = entry.getValue();
+ s = replace(m, s);
+ newArgs.put(entry.getKey(), s);
+ }
+ return newArgs;
+ }
+
+ String replace(Matcher m, CharSequence s) {
+ StringBuffer sb = new StringBuffer();
+ int max = '0' + m.groupCount() + 1;
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '$' && i < s.length() - 1) {
+ c = s.charAt(++i);
+ if (c >= '0' && c <= max) {
+ int index = c - '0';
+ String replacement = m.group(index);
+ if (replacement != null)
+ sb.append(replacement);
+ } else {
+ if (c == '$')
+ i++;
+ sb.append(c);
+ }
+ } else
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ Map<Instruction, Map<String, String>> getMakeHeader() {
+ if (make != null)
+ return make;
+ make = Processor.newMap();
+
+ String s = builder.getProperty(Builder.MAKE);
+ Map<String, Map<String, String>> make = builder.parseHeader(s);
+ for (Iterator<Map.Entry<String, Map<String, String>>> e = make
+ .entrySet().iterator(); e.hasNext();) {
+ Map.Entry<String, Map<String, String>> entry = e.next();
+ String pattern = Processor.removeDuplicateMarker(entry.getKey());
+
+ Instruction instr = Instruction.getPattern(pattern);
+ this.make.put(instr, entry.getValue());
+ }
+
+ return this.make;
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/Make.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeBnd.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeBnd.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeBnd.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeBnd.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,64 @@
+package aQute.bnd.make;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.bnd.build.*;
+import aQute.bnd.service.*;
+import aQute.lib.osgi.*;
+
+public class MakeBnd implements MakePlugin, Constants {
+ final static Pattern JARFILE = Pattern.compile("(.+)\\.(jar|ipa)");
+
+ public Resource make(Builder builder, String destination,
+ Map<String, String> argumentsOnMake) throws Exception {
+ String type = (String) argumentsOnMake.get("type");
+ if (!"bnd".equals(type))
+ return null;
+
+ String recipe = (String) argumentsOnMake.get("recipe");
+ if (recipe == null) {
+ builder.error("No recipe specified on a make instruction for "
+ + destination);
+ return null;
+ }
+ File bndfile = builder.getFile(recipe);
+ if (bndfile.isFile()) {
+ // We do not use a parent because then we would
+ // build ourselves again. So we can not blindly
+ // inherit the properties.
+ Builder bchild = builder.getSubBuilder();
+ bchild.removeBundleSpecificHeaders();
+
+ // We must make sure that we do not include ourselves again!
+ bchild.setProperty(Analyzer.INCLUDE_RESOURCE, "");
+ bchild.setProperties(bndfile, builder.getBase());
+
+ Jar jar = bchild.build();
+ Jar dot = builder.getTarget();
+
+ if (builder.hasSources()) {
+ for (String key : jar.getResources().keySet()) {
+ if (key.startsWith("OSGI-OPT/src"))
+ dot.putResource(key, (Resource) jar.getResource(key));
+ }
+ }
+ builder.getInfo(bchild, bndfile.getName() +": ");
+ String debug = bchild.getProperty(DEBUG);
+ if (Processor.isTrue(debug)) {
+ if ( builder instanceof ProjectBuilder ) {
+ ProjectBuilder pb = (ProjectBuilder) builder;
+ File target = pb.getProject().getTarget();
+ target.mkdirs();
+ String bsn = bchild.getBsn();
+ File output = new File(target, bsn+".jar");
+ jar.write(output);
+ }
+ }
+ return new JarResource(jar);
+ } else
+ return null;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeBnd.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeCopy.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeCopy.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeCopy.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeCopy.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,45 @@
+package aQute.bnd.make;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import aQute.bnd.service.*;
+import aQute.lib.osgi.*;
+
+public class MakeCopy implements MakePlugin {
+
+ public Resource make(Builder builder, String destination,
+ Map<String, String> argumentsOnMake) throws Exception {
+ String type = argumentsOnMake.get("type");
+ if (!type.equals("copy"))
+ return null;
+
+ String from = argumentsOnMake.get("from");
+ if (from == null) {
+ String content = argumentsOnMake.get("content");
+ if (content == null)
+ throw new IllegalArgumentException(
+ "No 'from' or 'content' field in copy "
+ + argumentsOnMake);
+ return new EmbeddedResource(content.getBytes("UTF-8"),0);
+ } else {
+
+ File f = builder.getFile(from);
+ if (f.isFile())
+ return new FileResource(f);
+ else {
+ try {
+ URL url = new URL(from);
+ return new URLResource(url);
+ } catch(MalformedURLException mfue) {
+ // We ignore this
+ }
+ throw new IllegalArgumentException(
+ "Copy source does not exist " + from
+ + " for destination " + destination);
+ }
+ }
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/MakeCopy.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/ServiceComponent.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/ServiceComponent.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/ServiceComponent.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/ServiceComponent.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,408 @@
+package aQute.bnd.make;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.bnd.service.*;
+import aQute.lib.filter.*;
+import aQute.lib.osgi.*;
+import aQute.libg.version.*;
+
+/**
+ * This class is an analyzer plugin. It looks at the properties and tries to
+ * find out if the Service-Component header contains the bnd shortut syntax. If
+ * not, the header is copied to the output, if it does, an XML file is created
+ * and added to the JAR and the header is modified appropriately.
+ */
+public class ServiceComponent implements AnalyzerPlugin {
+ public final static String NAMESPACE_STEM = "http://www.osgi.org/xmlns/scr";
+ public final static String JIDENTIFIER = "<<identifier>>";
+ public final static String COMPONENT_FACTORY = "factory:";
+ public final static String COMPONENT_SERVICEFACTORY = "servicefactory:";
+ public final static String COMPONENT_IMMEDIATE = "immediate:";
+ public final static String COMPONENT_ENABLED = "enabled:";
+ public final static String COMPONENT_DYNAMIC = "dynamic:";
+ public final static String COMPONENT_MULTIPLE = "multiple:";
+ public final static String COMPONENT_PROVIDE = "provide:";
+ public final static String COMPONENT_OPTIONAL = "optional:";
+ public final static String COMPONENT_PROPERTIES = "properties:";
+ public final static String COMPONENT_IMPLEMENTATION = "implementation:";
+
+ // v1.1.0
+ public final static String COMPONENT_VERSION = "version:";
+ public final static String COMPONENT_CONFIGURATION_POLICY = "configuration-policy:";
+ public final static String COMPONENT_MODIFIED = "modified:";
+ public final static String COMPONENT_ACTIVATE = "activate:";
+ public final static String COMPONENT_DEACTIVATE = "deactivate:";
+
+ public final static String[] componentDirectives = new String[] {
+ COMPONENT_FACTORY, COMPONENT_IMMEDIATE, COMPONENT_ENABLED,
+ COMPONENT_DYNAMIC, COMPONENT_MULTIPLE, COMPONENT_PROVIDE,
+ COMPONENT_OPTIONAL, COMPONENT_PROPERTIES, COMPONENT_IMPLEMENTATION,
+ COMPONENT_SERVICEFACTORY, COMPONENT_VERSION,
+ COMPONENT_CONFIGURATION_POLICY, COMPONENT_MODIFIED,
+ COMPONENT_ACTIVATE, COMPONENT_DEACTIVATE };
+
+ public final static Set<String> SET_COMPONENT_DIRECTIVES = new HashSet<String>(
+ Arrays
+ .asList(componentDirectives));
+
+ public final static Set<String> SET_COMPONENT_DIRECTIVES_1_1 = //
+ new HashSet<String>(
+ Arrays
+ .asList(
+ COMPONENT_VERSION,
+ COMPONENT_CONFIGURATION_POLICY,
+ COMPONENT_MODIFIED,
+ COMPONENT_ACTIVATE,
+ COMPONENT_DEACTIVATE));
+
+ public boolean analyzeJar(Analyzer analyzer) throws Exception {
+
+ ComponentMaker m = new ComponentMaker(analyzer);
+
+ Map<String, Map<String, String>> l = m.doServiceComponent();
+
+ if (!l.isEmpty())
+ analyzer.setProperty(Constants.SERVICE_COMPONENT, Processor
+ .printClauses(l, ""));
+
+ analyzer.getInfo(m, "Service Component");
+ m.close();
+ return false;
+ }
+
+ private static class ComponentMaker extends Processor {
+ Analyzer analyzer;
+
+ ComponentMaker(Analyzer analyzer) {
+ super(analyzer);
+ this.analyzer = analyzer;
+ }
+
+ Map<String, Map<String, String>> doServiceComponent() throws Exception {
+ String header = getProperty(SERVICE_COMPONENT);
+ return doServiceComponent(header);
+ }
+
+ /**
+ * Check if a service component header is actually referring to a class.
+ * If so, replace the reference with an XML file reference. This makes
+ * it easier to create and use components.
+ *
+ * @throws UnsupportedEncodingException
+ *
+ */
+ public Map<String, Map<String, String>> doServiceComponent(
+ String serviceComponent) throws IOException {
+ Map<String, Map<String, String>> list = newMap();
+ Map<String, Map<String, String>> sc = parseHeader(serviceComponent);
+ Map<String, String> empty = Collections.emptyMap();
+
+ for (Iterator<Map.Entry<String, Map<String, String>>> i = sc
+ .entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String, Map<String, String>> entry = i.next();
+ String name = entry.getKey();
+ Map<String, String> info = entry.getValue();
+ if (name == null) {
+ error("No name in Service-Component header: " + info);
+ continue;
+ }
+ if (name.indexOf("*") >= 0 || analyzer.getJar().exists(name)) {
+ // Normal service component, we do not process them
+ list.put(name, info);
+ } else {
+ String impl = name;
+
+ if (info.containsKey(COMPONENT_IMPLEMENTATION))
+ impl = info.get(COMPONENT_IMPLEMENTATION);
+
+ if (!analyzer.checkClass(impl)) {
+ error("Not found Service-Component header: " + name);
+ } else {
+ // We have a definition, so make an XML resources
+ Resource resource = createComponentResource(name, info);
+ analyzer.getJar().putResource(
+ "OSGI-INF/" + name + ".xml", resource);
+ list.put("OSGI-INF/" + name + ".xml", empty);
+ }
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Create the resource for a DS component.
+ *
+ * @param list
+ * @param name
+ * @param info
+ * @throws UnsupportedEncodingException
+ */
+ Resource createComponentResource(String name, Map<String, String> info)
+ throws IOException {
+ String namespace = getNamespace(info);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ PrintWriter pw = new PrintWriter(new OutputStreamWriter(out,
+ "UTF-8"));
+ pw.println("<?xml version='1.0' encoding='utf-8'?>");
+ pw.print("<component name='" + name + "'");
+ if (namespace != null) {
+ pw.print(" xmlns='" + namespace + "'");
+ }
+
+ doAttribute(pw, info.get(COMPONENT_FACTORY), "factory");
+ doAttribute(pw, info.get(COMPONENT_IMMEDIATE), "immediate",
+ "false", "true");
+ doAttribute(pw, info.get(COMPONENT_ENABLED), "enabled", "true",
+ "false");
+ doAttribute(pw, info.get(COMPONENT_CONFIGURATION_POLICY),
+ "configuration-policy", "optional", "require", "ignore");
+ doAttribute(pw, info.get(COMPONENT_ACTIVATE), "activate",
+ JIDENTIFIER);
+ doAttribute(pw, info.get(COMPONENT_DEACTIVATE), "deactivate",
+ JIDENTIFIER);
+ doAttribute(pw, info.get(COMPONENT_MODIFIED), "modified",
+ JIDENTIFIER);
+
+ pw.println(">");
+
+ // Allow override of the implementation when people
+ // want to choose their own name
+ String impl = (String) info.get(COMPONENT_IMPLEMENTATION);
+ pw.println(" <implementation class='"
+ + (impl == null ? name : impl) + "'/>");
+
+ String provides = info.get(COMPONENT_PROVIDE);
+ boolean servicefactory = Boolean.getBoolean(info
+ .get(COMPONENT_SERVICEFACTORY)
+ + "");
+ provides(pw, provides, servicefactory);
+ properties(pw, info);
+ reference(info, pw);
+ pw.println("</component>");
+ pw.close();
+ byte[] data = out.toByteArray();
+ out.close();
+ return new EmbeddedResource(data, 0);
+ }
+
+ private void doAttribute(PrintWriter pw, String value, String name,
+ String... matches) {
+ if (value != null) {
+ if (matches.length != 0) {
+ if (matches.length == 1 && matches[0].equals(JIDENTIFIER)) {
+ if (!Verifier.isIdentifier(value))
+ error(
+ "Component attribute %s has value %s but is not a Java identifier",
+ name, value);
+ } else {
+
+ if (!Verifier.isMember(value, matches))
+ error(
+ "Component attribute %s has value %s but is not a member of %s",
+ name, value, Arrays.toString(matches));
+ }
+ }
+ pw.print(" ");
+ pw.print(name);
+ pw.print("='");
+ pw.print(value);
+ pw.print("'");
+ }
+ }
+
+ /**
+ * Check if we need to use the v1.1 namespace (or later).
+ *
+ * @param info
+ * @return
+ */
+ private String getNamespace(Map<String, String> info) {
+ String version = info.get(COMPONENT_VERSION);
+ if (version != null) {
+ try {
+ Version v = new Version(version);
+ return NAMESPACE_STEM + "/v" + v;
+ } catch (Exception e) {
+ error("version: specified on component header but not a valid version: "
+ + version);
+ return null;
+ }
+ }
+ for (String key : info.keySet()) {
+ if (SET_COMPONENT_DIRECTIVES_1_1.contains(key)) {
+ return NAMESPACE_STEM + "/v1.1.0";
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Print the Service-Component properties element
+ *
+ * @param pw
+ * @param info
+ */
+ void properties(PrintWriter pw, Map<String, String> info) {
+ Collection<String> properties = split(info
+ .get(COMPONENT_PROPERTIES));
+ for (Iterator<String> p = properties.iterator(); p.hasNext();) {
+ String clause = p.next();
+ int n = clause.indexOf('=');
+ if (n <= 0) {
+ error("Not a valid property in service component: "
+ + clause);
+ } else {
+ String type = null;
+ String name = clause.substring(0, n);
+ if (name.indexOf('@') >= 0) {
+ String parts[] = name.split("@");
+ name = parts[1];
+ type = parts[0];
+ }
+ String value = clause.substring(n + 1).trim();
+ // TODO verify validity of name and value.
+ pw.print("<property name='");
+ pw.print(name);
+ pw.print("'");
+
+ if (type != null) {
+ if (VALID_PROPERTY_TYPES.matcher(type).matches()) {
+ pw.print(" type='");
+ pw.print(type);
+ pw.print("'");
+ } else {
+ warning("Invalid property type '" + type
+ + "' for property " + name);
+ }
+ }
+
+ String parts[] = value.split("\\s*(\\||\\n)\\s*");
+ if (parts.length > 1) {
+ pw.println(">");
+ for (String part : parts) {
+ pw.println(part);
+ }
+ pw.println("</property>");
+ } else {
+ pw.print(" value='");
+ pw.print(parts[0]);
+ pw.print("'/>");
+ }
+ }
+ }
+ }
+
+ /**
+ * @param pw
+ * @param provides
+ */
+ void provides(PrintWriter pw, String provides, boolean servicefactory) {
+ if (provides != null) {
+ if (!servicefactory)
+ pw.println(" <service>");
+ else
+ pw.println(" <service servicefactory='true'>");
+
+ StringTokenizer st = new StringTokenizer(provides, ",");
+ while (st.hasMoreTokens()) {
+ String interfaceName = st.nextToken();
+ pw.println(" <provide interface='" + interfaceName
+ + "'/>");
+ if (!analyzer.checkClass(interfaceName))
+ error("Component definition provides a class that is neither imported nor contained: "
+ + interfaceName);
+ }
+ pw.println(" </service>");
+ }
+ }
+
+ public final static Pattern REFERENCE = Pattern.compile("([^(]+)(\\(.+\\))?");
+
+ /**
+ * @param info
+ * @param pw
+ */
+
+ void reference(Map<String, String> info, PrintWriter pw) {
+ Collection<String> dynamic = new ArrayList<String>(split(info.get(COMPONENT_DYNAMIC)));
+ Collection<String> optional = new ArrayList<String>(split(info.get(COMPONENT_OPTIONAL)));
+ Collection<String> multiple = new ArrayList<String>(split(info.get(COMPONENT_MULTIPLE)));
+
+ for (Iterator<Map.Entry<String, String>> r = info.entrySet()
+ .iterator(); r.hasNext();) {
+ Map.Entry<String, String> ref = r.next();
+ String referenceName = (String) ref.getKey();
+ String target = null;
+ String interfaceName = (String) ref.getValue();
+ if (interfaceName == null || interfaceName.length() == 0) {
+ error("Invalid Interface Name for references in Service Component: "
+ + referenceName + "=" + interfaceName);
+ }
+ char c = interfaceName.charAt(interfaceName.length() - 1);
+ if ("?+*~".indexOf(c) >= 0) {
+ if (c == '?' || c == '*' || c == '~')
+ optional.add(referenceName);
+ if (c == '+' || c == '*')
+ multiple.add(referenceName);
+ if (c == '+' || c == '*' || c == '?')
+ dynamic.add(referenceName);
+ interfaceName = interfaceName.substring(0, interfaceName
+ .length() - 1);
+ }
+
+ if (referenceName.endsWith(":")) {
+ if (!SET_COMPONENT_DIRECTIVES.contains(referenceName))
+ error("Unrecognized directive in Service-Component header: "
+ + referenceName);
+ continue;
+ }
+
+ Matcher m = REFERENCE.matcher(interfaceName);
+ if (m.matches()) {
+ interfaceName = m.group(1);
+ target = m.group(2);
+ }
+
+ if (!analyzer.checkClass(interfaceName))
+ error("Component definition refers to a class that is neither imported nor contained: "
+ + interfaceName);
+
+ pw.print(" <reference name='" + referenceName
+ + "' interface='" + interfaceName + "'");
+
+ String cardinality = optional.contains(referenceName) ? "0"
+ : "1";
+ cardinality += "..";
+ cardinality += multiple.contains(referenceName) ? "n" : "1";
+ if (!cardinality.equals("1..1"))
+ pw.print(" cardinality='" + cardinality + "'");
+
+ if (Character.isLowerCase(referenceName.charAt(0))) {
+ String z = referenceName.substring(0, 1).toUpperCase()
+ + referenceName.substring(1);
+ pw.print(" bind='set" + z + "'");
+ pw.print(" unbind='unset" + z + "'");
+ // TODO Verify that the methods exist
+ }
+
+ if (dynamic.contains(referenceName)) {
+ pw.print(" policy='dynamic'");
+ }
+
+ if (target != null) {
+ Filter filter = new Filter(target);
+ if (filter.verify() == null)
+ pw.print(" target='" + filter.toString() + "'");
+ else
+ error("Target for " + referenceName
+ + " is not a correct filter: " + target + " "
+ + filter.verify());
+ }
+ pw.println("/>");
+ }
+ }
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/ServiceComponent.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,20 @@
+package aQute.bnd.service;
+
+import aQute.lib.osgi.*;
+
+public interface AnalyzerPlugin {
+
+ /**
+ * This plugin is called after analysis. The plugin is free to modify the
+ * jar and/or change the classpath information (see referred, contained).
+ * This plugin is called after analysis of the JAR but before manifest
+ * generation.
+ *
+ * @param analyzer
+ * @return true if the classpace has been modified so that the bundle
+ * classpath must be reanalyzed
+ * @throws Exception
+ */
+
+ boolean analyzeJar(Analyzer analyzer) throws Exception;
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,21 @@
+package aQute.bnd.service;
+
+import java.util.*;
+
+import aQute.lib.osgi.*;
+
+public interface MakePlugin {
+
+ /**
+ * This plugin is called when Include-Resource detects a reference to a resource
+ * that it can not find in the file system.
+ *
+ * @param builder The current builder
+ * @param source The source string (i.e. the place where bnd looked)
+ * @param arguments Any arguments on the clause in Include-Resource
+ * @return A resource or null if no resource could be made
+ * @throws Exception
+ */
+ Resource make(Builder builder, String source, Map<String,String> arguments) throws Exception;
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,31 @@
+package aQute.bnd.service;
+
+import java.util.*;
+
+import aQute.libg.reporter.*;
+
+/**
+ * An optional interface for plugins. If a plugin implements this interface then
+ * it can receive the reminaing attributes and directives given in its clause as
+ * well as the reporter to use.
+ *
+ */
+public interface Plugin {
+ /**
+ * Give the plugin the remaining properties.
+ *
+ * When a plugin is declared, the clause can contain extra properties.
+ * All the properties and directives are given to the plugin to use.
+ *
+ * @param map attributes and directives for this plugin's clause
+ */
+ void setProperties(Map<String,String> map);
+
+ /**
+ * Set the current reporter. This is called at init time. This plugin
+ * should report all errors and warnings to this reporter.
+ *
+ * @param processor
+ */
+ void setReporter(Reporter processor);
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,8 @@
+package aQute.bnd.service;
+
+import java.io.*;
+
+public interface Refreshable {
+ boolean refresh();
+ File getRoot();
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,59 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.*;
+
+import aQute.lib.osgi.*;
+import aQute.libg.version.*;
+
+public interface RepositoryPlugin {
+ /**
+ * Return a URL to a matching version of the given bundle.
+ *
+ * @param bsn
+ * Bundle-SymbolicName of the searched bundle
+ * @param range
+ * Version range for this bundle,"latest" if you only want the
+ * latest, or null when you want all.
+ * @return A list of URLs sorted on version, lowest version is at index 0.
+ * null is returned when no files with the given bsn ould be found.
+ * @throws Exception
+ * when anything goes wrong
+ */
+ File[] get(String bsn, String range) throws Exception;
+
+ /**
+ * Answer if this repository can be used to store files.
+ *
+ * @return true if writable
+ */
+ boolean canWrite();
+
+ /**
+ * Put a JAR file in the repository.
+ *
+ * @param jar
+ * @throws Exception
+ */
+ File put(Jar jar) throws Exception;
+
+ /**
+ * Return a list of bsns that are present in the repository.
+ *
+ * @param regex if not null, match against the bsn and if matches, return otherwise skip
+ * @return A list of bsns that match the regex parameter or all if regex is null
+ */
+ List<String> list(String regex);
+
+ /**
+ * Return a list of versions.
+ */
+
+ List<Version> versions(String bsn);
+
+ /**
+ * @return The name of the repository
+ */
+ String getName();
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,15 @@
+package aQute.bnd.service;
+
+import aQute.lib.osgi.*;
+
+public interface SignerPlugin {
+ /**
+ * Sign the current jar. The alias is the given certificate
+ * keystore.
+ *
+ * @param builder The current builder that contains the jar to sign
+ * @param alias The keystore certificate alias
+ * @throws Exception When anything goes wrong
+ */
+ void sign(Builder builder, String alias) throws Exception;
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,25 @@
+package aQute.bnd.service.action;
+
+import aQute.bnd.build.*;
+
+public interface Action {
+ /**
+ * A String[] that specifies a menu entry. The entry
+ * can be hierarchical by separating the parts with a ':'.
+ *
+ * <pre>
+ * A:B:C
+ * A:B:D
+ *
+ * A
+ * |
+ * B
+ * / \
+ * C D
+ *
+ * </pre>
+ */
+ String ACTION_MENU = "bnd.action.menu";
+
+ void execute( Project project, String action) throws Exception;
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/ProjectLauncher.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/ProjectLauncher.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/ProjectLauncher.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/ProjectLauncher.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,336 @@
+package aQute.bnd.test;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.bnd.build.*;
+import aQute.lib.osgi.*;
+import aQute.libg.header.*;
+
+public class ProjectLauncher extends Processor {
+ final Project project;
+ static File runtime;
+ String report;
+
+ public ProjectLauncher(Project project) {
+ super(project);
+ this.project = project;
+ }
+
+ /**
+ * Calculate the classpath. We include our own runtime.jar which includes
+ * the test framework and we include the first of the test frameworks
+ * specified.
+ */
+ public String[] getClasspath() {
+ try {
+ List<String> classpath = new ArrayList<String>();
+ classpath.add(getRuntime().getAbsolutePath());
+
+ for (Container c : project.getRunpath()) {
+ if (c.getType() != Container.TYPE.ERROR) {
+ if (!c.getFile().getName().startsWith("ee."))
+ classpath.add(c.getFile().getAbsolutePath());
+ } else {
+ error("Invalid entry on the " + Constants.RUNPATH + ": "
+ + c);
+ }
+ }
+ return classpath.toArray(new String[classpath.size()]);
+ } catch (Exception e) {
+ error("Calculating class path", e);
+ }
+ return null;
+ }
+
+ /**
+ * Extract the runtime on the file system so we can refer to it. in the
+ * remote VM.
+ *
+ * @return
+ */
+ public static File getRuntime() {
+ if (runtime == null) {
+ try {
+ URL url = ProjectLauncher.class
+ .getResource("aQute.runtime.jar");
+ if (url == null)
+ throw new IllegalStateException(
+ "Can not find my runtime.jar");
+
+ runtime = File.createTempFile("aQute.runtime", ".jar");
+ // runtime.deleteOnExit();
+ FileOutputStream out = new FileOutputStream(runtime);
+ InputStream in = url.openStream();
+ copy(in, out);
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return runtime;
+ }
+
+ public void doRunbundles(List<String> programArguments) throws Exception {
+ // we are going to use this for running, so we want to
+ // use the "best" version. For compile, we should
+ // use the lowest version.
+ Collection<Container> testbundles = project.getRunbundles();
+
+ for (Container c : testbundles) {
+ if (c.getError() != null)
+ error("Invalid bundle on " + Constants.RUNBUNDLES + " "
+ + c.getError());
+ else {
+ // Do we need to build any sub projects?
+ if (c.getVersion() != null && c.getVersion().equals("project")) {
+ Project sub = c.getProject();
+ sub.clear();
+ File[] outputs = sub.build(false);
+ for (File f : outputs) {
+ programArguments.add("-bundle");
+ programArguments.add(f.getAbsolutePath());
+ }
+ getInfo(sub);
+ } else {
+ programArguments.add("-bundle");
+ programArguments.add(c.getFile().getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ private void doRunpath(List<String> programArguments) throws Exception {
+ Collection<Container> testpath = project.getRunpath();
+ Container found = null;
+ for (Container c : testpath) {
+ if (c.getAttributes().containsKey("framework")) {
+ if (found != null) {
+ warning("Specifying multiple framework classes on the "
+ + Constants.RUNPATH + "\n" + "Previous found: "
+ + found.getProject() + " " + found.getAttributes()
+ + "\n" + "Now found : " + c.getProject() + " "
+ + c.getAttributes());
+ }
+ programArguments.add("-framework");
+ programArguments.add(c.getAttributes().get("framework"));
+ found = c;
+ }
+ if (c.getAttributes().containsKey("factory")) {
+ if (found != null) {
+ warning("Specifying multiple framework factories on the "
+ + Constants.RUNPATH + "\n" + "Previous found: "
+ + found.getProject() + " " + found.getAttributes()
+ + "\n" + "Now found : " + c.getProject() + " "
+ + c.getAttributes());
+ }
+ programArguments.add("-framework");
+ programArguments.add(c.getAttributes().get("factory"));
+ found = c;
+ }
+ String exports = c.getAttributes().get("export");
+ if (exports != null) {
+ String parts[] = exports.split("\\s*,\\s*");
+ for (String p : parts) {
+ programArguments.add("-export");
+ programArguments.add(p);
+ }
+ }
+ }
+
+ doSystemPackages(programArguments);
+ doRunProperties(programArguments);
+ }
+
+ private void doRunProperties(List<String> programArguments) {
+ Map<String, String> properties = OSGiHeader
+ .parseProperties(getProperty(RUNPROPERTIES));
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+ programArguments.add("-set");
+ programArguments.add(entry.getKey());
+ programArguments.add(entry.getValue());
+ }
+ }
+
+ private void doSystemPackages(List<String> programArguments) {
+ Map<String, Map<String, String>> systemPackages = parseHeader(getProperty(RUNSYSTEMPACKAGES));
+ for (Map.Entry<String, Map<String, String>> entry : systemPackages
+ .entrySet()) {
+ programArguments.add("-export");
+ StringBuffer sb = new StringBuffer();
+ sb.append(entry.getKey());
+ printClause(entry.getValue(), null, sb);
+ programArguments.add(sb.toString());
+ }
+ }
+
+ private void doStorage(List<String> programArguments) throws Exception {
+ File tmp = new File(project.getTarget(), "fwtmp");
+ tmp.mkdirs();
+ tmp.deleteOnExit();
+
+ programArguments.add("-storage");
+ programArguments.add(tmp.getAbsolutePath());
+ }
+
+ /**
+ * Utility to copy a file from a resource.
+ *
+ * @param in
+ * @param out
+ * @throws IOException
+ */
+ private static void copy(InputStream in, FileOutputStream out)
+ throws IOException {
+ byte buf[] = new byte[8192];
+ int size = in.read(buf);
+ while (size > 0) {
+ out.write(buf, 0, size);
+ size = in.read(buf);
+ }
+ in.close();
+ }
+
+ private Process launch(File[] targets) throws Exception {
+ List<String> arguments = newList();
+ List<String> vmArguments = newList();
+
+ vmArguments.add(getProperty("java", "java"));
+ doClasspath(vmArguments);
+
+ getArguments(targets, vmArguments, arguments);
+
+ vmArguments.add("aQute.junit.runtime.Target");
+ arguments.add("-report");
+ arguments.add(getTestreport());
+
+ List<String> all = newList();
+ all.addAll(vmArguments);
+ all.addAll(arguments);
+
+ System.out.println("Cmd: " + all);
+
+ String[] cmdarray = all.toArray(new String[all.size()]);
+ if (getErrors().size() > 0)
+ return null;
+
+ return Runtime.getRuntime().exec(cmdarray, null, project.getBase());
+ }
+/*
+ static Pattern ARGUMENT = Pattern.compile("[-a-zA-Z0-9\\._]+");
+ private void doVMArguments(List<String> arguments) {
+ Map<String,String> map = OSGiHeader.parseProperties( getProperty(RUNVM));
+ for ( String key : map.keySet() ) {
+ if ( ARGUMENT.matcher(key).matches())
+ if ( key.startsWith("-"))
+ arguments.add(key);
+ else
+ arguments.add("-D" + key.trim() + "=" + map.get(key));
+ else
+ warning("VM Argument is not a proper property key: " + key );
+ }
+ }
+*/
+ private void doVMArguments(List<String> arguments) {
+ Map<String, String> map = OSGiHeader
+ .parseProperties(getProperty(RUNVM));
+ for (String key : map.keySet()) {
+ if (key.startsWith("-"))
+ arguments.add(key);
+ else
+ arguments.add("-D" + key.trim() + "=" + map.get(key));
+ }
+ }
+ private void doClasspath(List<String> arguments) {
+ Collection<String> cp = Arrays.asList(getClasspath());
+ if (!cp.isEmpty()) {
+ arguments.add("-classpath");
+ arguments.add(join(cp, File.pathSeparator));
+ }
+ }
+
+ public int run(File f) throws Exception {
+ final Process process = launch(new File[] { f });
+
+ Thread killer = new Thread() {
+ public void run() {
+ process.destroy();
+ }
+ };
+ Runtime.getRuntime().addShutdownHook(killer);
+ Streamer sin = new Streamer(process.getInputStream(), System.out);
+ Streamer serr = new Streamer(process.getErrorStream(), System.out);
+ try {
+ sin.start();
+ serr.start();
+ return process.waitFor();
+ } finally {
+ Runtime.getRuntime().removeShutdownHook(killer);
+ sin.join();
+ serr.join();
+ }
+ }
+
+ static class Streamer extends Thread {
+ final InputStream in;
+ final OutputStream out;
+
+ Streamer(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ int c;
+ while ((c = in.read()) > 0) {
+ this.out.write(c);
+ }
+ } catch (IOException ioe) {
+ // Ignore
+ }
+ };
+
+ };
+
+ public String getTestreport() {
+ if (report != null)
+ return report;
+ return report = getProperty(Constants.TESTREPORT,
+ "${target}/test-report.xml");
+
+ }
+
+ public void getArguments(List<String> vmArguments,
+ List<String> programArguments, boolean undertest) throws Exception {
+ File files[] = project.build(undertest);
+ getInfo(project);
+ if (files == null)
+ return;
+
+ getArguments(files, vmArguments, programArguments);
+ }
+
+ public void getArguments(File files[], List<String> vmArguments,
+ List<String> programArguments) throws Exception {
+ doVMArguments(vmArguments);
+ doStorage(programArguments);
+ doRunpath(programArguments);
+ doRunbundles(programArguments);
+ for (File file : files) {
+ programArguments.add("-target");
+ programArguments.add(file.getAbsolutePath());
+ }
+ }
+
+ public String getReport() {
+ return report;
+ }
+
+ public void setReport(String report) {
+ this.report = report;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/test/ProjectLauncher.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,353 @@
+/**
+ * Copyright (c) 2000 Gatespace AB. All Rights Reserved.
+ *
+ * Gatespace grants Open Services Gateway Initiative (OSGi) an irrevocable,
+ * perpetual, non-exclusive, worldwide, paid-up right and license to
+ * reproduce, display, perform, prepare and have prepared derivative works
+ * based upon and distribute and sublicense this material and derivative
+ * works thereof as set out in the OSGi MEMBER AGREEMENT as of January 24
+ * 2000, for use in accordance with Section 2.2 of the BY-LAWS of the
+ * OSGi MEMBER AGREEMENT.
+ */
+
+package aQute.lib.filter;
+
+import java.lang.reflect.*;
+import java.math.*;
+import java.util.*;
+
+public class Filter {
+ final char WILDCARD = 65535;
+
+ final int EQ = 0;
+ final int LE = 1;
+ final int GE = 2;
+ final int APPROX = 3;
+
+ private String filter;
+
+ abstract class Query {
+ static final String GARBAGE = "Trailing garbage";
+ static final String MALFORMED = "Malformed query";
+ static final String EMPTY = "Empty list";
+ static final String SUBEXPR = "No subexpression";
+ static final String OPERATOR = "Undefined operator";
+ static final String TRUNCATED = "Truncated expression";
+ static final String EQUALITY = "Only equality supported";
+
+ private String tail;
+
+ boolean match() throws IllegalArgumentException {
+ tail = filter;
+ boolean val = doQuery();
+ if (tail.length() > 0)
+ error(GARBAGE);
+ return val;
+ }
+
+ private boolean doQuery() throws IllegalArgumentException {
+ if (tail.length() < 3 || !prefix("("))
+ error(MALFORMED);
+ boolean val;
+
+ switch (tail.charAt(0)) {
+ case '&':
+ val = doAnd();
+ break;
+ case '|':
+ val = doOr();
+ break;
+ case '!':
+ val = doNot();
+ break;
+ default:
+ val = doSimple();
+ break;
+ }
+
+ if (!prefix(")"))
+ error(MALFORMED);
+ return val;
+ }
+
+ private boolean doAnd() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ boolean val = true;
+ if (!tail.startsWith("("))
+ error(EMPTY);
+ do {
+ if (!doQuery())
+ val = false;
+ } while (tail.startsWith("("));
+ return val;
+ }
+
+ private boolean doOr() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ boolean val = false;
+ if (!tail.startsWith("("))
+ error(EMPTY);
+ do {
+ if (doQuery())
+ val = true;
+ } while (tail.startsWith("("));
+ return val;
+ }
+
+ private boolean doNot() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ if (!tail.startsWith("("))
+ error(SUBEXPR);
+ return !doQuery();
+ }
+
+ private boolean doSimple() throws IllegalArgumentException {
+ int op = 0;
+ Object attr = getAttr();
+
+ if (prefix("="))
+ op = EQ;
+ else if (prefix("<="))
+ op = LE;
+ else if (prefix(">="))
+ op = GE;
+ else if (prefix("~="))
+ op = APPROX;
+ else
+ error(OPERATOR);
+
+ return compare(attr, op, getValue());
+ }
+
+ private boolean prefix(String pre) {
+ if (!tail.startsWith(pre))
+ return false;
+ tail = tail.substring(pre.length());
+ return true;
+ }
+
+ private Object getAttr() {
+ int len = tail.length();
+ int ix = 0;
+ label: for (; ix < len; ix++) {
+ switch (tail.charAt(ix)) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '=':
+ case '~':
+ case '*':
+ case '\\':
+ break label;
+ }
+ }
+ String attr = tail.substring(0, ix).toLowerCase();
+ tail = tail.substring(ix);
+ return getProp(attr);
+ }
+
+ abstract Object getProp(String key);
+
+ private String getValue() {
+ StringBuffer sb = new StringBuffer();
+ int len = tail.length();
+ int ix = 0;
+ label: for (; ix < len; ix++) {
+ char c = tail.charAt(ix);
+ switch (c) {
+ case '(':
+ case ')':
+ break label;
+ case '*':
+ sb.append(WILDCARD);
+ break;
+ case '\\':
+ if (ix == len - 1)
+ break label;
+ sb.append(tail.charAt(++ix));
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ tail = tail.substring(ix);
+ return sb.toString();
+ }
+
+ private void error(String m) throws IllegalArgumentException {
+ throw new IllegalArgumentException(m + " " + tail);
+ }
+
+ private boolean compare(Object obj, int op, String s) {
+ if (obj == null)
+ return false;
+ try {
+ Class<?> numClass = obj.getClass();
+ if (numClass == String.class) {
+ return compareString((String) obj, op, s);
+ } else if (numClass == Character.class) {
+ return compareString(obj.toString(), op, s);
+ } else if (numClass == Long.class) {
+ return compareSign(op, Long.valueOf(s)
+ .compareTo((Long) obj));
+ } else if (numClass == Integer.class) {
+ return compareSign(op, Integer.valueOf(s).compareTo(
+ (Integer) obj));
+ } else if (numClass == Short.class) {
+ return compareSign(op, Short.valueOf(s).compareTo(
+ (Short) obj));
+ } else if (numClass == Byte.class) {
+ return compareSign(op, Byte.valueOf(s)
+ .compareTo((Byte) obj));
+ } else if (numClass == Double.class) {
+ return compareSign(op, Double.valueOf(s).compareTo(
+ (Double) obj));
+ } else if (numClass == Float.class) {
+ return compareSign(op, Float.valueOf(s).compareTo(
+ (Float) obj));
+ } else if (numClass == Boolean.class) {
+ if (op != EQ)
+ return false;
+ int a = Boolean.valueOf(s).booleanValue() ? 1 : 0;
+ int b = ((Boolean) obj).booleanValue() ? 1 : 0;
+ return compareSign(op, a - b);
+ } else if (numClass == BigInteger.class) {
+ return compareSign(op, new BigInteger(s)
+ .compareTo((BigInteger) obj));
+ } else if (numClass == BigDecimal.class) {
+ return compareSign(op, new BigDecimal(s)
+ .compareTo((BigDecimal) obj));
+ } else if (obj instanceof Collection) {
+ for (Object x : (Collection<?>) obj)
+ if (compare(x, op, s))
+ return true;
+ } else if (numClass.isArray()) {
+ int len = Array.getLength(obj);
+ for (int i = 0; i < len; i++)
+ if (compare(Array.get(obj, i), op, s))
+ return true;
+ }
+ } catch (Exception e) {
+ }
+ return false;
+ }
+ }
+
+ class DictQuery extends Query {
+ private Dictionary<?,?> dict;
+
+ DictQuery(Dictionary<?,?> dict) {
+ this.dict = dict;
+ }
+
+ Object getProp(String key) {
+ return dict.get(key);
+ }
+ }
+
+ public Filter(String filter) throws IllegalArgumentException {
+ // NYI: Normalize the filter string?
+ this.filter = filter;
+ if (filter == null || filter.length() == 0)
+ throw new IllegalArgumentException("Null query");
+ }
+
+ public boolean match(Dictionary<?,?> dict) {
+ try {
+ return new DictQuery(dict).match();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ public String verify() {
+ try {
+ new DictQuery(new Hashtable<Object,Object>()).match();
+ } catch (IllegalArgumentException e) {
+ return e.getMessage();
+ }
+ return null;
+ }
+
+ public String toString() {
+ return filter;
+ }
+
+ public boolean equals(Object obj) {
+ return obj != null && obj instanceof Filter
+ && filter.equals(((Filter) obj).filter);
+ }
+
+ public int hashCode() {
+ return filter.hashCode();
+ }
+
+ boolean compareString(String s1, int op, String s2) {
+ switch (op) {
+ case EQ:
+ return patSubstr(s1, s2);
+ case APPROX:
+ return fixupString(s2).equals(fixupString(s1));
+ default:
+ return compareSign(op, s2.compareTo(s1));
+ }
+ }
+
+ boolean compareSign(int op, int cmp) {
+ switch (op) {
+ case LE:
+ return cmp >= 0;
+ case GE:
+ return cmp <= 0;
+ case EQ:
+ return cmp == 0;
+ default: /* APPROX */
+ return cmp == 0;
+ }
+ }
+
+ String fixupString(String s) {
+ StringBuffer sb = new StringBuffer();
+ int len = s.length();
+ boolean isStart = true;
+ boolean isWhite = false;
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (Character.isWhitespace(c)) {
+ isWhite = true;
+ } else {
+ if (!isStart && isWhite)
+ sb.append(' ');
+ if (Character.isUpperCase(c))
+ c = Character.toLowerCase(c);
+ sb.append(c);
+ isStart = false;
+ isWhite = false;
+ }
+ }
+ return sb.toString();
+ }
+
+ boolean patSubstr(String s, String pat) {
+ if (s == null)
+ return false;
+ if (pat.length() == 0)
+ return s.length() == 0;
+ if (pat.charAt(0) == WILDCARD) {
+ pat = pat.substring(1);
+ for (;;) {
+ if (patSubstr(s, pat))
+ return true;
+ if (s.length() == 0)
+ return false;
+ s = s.substring(1);
+ }
+ } else {
+ if (s.length() == 0 || s.charAt(0) != pat.charAt(0))
+ return false;
+ return patSubstr(s.substring(1), pat.substring(1));
+ }
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/filter/Filter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,48 @@
+/* Copyright 2006 aQute SARL
+ * Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 */
+package aQute.lib.osgi;
+
+/**
+ * This package contains a number of classes that assists by analyzing JARs and
+ * constructing bundles.
+ *
+ * The Analyzer class can be used to analyze an existing bundle and can create a
+ * manifest specification from proposed (wildcard) Export-Package,
+ * Bundle-Includes, and Import-Package headers.
+ *
+ * The Builder class can use the headers to construct a JAR from the classpath.
+ *
+ * The Verifier class can take an existing JAR and verify that all headers are
+ * correctly set. It will verify the syntax of the headers, match it against the
+ * proper contents, and verify imports and exports.
+ *
+ * A number of utility classes are available.
+ *
+ * Jar, provides an abstraction of a Jar file. It has constructors for creating
+ * a Jar from a stream, a directory, or a jar file. A Jar, keeps a collection
+ * Resource's. There are Resource implementations for File, from ZipFile, or from
+ * a stream (which copies the data). The Jar tries to minimize the work during
+ * build up so that it is cheap to use. The Resource's can be used to iterate
+ * over the names and later read the resources when needed.
+ *
+ * Clazz, provides a parser for the class files. This will be used to define the
+ * imports and exports.
+ *
+ * A key component in this library is the Map. Headers are translated to Maps of Maps. OSGi
+ * header syntax is like:
+ * <pre>
+ * header = clause ( ',' clause ) *
+ * clause = file ( ';' file ) * ( parameter ) *
+ * param = attr '=' value | directive ':=' value
+ * </pre>
+ * These headers are translated to a Map that contains all headers (the order is
+ * maintained). Each additional file in a header definition will have its own
+ * entry (only native code does not work this way). The clause is represented
+ * as another map. The ':' of directives is considered part of the name. This
+ * allows attributes and directives to be maintained in the clause map.
+ *
+ * @version $Revision: 1.1 $
+ */
+public class About {
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/About.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,50 @@
+package aQute.lib.osgi;
+
+import java.io.*;
+
+public abstract class AbstractResource implements Resource {
+ String extra;
+ byte[] calculated;
+ long lastModified;
+
+ protected AbstractResource(long modified) {
+ lastModified = modified;
+ }
+
+ public String getExtra() {
+ return extra;
+ }
+
+ public long lastModified() {
+ return lastModified;
+ }
+
+ public InputStream openInputStream() throws IOException {
+ return new ByteArrayInputStream(getLocalBytes());
+ }
+
+ private byte[] getLocalBytes() throws IOException {
+ try {
+ if (calculated != null)
+ return calculated;
+
+ return calculated = getBytes();
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ IOException ee = new IOException("Opening resource");
+ ee.initCause(e);
+ throw ee;
+ }
+ }
+
+ public void setExtra(String extra) {
+ this.extra = extra;
+ }
+
+ public void write(OutputStream out) throws IOException {
+ out.write(getLocalBytes());
+ }
+
+ abstract protected byte[] getBytes() throws Exception;
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/AbstractResource.java
------------------------------------------------------------------------------
svn:eol-style = native