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 2011/10/17 12:31:51 UTC

svn commit: r1185095 [6/15] - in /felix/trunk/bundleplugin: ./ src/main/java/aQute/ src/main/java/aQute/bnd/ src/main/java/aQute/bnd/annotation/ src/main/java/aQute/bnd/annotation/component/ src/main/java/aQute/bnd/annotation/metatype/ src/main/java/aQ...

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenEntry.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenEntry.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenEntry.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenEntry.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,338 @@
+package aQute.bnd.maven.support;
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import aQute.lib.hex.*;
+import aQute.lib.io.*;
+import aQute.libg.filelock.*;
+
+/**
+ * An entry (a group/artifact) in the maven cache in the .m2/repository
+ * directory. It provides methods to get the pom and the artifact.
+ * 
+ */
+public class MavenEntry implements Closeable {
+	final Maven					maven;
+	final File					root;
+	final File					dir;
+	final String				path;
+	final DirectoryLock			lock;
+	final Map<URI, CachedPom>	poms	= new HashMap<URI, CachedPom>();
+	final File					pomFile;
+	final File					artifactFile;
+	final String				pomPath;
+	final File					propertiesFile;
+	Properties					properties;
+	private boolean				propertiesChanged;
+	FutureTask<File>			artifact;
+	private String				artifactPath;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param maven
+	 * @param path
+	 */
+	MavenEntry(Maven maven, String path) {
+		this.root = maven.repository;
+		this.maven = maven;
+		this.path = path;
+		this.pomPath = path + ".pom";
+		this.artifactPath = path + ".jar";
+		this.dir = IO.getFile(maven.repository, path).getParentFile();
+		this.dir.mkdirs();
+		this.pomFile = new File(maven.repository, pomPath);
+		this.artifactFile = new File(maven.repository, artifactPath);
+		this.propertiesFile = new File(dir, "bnd.properties");
+		this.lock = new DirectoryLock(dir, 5 * 60000); // 5 mins
+	}
+
+	/**
+	 * This is the method to get the POM for a cached entry.
+	 * 
+	 * @param urls
+	 *            The allowed URLs
+	 * @return a CachedPom for this maven entry
+	 * 
+	 * @throws Exception
+	 *             If something goes haywire
+	 */
+	public CachedPom getPom(URI[] urls) throws Exception {
+
+		// First check if we have the pom cached in memory
+		synchronized (this) {
+			// Try to find it in the in-memory cache
+			for (URI url : urls) {
+				CachedPom pom = poms.get(url);
+				if (pom != null)
+					return pom;
+			}
+		}
+
+		// Ok, we need to see if it exists on disk
+
+		// lock.lock();
+		try {
+
+			if (isValid()) {
+				// Check if one of our repos had the correct file.
+				for (URI url : urls) {
+					String valid = getProperty(url.toASCIIString());
+					if (valid != null)
+						return createPom(url);
+				}
+
+				// we have the info, but have to verify that it
+				// exists in one of our repos but we do not have
+				// to download it as our cache is already ok.
+				for (URI url : urls) {
+					if (verify(url, pomPath)) {
+						return createPom(url);
+					}
+				}
+
+				// It does not exist in out repo
+				// so we have to fail even though we do have
+				// the file.
+
+			} else {
+				dir.mkdirs();
+				// We really do not have the file
+				// so we have to find out who has it.
+				for (final URI url : urls) {
+
+					if (download(url, pomPath)) {
+						if (verify(url, pomPath)) {
+							artifact = new FutureTask<File>(new Callable<File>() {
+
+								public File call() throws Exception {
+									if (download(url, artifactPath)) {
+										verify(url, artifactPath);
+									}
+									return artifactFile;
+								}
+
+							});
+							maven.executor.execute(artifact);
+							return createPom(url);
+						}
+					}
+				}
+			}
+			return null;
+		} finally {
+			saveProperties();
+			// lock.release();
+		}
+	}
+
+	/**
+	 * Download a resource from the given repo.
+	 * 
+	 * @param url
+	 *            The base url for the repo
+	 * @param path
+	 *            The path part
+	 * @return
+	 * @throws MalformedURLException
+	 */
+	private boolean download(URI repo, String path) throws MalformedURLException {
+		try {
+			URL url = toURL(repo, path);
+			System.out.println("Downloading "  + repo + " path " + path + " url " + url);
+			File file = new File(root, path);
+			IO.copy(url.openStream(), file);
+			System.out.println("Downloaded "  + url);
+			return true;
+		} catch (Exception e) {
+			System.err.println("debug: " + e);
+			return false;
+		}
+	}
+
+	/**
+	 * Converts a repo + path to a URL..
+	 * 
+	 * @param base
+	 *            The base repo
+	 * @param path
+	 *            The path in the directory + url
+	 * @return a URL that points to the file in the repo
+	 * 
+	 * @throws MalformedURLException
+	 */
+	URL toURL(URI base, String path) throws MalformedURLException {
+		StringBuilder r = new StringBuilder();
+		r.append(base.toString());
+		if (r.charAt(r.length() - 1) != '/')
+			r.append('/');
+		r.append(path);
+		return new URL(r.toString());
+	}
+
+	/**
+	 * Check if this is a valid cache directory, might probably need some more
+	 * stuff.
+	 * 
+	 * @return true if valid
+	 */
+	private boolean isValid() {
+		return pomFile.isFile() && pomFile.length() > 100 && artifactFile.isFile()
+				&& artifactFile.length() > 100;
+	}
+
+	/**
+	 * We maintain a set of bnd properties in the cache directory.
+	 * 
+	 * @param key
+	 *            The key for the property
+	 * @param value
+	 *            The value for the property
+	 */
+	private void setProperty(String key, String value) {
+		Properties properties = getProperties();
+		properties.setProperty(key, value);
+		propertiesChanged = true;
+	}
+
+	/**
+	 * Answer the properties, loading if needed.
+	 */
+	protected Properties getProperties() {
+		if (properties == null) {
+			properties = new Properties();
+			File props = new File(dir, "bnd.properties");
+			if (props.exists()) {
+				try {
+					FileInputStream in = new FileInputStream(props);
+					properties.load(in);
+				} catch (Exception e) {
+					// we ignore for now, will handle it on safe
+				}
+			}
+		}
+		return properties;
+	}
+
+	/**
+	 * Answer a property.
+	 * 
+	 * @param key
+	 *            The key
+	 * @return The value
+	 */
+	private String getProperty(String key) {
+		Properties properties = getProperties();
+		return properties.getProperty(key);
+	}
+
+	private void saveProperties() throws IOException {
+		if (propertiesChanged) {
+			FileOutputStream fout = new FileOutputStream(propertiesFile);
+			try {
+				properties.store(fout, "");
+			} finally {
+				properties = null;
+				propertiesChanged = false;
+				fout.close();
+			}
+		}
+	}
+
+	/**
+	 * Help function to create the POM and record its source.
+	 * 
+	 * @param url
+	 *            the repo from which it was constructed
+	 * @return the new pom
+	 * @throws Exception
+	 */
+	private CachedPom createPom(URI url) throws Exception {
+		CachedPom pom = new CachedPom(this, url);
+		pom.parse();
+		poms.put(url, pom);
+		setProperty(url.toASCIIString(), "true");
+		return pom;
+	}
+
+	/**
+	 * Verify that the repo has a checksum file for the given path and that this
+	 * checksum matchs.
+	 * 
+	 * @param repo
+	 *            The repo
+	 * @param path
+	 *            The file id
+	 * @return true if there is a digest and it matches one of the algorithms
+	 * @throws Exception
+	 */
+	boolean verify(URI repo, String path) throws Exception {
+		for (String algorithm : Maven.ALGORITHMS) {
+			if (verify(repo, path, algorithm))
+				return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Verify the path against its digest for the given algorithm.
+	 * 
+	 * @param repo
+	 * @param path
+	 * @param algorithm
+	 * @return
+	 * @throws Exception
+	 */
+	private boolean verify(URI repo, String path, String algorithm) throws Exception {
+		String digestPath = path + "." + algorithm;
+		File actualFile = new File(root, path);
+
+		if (download(repo, digestPath)) {
+			File digestFile = new File(root, digestPath);
+			final MessageDigest md = MessageDigest.getInstance(algorithm);
+			IO.copy(actualFile, new OutputStream() {
+				@Override public void write(int c) throws IOException {
+					md.update((byte) c);
+				}
+
+				@Override public void write(byte[] buffer, int offset, int length) {
+					md.update(buffer, offset, length);
+				}
+			});
+			byte[] digest = md.digest();
+			String source = IO.collect(digestFile).toUpperCase();
+			String hex = Hex.toHexString(digest).toUpperCase();
+			if (source.startsWith(hex)) {
+				System.out.println("Verified ok " + actualFile + " digest " + algorithm);
+				return true;
+			}
+		}
+		System.out.println("Failed to verify " + actualFile + " for digest " + algorithm);
+		return false;
+	}
+
+	public File getArtifact() throws Exception {
+		if (artifact == null )
+			return artifactFile;
+		return artifact.get();
+	}
+
+	public File getPomFile() {
+		return pomFile;
+	}
+
+	public void close() throws IOException {
+
+	}
+
+	public void remove() {
+		if (dir.getParentFile() != null) {
+			IO.delete(dir);
+		}
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenEntry.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenRemoteRepository.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenRemoteRepository.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenRemoteRepository.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenRemoteRepository.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,130 @@
+package aQute.bnd.maven.support;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import aQute.bnd.service.*;
+import aQute.lib.io.*;
+import aQute.lib.osgi.*;
+import aQute.libg.reporter.*;
+import aQute.libg.version.*;
+
+public class MavenRemoteRepository implements RepositoryPlugin, RegistryPlugin, Plugin {
+	Reporter	reporter;
+	URI[]		repositories;
+	Registry	registry;
+	Maven		maven;
+
+	public File[] get(String bsn, String range) throws Exception {
+		File f = get(bsn, range, Strategy.HIGHEST, null);
+		if (f == null)
+			return null;
+
+		return new File[] { f };
+	}
+
+	public File get(String bsn, String version, Strategy strategy, Map<String, String> properties)
+			throws Exception {
+		String groupId = null;
+		
+		if (properties != null)
+			groupId = properties.get("groupId");
+		
+		if (groupId == null) {
+			int n = bsn.indexOf('+');
+			if ( n < 0)
+				return null;
+			
+			groupId = bsn.substring(0,n);
+			bsn = bsn.substring(n+1);
+		}
+
+		String artifactId = bsn;
+
+		if (version == null) {
+			if (reporter != null)
+				reporter.error("Maven dependency version not set for %s - %s", groupId, artifactId);
+			return null;
+		}
+
+		CachedPom pom = getMaven().getPom(groupId, artifactId, version, repositories);
+
+		String value = properties == null ? null : properties.get("scope");
+		if (value == null)
+			return pom.getArtifact();
+
+		Pom.Scope action = null;
+
+		try {
+			action = Pom.Scope.valueOf(value);
+			return pom.getLibrary(action, repositories);
+		} catch (Exception e) {
+			return pom.getArtifact();
+		}
+	}
+
+	public Maven getMaven() {
+		if ( maven != null)
+			return maven;
+		
+		maven = registry.getPlugin(Maven.class);
+		return maven;
+	}
+
+	public boolean canWrite() {
+		return false;
+	}
+
+	public File put(Jar jar) throws Exception {
+		throw new UnsupportedOperationException("cannot do put");
+	}
+
+	public List<String> list(String regex) throws Exception {
+		throw new UnsupportedOperationException("cannot do list");
+	}
+
+	public List<Version> versions(String bsn) throws Exception {
+		throw new UnsupportedOperationException("cannot do versions");
+	}
+
+	public String getName() {
+		return "maven";
+	}
+
+	public void setRepositories(URI... urls) {
+		repositories = urls;
+	}
+
+	public void setProperties(Map<String, String> map) {
+		String repoString = map.get("repositories");
+		if (repoString != null) {
+			String[] repos = repoString.split("\\s*,\\s*");
+			repositories = new URI[repos.length];
+			int n = 0;
+			for (String repo : repos) {
+				try {
+					URI uri = new URI(repo);
+					if ( !uri.isAbsolute())
+						uri = IO.getFile( new File(""),repo).toURI();
+					repositories[n++] = uri;
+				} catch (Exception e) {
+					if (reporter != null)
+						reporter.error("Invalid repository %s for maven plugin, %s", repo, e);
+				}
+			}
+		}
+	}
+
+	public void setReporter(Reporter reporter) {
+		this.reporter = reporter;
+	}
+
+	public void setRegistry(Registry registry) {
+		this.registry = registry;
+	}
+
+	public void setMaven(Maven maven) {
+		this.maven = maven;
+	}
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenRemoteRepository.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/MavenRemoteRepository.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Pom.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Pom.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Pom.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Pom.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,350 @@
+package aQute.bnd.maven.support;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import javax.xml.parsers.*;
+import javax.xml.xpath.*;
+
+import org.w3c.dom.*;
+
+public abstract class Pom {
+	static DocumentBuilderFactory	dbf	= DocumentBuilderFactory.newInstance();
+	static XPathFactory				xpf	= XPathFactory.newInstance();
+
+	static {
+		dbf.setNamespaceAware(false);
+	}
+	
+	public enum Scope {
+		compile, runtime, system, import_, provided, test, ;
+		
+		private boolean includes(Scope other) {
+			if (other == this) return true;
+			switch (this) {
+			case compile:
+				return other == provided || other == test;
+			default:
+				return false;
+			}
+		}
+	};
+
+	final Maven			maven;
+	final URI			home;
+
+	String				groupId;
+	String				artifactId;
+	String				version;
+	List<Dependency>	dependencies	= new ArrayList<Dependency>();
+	Exception			exception;
+	File				pomFile;
+	String				description="";
+	String				name;
+
+	public String getDescription() {
+		return description;
+	}
+
+	public class Dependency {
+		Scope		scope;
+		String		type;
+		boolean		optional;
+		String		groupId;
+		String		artifactId;
+		String		version;
+		Set<String>	exclusions	= new HashSet<String>();
+
+		public Scope getScope() {
+			return scope;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public boolean isOptional() {
+			return optional;
+		}
+
+		public String getGroupId() {
+			return replace(groupId);
+		}
+
+		public String getArtifactId() {
+			return replace(artifactId);
+		}
+
+		public String getVersion() {
+			return replace(version);
+		}
+
+		public Set<String> getExclusions() {
+			return exclusions;
+		}
+
+		public Pom getPom() throws Exception {
+			return maven.getPom(groupId, artifactId, version);
+		}
+		@Override
+		public String toString() {
+			StringBuilder builder = new StringBuilder();
+			builder.append("Dependency [");
+			if (groupId != null)
+				builder.append("groupId=").append(groupId).append(", ");
+			if (artifactId != null)
+				builder.append("artifactId=").append(artifactId).append(", ");
+			if (version != null)
+				builder.append("version=").append(version).append(", ");
+			if (type != null)
+				builder.append("type=").append(type).append(", ");
+			if (scope != null)
+				builder.append("scope=").append(scope).append(", ");
+			builder.append("optional=").append(optional).append(", ");
+			if (exclusions != null)
+				builder.append("exclusions=").append(exclusions);
+			builder.append("]");
+			return builder.toString();
+		}
+	}
+
+	public Pom(Maven maven, File pomFile, URI home) throws Exception {
+		this.maven = maven;
+		this.home = home;
+		this.pomFile = pomFile;
+	}
+
+	void parse() throws Exception {
+		DocumentBuilder db = dbf.newDocumentBuilder();
+		System.out.println("Parsing " + pomFile.getAbsolutePath());
+		Document doc = db.parse(pomFile);
+		XPath xp = xpf.newXPath();
+		parse(doc, xp);
+	}
+
+	protected void parse(Document doc, XPath xp) throws XPathExpressionException, Exception {
+
+		this.artifactId = replace(xp.evaluate("project/artifactId", doc).trim(), this.artifactId);
+		this.groupId = replace(xp.evaluate("project/groupId", doc).trim(), this.groupId);
+		this.version = replace(xp.evaluate("project/version", doc).trim(), this.version);
+		
+		String nextDescription = xp.evaluate("project/description", doc).trim();
+		if ( this.description.length() != 0 && nextDescription.length() != 0)
+			this.description += "\n";
+		this.description += replace(nextDescription);
+		
+		this.name = replace(xp.evaluate("project/name", doc).trim(), this.name);
+
+		NodeList list = (NodeList) xp.evaluate("project/dependencies/dependency", doc,
+				XPathConstants.NODESET);
+		for (int i = 0; i < list.getLength(); i++) {
+			Node node = list.item(i);
+			Dependency dep = new Dependency();
+			String scope = xp.evaluate("scope", node).trim();
+			if (scope.length() == 0)
+				dep.scope = Scope.compile;
+			else
+				dep.scope = Scope.valueOf(scope);
+			dep.type = xp.evaluate("type", node).trim();
+
+			String opt = xp.evaluate("optional", node).trim();
+			dep.optional = opt != null && opt.equalsIgnoreCase("true");
+			dep.groupId = replace(xp.evaluate("groupId", node));
+			dep.artifactId = replace(xp.evaluate("artifactId", node).trim());
+
+			dep.version = replace(xp.evaluate("version", node).trim());
+			dependencies.add(dep);
+
+			NodeList exclusions = (NodeList) xp
+					.evaluate("exclusions", node, XPathConstants.NODESET);
+			for (int e = 0; e < exclusions.getLength(); e++) {
+				Node exc = exclusions.item(e);
+				String exclGroupId = xp.evaluate("groupId", exc).trim();
+				String exclArtifactId = xp.evaluate("artifactId", exc).trim();
+				dep.exclusions.add(exclGroupId + "+" + exclArtifactId);
+			}
+		}
+
+	}
+
+	private String replace(String key, String dflt) {
+		if ( key == null || key.length() == 0)
+			return dflt;
+		
+		return replace(key);
+	}
+
+	public String getArtifactId() throws Exception {
+		return replace(artifactId);
+	}
+
+	public String getGroupId() throws Exception {
+		return replace(groupId);
+	}
+
+	public String getVersion() throws Exception {
+		if ( version == null)
+			return "<not set>";
+		return replace(version);
+	}
+
+	public List<Dependency> getDependencies() throws Exception {
+		return dependencies;
+	}
+
+	class Rover {
+
+		public Rover(Rover rover, Dependency d) {
+			this.previous = rover;
+			this.dependency = d;
+		}
+
+		final Rover			previous;
+		final Dependency	dependency;
+
+		public boolean excludes(String name) {
+			return dependency.exclusions.contains(name) && previous != null
+					&& previous.excludes(name);
+		}
+	}
+
+	public Set<Pom> getDependencies(Scope scope, URI... urls) throws Exception {
+		Set<Pom> result = new LinkedHashSet<Pom>();
+
+		List<Rover> queue = new ArrayList<Rover>();
+		for (Dependency d : dependencies) {
+			queue.add(new Rover(null, d));
+		}
+
+		while (!queue.isEmpty()) {
+			Rover rover = queue.remove(0);
+			Dependency dep = rover.dependency;
+			String groupId = replace(dep.groupId);
+			String artifactId = replace(dep.artifactId);
+			String version = replace(dep.version);
+
+			String name = groupId + "+" + artifactId;
+
+			if (rover.excludes(name) || dep.optional)
+				continue;
+			
+			if (dep.scope == scope && !dep.optional) {
+				try {
+					Pom sub = maven.getPom(groupId, artifactId, version, urls);
+					if (sub != null) {
+						if (!result.contains(sub)) {
+							result.add(sub);
+							for (Dependency subd : sub.dependencies) {
+								queue.add(new Rover(rover, subd));
+							}
+						}
+					} else
+						if (rover.previous != null)
+							System.out.println("Cannot find " + dep + " from "
+									+ rover.previous.dependency);
+						else
+							System.out.println("Cannot find " + dep + " from top");
+				} catch (Exception e) {
+					if (rover.previous != null)
+						System.out.println("Cannot find " + dep + " from "
+								+ rover.previous.dependency);
+					else
+						System.out.println("Cannot find " + dep + " from top");
+
+//			boolean include = false;
+//			if (dep.scope == Scope.compile) {
+//				include = true;
+//			} else if (dep.scope == Scope.test) {
+//				include = rover.previous == null && (action == Action.compile || action == Action.test);
+//			} else if (dep.scope == Scope.runtime) {
+//				include = action == Action.run;
+//			}
+//			if (include) {
+//				Pom sub = maven.getPom(groupId, artifactId, version, urls);
+//				if (!result.contains(sub)) {
+//					result.add(sub);
+//					for (Dependency subd : sub.dependencies) {
+//						queue.add(new Rover(rover, subd));
+//					}
+					
+				}
+			}
+		}
+		return result;
+	}
+
+	protected String replace(String in) {
+		System.out.println("replace: " + in);
+		if (in == null)
+			return "null";
+
+		in = in.trim();
+		if ("${pom.version}".equals(in) || "${version}".equals(in)
+				|| "${project.version}".equals(in))
+			return version;
+
+		if ("${basedir}".equals(in))
+			return pomFile.getParentFile().getAbsolutePath();
+
+		if ("${pom.name}".equals(in) || "${project.name}".equals(in))
+			return name;
+
+		if ("${pom.artifactId}".equals(in) || "${project.artifactId}".equals(in))
+			return artifactId;
+		if ("${pom.groupId}".equals(in) || "${project.groupId}".equals(in))
+			return groupId;
+
+		return in;
+	}
+
+	public String toString() {
+		return groupId + "+" + artifactId + "-" + version;
+	}
+
+	public File getLibrary(Scope action, URI... repositories) throws Exception {
+		MavenEntry entry = maven.getEntry(this);
+		File file = new File(entry.dir, action + ".lib");
+
+		if (file.isFile() && file.lastModified() >= getPomFile().lastModified())
+			return file;
+
+		file.delete();
+
+		Writer writer = new FileWriter(file);
+		doEntry(writer, this);
+		try {
+			for (Pom dep : getDependencies(action, repositories)) {
+				doEntry(writer, dep);
+			}
+		} finally {
+			writer.close();
+		}
+		return file;
+	}
+
+	/**
+	 * @param writer
+	 * @param dep
+	 * @throws IOException
+	 * @throws Exception
+	 */
+	private void doEntry(Writer writer, Pom dep) throws IOException, Exception {
+		writer.append(dep.getGroupId());
+		writer.append("+");
+		writer.append(dep.getArtifactId());
+		writer.append(";version=\"");
+		writer.append(dep.getVersion());
+		writer.append("\"\n");
+	}
+
+	public File getPomFile() {
+		return pomFile;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public abstract java.io.File getArtifact() throws Exception;
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Pom.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Pom.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/ProjectPom.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/ProjectPom.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/ProjectPom.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/ProjectPom.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,204 @@
+package aQute.bnd.maven.support;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.xml.xpath.*;
+
+import org.w3c.dom.*;
+
+import aQute.lib.io.*;
+
+public class ProjectPom extends Pom {
+
+	final List<URI>	repositories	= new ArrayList<URI>();
+	final Properties	properties		= new Properties();
+	String 		packaging;
+	String 		url;
+	
+	ProjectPom(Maven maven, File pomFile) throws Exception {
+		super(maven, pomFile, pomFile.toURI());
+	}
+
+	@Override protected void parse(Document doc, XPath xp) throws Exception {
+
+		packaging = xp.evaluate("project/packaging", doc);
+		url = xp.evaluate("project/url", doc);
+		
+		Node parent = (Node) xp.evaluate("project/parent", doc, XPathConstants.NODE);
+		if (parent != null && parent.hasChildNodes()) {
+			File parentFile = IO.getFile(getPomFile().getParentFile(), "../pom.xml");
+
+			String parentGroupId = xp.evaluate("groupId", parent).trim();
+			String parentArtifactId = xp.evaluate("artifactId", parent).trim();
+			String parentVersion = xp.evaluate("version", parent).trim();
+			String parentPath = xp.evaluate("relativePath", parent).trim();
+			if (parentPath != null && parentPath.length()!=0) {
+				parentFile = IO.getFile(getPomFile().getParentFile(), parentPath);
+			}
+			if (parentFile.isFile()) {
+				ProjectPom parentPom = new ProjectPom(maven, parentFile);
+				parentPom.parse();
+				dependencies.addAll(parentPom.dependencies);
+				for ( Enumeration<?> e = parentPom.properties.propertyNames(); e.hasMoreElements(); ) {
+					String key = (String) e.nextElement();
+					if ( ! properties.contains(key))
+						properties.put(key, parentPom.properties.get(key));
+				}
+				repositories.addAll(parentPom.repositories);
+				
+				setNames(parentPom);
+			} else {
+				// This seems to be a bit bizarre, extending an external pom?
+				CachedPom parentPom = maven.getPom(parentGroupId, parentArtifactId, parentVersion);
+				dependencies.addAll(parentPom.dependencies);
+				setNames(parentPom);
+			}
+		}
+
+		NodeList propNodes = (NodeList) xp.evaluate("project/properties/*", doc,
+				XPathConstants.NODESET);
+		for (int i = 0; i < propNodes.getLength(); i++) {
+			Node node = propNodes.item(i);
+			String key = node.getNodeName();
+			String value = node.getTextContent();
+			if ( key == null || key.length()==0)
+				throw new IllegalArgumentException("Pom has an empty or null key");
+			if ( value == null || value.length()==0)
+				throw new IllegalArgumentException("Pom has an empty or null value for property " + key);
+			properties.setProperty(key, value.trim());
+		}
+
+		NodeList repos = (NodeList) xp.evaluate("project/repositories/repository/url", doc,
+				XPathConstants.NODESET);
+		for (int i = 0; i < repos.getLength(); i++) {
+			Node node = repos.item(i);
+			String URIString = node.getTextContent().trim();
+			URI uri = new URI(URIString);
+			if ( uri.getScheme() ==null )
+				uri = IO.getFile(pomFile.getParentFile(),URIString).toURI();
+			repositories.add(uri);
+		}
+
+		super.parse(doc, xp);
+	}
+
+//	private void print(Node node, String indent) {
+//		System.out.print(indent);
+//		System.out.println(node.getNodeName());
+//		Node rover = node.getFirstChild();
+//		while ( rover != null) {
+//			print( rover, indent+" ");
+//			rover = rover.getNextSibling();
+//		}
+//	}
+
+	/**
+	 * @param parentArtifactId
+	 * @param parentGroupId
+	 * @param parentVersion
+	 * @throws Exception
+	 */
+	private void setNames(Pom pom) throws Exception {
+		if (artifactId == null || artifactId.length()==0)
+			artifactId = pom.getArtifactId();
+		if (groupId == null || groupId.length()==0)
+			groupId = pom.getGroupId();
+		if (version == null || version.length()==0)
+			version = pom.getVersion();
+		if ( description == null )
+			description = pom.getDescription();
+		else
+			description = pom.getDescription() + "\n" + description;
+	
+	}
+
+	class Rover {
+
+		public Rover(Rover rover, Dependency d) {
+			this.previous = rover;
+			this.dependency = d;
+		}
+
+		final Rover			previous;
+		final Dependency	dependency;
+
+		public boolean excludes(String name) {
+			return dependency.exclusions.contains(name) && previous != null
+					&& previous.excludes(name);
+		}
+	}
+
+	public Set<Pom> getDependencies(Scope action) throws Exception {
+		return getDependencies(action, repositories.toArray(new URI[0]));
+	}
+
+	// Match any macros
+	final static Pattern	MACRO	= Pattern.compile("(\\$\\{\\s*([^}\\s]+)\\s*\\})");
+
+	protected String replace(String in) {
+		System.out.println("Replce: " + in);
+		if ( in == null) {
+			System.out.println("null??");
+		}
+		Matcher matcher = MACRO.matcher(in);
+		int last = 0;
+		StringBuilder sb = new StringBuilder();
+		while (matcher.find()) {
+			int n = matcher.start();
+			sb.append( in, last, n);
+			String replacement = get(matcher.group(2));
+			if ( replacement == null )
+				sb.append( matcher.group(1));
+			else
+				sb.append( replacement );
+			last = matcher.end();
+		}
+		if ( last == 0)
+			return in;
+		
+		sb.append( in, last, in.length());
+		return sb.toString();
+	}
+
+	private String get(String key) {
+		if (key.equals("pom.artifactId"))
+			return artifactId;
+		if (key.equals("pom.groupId"))
+			return groupId;
+		if (key.equals("pom.version"))
+			return version;
+		
+		if (key.equals("pom.name"))
+			return name;
+		
+		String prop = properties.getProperty(key);
+		if ( prop != null )
+			return prop;
+		
+		return System.getProperty(key);
+	}
+
+	public Properties getProperties() {
+		return properties;
+	}
+
+	public String getPackaging() {
+		return packaging;
+	}
+
+	public String getUrl() {
+		return url;
+	}
+
+	public String getProperty(String key) {
+		String s = properties.getProperty(key);
+		return replace(s);
+	}
+
+	@Override public File getArtifact() throws Exception {
+		return null;
+	}
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/ProjectPom.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/ProjectPom.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Repo.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Repo.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Repo.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Repo.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,5 @@
+package aQute.bnd.maven.support;
+
+public class Repo {
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Repo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/maven/support/Repo.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/repo/eclipse/EclipseRepo.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/repo/eclipse/EclipseRepo.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/repo/eclipse/EclipseRepo.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/repo/eclipse/EclipseRepo.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,199 @@
+package aQute.bnd.repo.eclipse;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+import aQute.bnd.service.*;
+import aQute.lib.osgi.*;
+import aQute.libg.generics.*;
+import aQute.libg.reporter.*;
+import aQute.libg.version.*;
+
+public class EclipseRepo implements Plugin, RepositoryPlugin {
+    File                             root;
+    Reporter                         reporter;
+    String                           name;
+    Map<String, Map<String, String>> index;
+
+    public static String             LOCATION = "location";
+    public static String             NAME     = "name";
+
+    public void setProperties(Map<String, String> map) {
+        String location = (String) map.get(LOCATION);
+        if (location == null)
+            throw new IllegalArgumentException(
+                    "Location muse be set on a EclipseRepo plugin");
+
+        root = new File(location);
+        if (!root.isDirectory())
+            throw new IllegalArgumentException(
+                    "Repository is not a valid directory " + root);
+
+        if (!new File(root, "plugins").isDirectory())
+            throw new IllegalArgumentException(
+                    "Repository is not a valid directory (no plugins directory)"
+                            + root);
+
+        name = (String) map.get(NAME);
+
+        try {
+            index = buildIndex();
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Could not build index for eclipse repo: " + root);
+        }
+    }
+
+    Map<String, Map<String, String>> buildIndex() throws Exception {
+        File index = new File(root, "bnd.index").getAbsoluteFile();
+        File[] plugins = new File(root, "plugins").listFiles();
+
+        for (File f : plugins) {
+            f = f.getAbsoluteFile();
+            if (f.isFile()) {
+                if (f.lastModified() > index.lastModified()) {
+
+                    Map<String, Map<String, String>> map = buildIndex(plugins);
+                    write(index, map);
+                    return map;
+                }
+            }
+        }
+
+        String s = read(index);
+        return Processor.parseHeader(s, null);
+    }
+
+    private String read(File index) throws Exception {
+        if (index.isFile()) {
+            BufferedReader fr = new BufferedReader(new FileReader(index));
+            StringBuilder sb = new StringBuilder();
+
+            try {
+                String s = fr.readLine();
+                while (s != null) {
+                    sb.append(s);
+                    s = fr.readLine();
+                }
+            } finally {
+                fr.close();
+            }
+        }
+        return null;
+    }
+
+    private void write(File index, Map<String, Map<String, String>> map)
+            throws Exception {
+        String s = Processor.printClauses(map);
+        index.getParentFile().mkdirs();
+        FileWriter fw = new FileWriter(index);
+        try {
+            fw.write(s);
+        } finally {
+            fw.close();
+        }
+    }
+
+    private Map<String, Map<String, String>> buildIndex(File[] plugins) {
+        Map<String, Map<String, String>> map = Create.map();
+        for (File plugin : plugins) {
+            try {
+                Jar jar = new Jar(plugin);
+                Manifest manifest = jar.getManifest();
+                String bsn = manifest.getMainAttributes().getValue(
+                        Constants.BUNDLE_SYMBOLICNAME);
+                String version = manifest.getMainAttributes().getValue(
+                        Constants.BUNDLE_VERSION);
+
+                if (bsn != null) {
+                    if (version == null)
+                        version = "0";
+
+                    Map<String, String> instance = map.get(bsn);
+                    if (instance == null) {
+                        instance = Create.map();
+                    }
+                    instance.put(version, plugin.getAbsolutePath());
+                }
+            } catch (Exception e) {
+                // Ignore exceptions in the plugins dir.
+            }
+        }
+        return map;
+    }
+
+    public void setReporter(Reporter reporter) {
+        this.reporter = reporter;
+    }
+
+    public boolean canWrite() {
+        return false;
+    }
+
+    public File[] get(String bsn, String range) throws Exception {
+        VersionRange r = new VersionRange(range);
+        Map<String, String> instances = index.get(bsn);
+        if (instances == null)
+            return null;
+
+        List<File> result = Create.list();
+
+        for (String version : instances.keySet()) {
+            Version v = new Version(version);
+            if (r.includes(v)) {
+                File f = new File(instances.get(version));
+                if (f.isFile()) {
+                    result.add(f);
+                }
+            }
+        }
+        return result.toArray(new File[result.size()]);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<String> list(String regex) {
+        Instruction pattern = null;
+        if (regex != null)
+            pattern = Instruction.getPattern(regex);
+
+        List<String> result = new ArrayList<String>();
+        for (String f : index.keySet()) {
+            if (pattern == null || pattern.matches(f))
+                result.add(f);
+        }
+        return result;
+    }
+
+    public File put(Jar jar) throws Exception {
+        return null;
+    }
+
+    public List<Version> versions(String bsn) {
+        Map<String, String> instances = index.get(bsn);
+        if (instances == null)
+            return null;
+
+        List<Version> versions = Create.list();
+        for (String v : instances.keySet())
+            versions.add(new Version(v));
+        return versions;
+    }
+
+
+	public File get(String bsn, String range, Strategy strategy, Map<String,String> properties) throws Exception {
+		File[] files = get(bsn, range);
+		if (files.length >= 0) {
+			switch (strategy) {
+			case LOWEST:
+				return files[0];
+			case HIGHEST:
+				return files[files.length - 1];
+			}
+		}
+		return null;
+	}
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/repo/eclipse/EclipseRepo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/repo/eclipse/EclipseRepo.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolution.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolution.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolution.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolution.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,12 @@
+package aQute.bnd.resolver;
+
+import java.util.*;
+
+import aQute.bnd.resolver.Resource.Requirement;
+import aQute.lib.collections.*;
+
+public class Resolution {
+	public Set<Requirement>				unresolved;
+	public MultiMap<Requirement, Resource>	multiple;
+	public Map<Requirement, Resource>		unique;
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolution.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolution.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolver.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolver.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolver.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolver.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,172 @@
+package aQute.bnd.resolver;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+import aQute.bnd.build.*;
+import aQute.bnd.resolver.Resource.Requirement;
+import aQute.lib.collections.*;
+import aQute.lib.osgi.*;
+import aQute.libg.generics.*;
+
+public class Resolver extends Processor {
+
+	final Set<Resource>									resources	= new HashSet<Resource>();
+	private Map<Resource.Requirement, Set<Resource>>	cache		= new IdentityHashMap<Resource.Requirement, Set<Resource>>();
+
+	public void add(Container c) throws Exception {
+		List<File> files = new ArrayList<File>();
+		c.contributeFiles(files, this);
+		for (File f : files) {
+			add(f);
+		}
+	}
+
+	public void addAll(Collection<Container> containers) throws Exception {
+		for (Container c : containers) {
+			add(c);
+		}
+	}
+
+	public Resolution resolve() throws Exception {
+		// Split fragments and bundles
+		Set<Resource> active = new HashSet<Resource>();
+		Set<Resource> fragments = new HashSet<Resource>();
+		Set<Resource> singletons = new HashSet<Resource>();
+
+		for (Resource r : resources) {
+			if (r.fragments != null) {
+				active.add(r);
+				if (r.singleton)
+					singletons.add(r);
+			} else
+				fragments.add(r);
+		}
+
+		// Attach fragments
+		for (Resource r : fragments) {
+			Collection<Resource> hosts = find(active, r.requirements, new HashSet<Resource>());
+			for (Resource host : hosts) {
+				host.fragments.add(host);
+			}
+		}
+
+		// Create a list of all the requirements
+		Set<Resource.Requirement> reqs = new HashSet<Resource.Requirement>();
+		for (Resource r : active) {
+			reqs.addAll(r.requirements);
+			// And its attached fragments
+			for (Resource f : r.fragments) {
+				reqs.addAll(f.requirements);
+			}
+		}
+
+		Set<Resource.Requirement> optional = Create.set();
+		Set<Resource.Requirement> unresolved = Create.set();
+		Map<Resource.Requirement, Resource> unique = Create.map();
+		MultiMap<Requirement, Resource> multiple = new MultiMap<Requirement, Resource>();
+
+		for (Resource.Requirement req : reqs) {
+			Collection<Resource> solutions = find(active, req, new HashSet<Resource>());
+			if (solutions.isEmpty()) {
+				if (req.optional)
+					optional.add(req);
+				else
+					unresolved.add(req);
+			} else if (solutions.size() == 1)
+				unique.put(req, solutions.iterator().next());
+			else {
+				multiple.addAll(req, solutions);
+			}
+		}
+
+		// If we have unresolveds, tough shit
+
+		if (!unresolved.isEmpty()) {
+			for (Requirement r : unresolved) {
+				error("Unresolved %s", r);
+			}
+		}
+
+		// Calculate our singleton candidates
+		MultiMap<String, Resource> picked = new MultiMap<String, Resource>();
+		for (Resource r : singletons) {
+			picked.add(r.bsn, r);
+		}
+
+		// Remove any singletons that are alone
+		// and verify that if there are multiple they are not
+		// both in the unique solutions
+		for (Iterator<Map.Entry<String, Set<Resource>>> i = picked.entrySet().iterator(); i
+				.hasNext();) {
+			Map.Entry<String, Set<Resource>> entry = i.next();
+			if (entry.getValue().size() == 1)
+				i.remove();
+			else {
+				Set<Resource> x = new HashSet<Resource>(entry.getValue());
+				boolean changed = x.retainAll(unique.values());
+				if (x.size() > 1) {
+					// We need multiple singleton bundles with the same bsn
+					error("Singleton conflict: %s", x);
+				} else if (changed) {
+					Set<Resource> delta = new HashSet<Resource>(entry.getValue());
+					delta.removeAll(x);
+
+					// We've removed bundles from the possible solutions
+					for (Iterator<Resource> it = multiple.all(); i.hasNext();) {
+						Resource r = it.next();
+						if (delta.contains(r)) {
+							it.remove();
+						}
+					}
+				}
+			}
+		}
+
+		Resolution res = new Resolution();
+		res.multiple = multiple;
+		res.unique = unique;
+		res.unresolved = unresolved;
+		return res;
+	}
+
+	private Collection<Resource> find(Set<Resource> active, Set<Resource.Requirement> requirements,
+			Set<Resource> result) {
+		for (Resource.Requirement req : requirements) {
+			Set<Resource> resources = cache.get(req);
+			if (resources != null) {
+				result.addAll(resources);
+			} else {
+				resources = find(active, req, new HashSet<Resource>());
+				cache.put(req, resources);
+				result.addAll(resources);
+			}
+		}
+		return result;
+	}
+
+	private Set<Resource> find(Set<Resource> active, Requirement req, Set<Resource> result) {
+		for (Resource r : active) {
+			for (Resource.Capability cap : r.capabilities) {
+				if ( cap.name.equals(req.name))
+					System.out.println("Yes");
+				if (req.matches(cap))
+					result.add(r);
+			}
+		}
+		return result;
+	}
+
+	public void add(File file) throws IOException {
+		JarFile jf = new JarFile(file);
+		try {
+			Manifest m = jf.getManifest();
+			Resource r = new Resource(this, m);
+			resources.add(r);
+		} finally {
+			jf.close();
+		}
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resolver.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resource.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resource.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resource.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resource.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,161 @@
+package aQute.bnd.resolver;
+
+import java.util.*;
+import java.util.jar.*;
+
+import aQute.lib.osgi.*;
+import aQute.libg.version.*;
+
+public class Resource {
+	enum Type {
+		PACKAGE,
+		BUNDLE,
+		HOST;
+	}
+	
+	final Set<Requirement>	requirements	= new HashSet<Requirement>();
+	final Set<Capability>	capabilities	= new HashSet<Capability>();
+	final List<Resource>	fragments;
+	final String			bsn;
+	final Version			version;
+	final boolean			singleton;
+	final Resolver			resolver;
+
+	class Requirement {
+		final Type		type;
+		final String		name;
+		final VersionRange	range;
+		final boolean		optional;
+
+		Requirement(Type type, String name, VersionRange range, boolean optional) {
+			this.type = type;
+			this.name = name;
+			this.range = range;
+			this.optional = optional;
+		}
+
+		Resource getDeclaredResource() {
+			return Resource.this;
+		}
+
+		public boolean matches(Capability cap) {
+			boolean a = cap.type == type;
+			boolean b = cap.name.equals(name);
+			boolean c = range.includes(cap.version);
+			return a && b && c;
+		}
+		
+		public String toString() {
+			return "R." +type + ":" + name + "-" + range;
+		}
+
+	}
+
+	class Capability {
+		final Type	type;
+		final String	name;
+		final Version	version;
+
+		Capability(Type type, String name, Version version) {
+			this.type = type;
+			this.name = name;
+			this.version = version;
+		}
+
+		Resource getDeclaredResource() {
+			return Resource.this;
+		}
+		public String toString() {
+			return "C." + type + ":" + name + "-" + version;
+		}
+	}
+
+	Resource(Resolver resolver, Manifest m) {
+		this.resolver= resolver;
+		Attributes main = m.getMainAttributes();
+		Map<String, Map<String, String>> bsns = resolver.parseHeader(main
+				.getValue(Constants.BUNDLE_SYMBOLICNAME));
+		if (bsns.size() > 1)
+			resolver.error("Multiple bsns %s", bsns);
+		if (bsns.size() < 1) {
+			resolver.error("No bsns");
+			bsn = "<not set>";
+			version = new Version("0");
+			singleton = false;
+		} else {
+			Map.Entry<String, Map<String, String>> entry = bsns.entrySet().iterator().next();
+			bsn = entry.getKey();
+			String v = main.getValue(Constants.BUNDLE_VERSION);
+			this.version = version(v);
+			singleton = "true"
+					.equalsIgnoreCase(entry.getValue().get(Constants.SINGLETON_DIRECTIVE));
+
+			String directive = entry.getValue().get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE);
+			boolean attach = directive == null || "always".equals(directive) || "resolve-time".equals(directive);
+			if (attach) {
+				capabilities.add(new Capability(Type.HOST, bsn, version));
+			}
+		}
+		Map<String, Map<String, String>> hosts = resolver.parseHeader(main.getValue(Constants.FRAGMENT_HOST));
+		if (hosts.size() > 1)
+			resolver.error("Multiple fragment hosts %s", hosts);
+		if (hosts.size() == 1) {
+			Map.Entry<String, Map<String, String>> entry = hosts.entrySet().iterator().next();
+			String host = entry.getKey();
+			VersionRange range = range(entry.getValue().get(Constants.VERSION_ATTRIBUTE));
+			requirements.add(new Requirement(Type.HOST, host, range, false));
+			fragments = null;
+		} else {
+			fragments = new ArrayList<Resource>();
+			capabilities.add(new Capability(Type.BUNDLE, bsn, version));
+		}
+
+		Map<String, Map<String, String>> rbs = resolver.parseHeader(main.getValue(Constants.REQUIRE_BUNDLE));
+		for (Map.Entry<String, Map<String, String>> clause : rbs.entrySet()) {
+			boolean optional = "optional".equals(clause.getValue().get(
+					Constants.RESOLUTION_DIRECTIVE));
+			requirements.add(new Requirement(Type.BUNDLE, clause.getKey(), range(clause
+					.getValue().get(Constants.VERSION_ATTRIBUTE)), optional));
+		}
+		Map<String, Map<String, String>> imports = resolver.parseHeader(main
+				.getValue(Constants.IMPORT_PACKAGE));
+		for (Map.Entry<String, Map<String, String>> clause : imports.entrySet()) {
+			boolean optional = "optional".equals(clause.getValue().get(
+					Constants.RESOLUTION_DIRECTIVE));
+			requirements.add(new Requirement(Type.PACKAGE, clause.getKey(), range(clause
+					.getValue().get(Constants.VERSION_ATTRIBUTE)), optional));
+		}
+		Map<String, Map<String, String>> exports = resolver.parseHeader(main
+				.getValue(Constants.EXPORT_PACKAGE));
+		for (Map.Entry<String, Map<String, String>> clause : exports.entrySet()) {
+			capabilities.add(new Capability(Type.PACKAGE, clause.getKey(), version(clause
+					.getValue().get(Constants.VERSION_ATTRIBUTE))));
+		}
+	}
+
+	private VersionRange range(String string) {
+		try {
+			return new VersionRange(string);
+		} catch (NullPointerException e) {
+			return new VersionRange("0");
+		} catch (Exception e) {
+			resolver.error("Invalid version range: %s in %s-%s", string, bsn, version);
+			return new VersionRange("0");
+		}
+	}
+
+	private Version version(String string) {
+		try {
+			return new Version(string);
+		} catch (NullPointerException e) {
+			return new Version("0");
+		} catch (Exception e) {
+			resolver.error("Invalid version: %s in %s-%s", string, bsn, version);
+			return new Version("0");
+		}
+	}
+	
+	public String toString() {
+		return bsn + "-" + version;
+	}
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/resolver/Resource.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -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

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,17 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.concurrent.atomic.*;
+
+public class BndListener {
+	final AtomicInteger inside = new AtomicInteger();
+	
+    public void changed(File file) {
+    }
+    public void begin() { inside.incrementAndGet();}
+    public void end() { inside.decrementAndGet(); }
+    
+    public boolean isInside() {
+    	return inside.get()!=0;
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,30 @@
+package aQute.bnd.service;
+
+import aQute.bnd.build.*;
+
+/**
+ * A plugin that makes it possible to 
+ * @author aqute
+ *
+ */
+public interface CommandPlugin {
+    /**
+     * Is run before a command is executed. These plugins are called
+     * in the order of declaration.
+     * 
+     * @param project The project for which the command runs
+     * 
+     * @param command the command name
+     */
+    void before(Project project, String command);
+    
+    /**
+     * Is run after a command is executed. These plugins are
+     * called in the reverse order of declaration.
+     * 
+     * @param project The project for which the command runs
+     *
+     * @param command the command name
+     */
+    void after(Project project, String command, Throwable outcome);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,11 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.*;
+
+import aQute.bnd.build.*;
+
+public interface Compiler {
+	boolean compile(Project project, Collection<File> sources, Collection<Container> buildpath,
+			File bin) throws Exception;
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,9 @@
+package aQute.bnd.service;
+
+import java.util.*;
+
+import aQute.bnd.build.*;
+
+public interface DependencyContributor {
+    void addDependencies(Project project, Set<String> dependencies);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,12 @@
+package aQute.bnd.service;
+
+import aQute.bnd.build.*;
+import aQute.lib.osgi.*;
+
+/**
+ * Deploy this artifact to maven.
+ * 
+ */
+public interface Deploy {	
+	boolean deploy(Project project, Jar jar) throws Exception;
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,6 @@
+package aQute.bnd.service;
+
+public interface EclipseJUnitTester {
+	void setPort(int port);
+	void setHost( String host);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,9 @@
+package aQute.bnd.service;
+
+import aQute.bnd.build.*;
+
+public interface LauncherPlugin {
+	ProjectLauncher getLauncher(Project project) throws Exception;
+
+	ProjectTester getTester(Project project);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -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

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,11 @@
+package aQute.bnd.service;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Set;
+
+public interface OBRIndexProvider {
+	Collection<URL> getOBRIndexes() throws IOException;
+	Set<OBRResolutionMode> getSupportedModes();
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,5 @@
+package aQute.bnd.service;
+
+public enum OBRResolutionMode {
+	build, runtime
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -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

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -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

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Registry.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Registry.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Registry.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Registry.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,11 @@
+package aQute.bnd.service;
+
+import java.util.*;
+
+/**
+ * A registry for objects.
+ */
+public interface Registry {
+	<T> List<T> getPlugins(Class<T> c);
+	<T> T getPlugin(Class<T> c);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Registry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Registry.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,9 @@
+package aQute.bnd.service;
+
+
+/**
+ * A plugin that wants a registry
+ */
+public interface RegistryPlugin {
+	void setRegistry(Registry registry);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,17 @@
+package aQute.bnd.service;
+
+import java.util.Map;
+
+public interface RemoteRepositoryPlugin extends RepositoryPlugin {
+	/**
+	 * Retrieve a resource handle from the repository. For all implementations of this interface, calling {@code getFile(bsn, range, strategy, props)}
+	 * should always return the same result as {@code getResource(bsn, range, strategy, props).request()}.
+	 * @param bsn
+	 * @param range
+	 * @param strategy
+	 * @param properties
+	 * @return
+	 * @throws Exception
+	 */
+	ResourceHandle getHandle(String bsn, String range, Strategy strategy, Map<String,String> properties) throws Exception;
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,16 @@
+package aQute.bnd.service;
+
+import java.io.File;
+
+import aQute.lib.osgi.Jar;
+
+public interface RepositoryListenerPlugin {
+	
+	/**
+	 * Called when a bundle is added to a repository.
+	 * @param repository
+	 * @param jar
+	 * @param file
+	 */
+	void bundleAdded(RepositoryPlugin repository, Jar jar, File file);
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -0,0 +1,86 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.*;
+
+import aQute.lib.osgi.*;
+import aQute.libg.version.*;
+
+public interface RepositoryPlugin {
+	public enum Strategy {
+		LOWEST, HIGHEST, EXACT
+	}
+
+	/**
+	 * 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
+	 */
+	@Deprecated File[] get(String bsn, String range) throws Exception;
+
+	/**
+	 * 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.
+	 * @param strategy
+	 *            Get the highest or the lowest
+	 * @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, Strategy strategy, Map<String,String> properties) 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
+	 * @throws Exception
+	 */
+	List<String> list(String regex) throws Exception;
+
+	/**
+	 * Return a list of versions.
+	 * 
+	 * @throws Exception
+	 */
+
+	List<Version> versions(String bsn) throws Exception;
+
+	/**
+	 * @return The name of the repository
+	 */
+	String getName();
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,13 @@
+package aQute.bnd.service;
+
+import java.io.File;
+import java.io.IOException;
+
+public interface ResourceHandle {
+	
+	public enum Location { local, remote_cached, remote };
+	
+	String getName();
+	Location getLocation();
+	File request() throws IOException;
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,10 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.*;
+
+public interface Scripter {
+
+	void eval(Map<String, Object> x, StringReader stringReader);
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -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

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

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=1185095&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 Oct 17 10:31:43 2011
@@ -0,0 +1,7 @@
+package aQute.bnd.service.action;
+
+import aQute.bnd.build.*;
+
+public interface Action {
+    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

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,6 @@
+package aQute.bnd.service.action;
+
+
+public interface NamedAction extends Action {
+    String getName();
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo Mon Oct 17 10:31:43 2011
@@ -0,0 +1 @@
+version 1.43.1

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/packageinfo?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/packageinfo (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/service/packageinfo Mon Oct 17 10:31:43 2011
@@ -0,0 +1 @@
+version 1.44.0

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/settings/Settings.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/settings/Settings.java?rev=1185095&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/settings/Settings.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/settings/Settings.java Mon Oct 17 10:31:43 2011
@@ -0,0 +1,62 @@
+package aQute.bnd.settings;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.util.*;
+import java.util.prefs.*;
+
+import aQute.libg.cryptography.*;
+import aQute.libg.tuple.*;
+
+public class Settings {
+	public final static String	EMAIL			= "email";
+	public final static String	NAME			= "name";
+	public final static String	PASSWORD_SHA1	= "password.sha1";
+	final static String			KEY_PRIVATE		= "key.private";
+	final static String			KEY_PUBLIC		= "key.public";
+	final static String			KEY_SET			= "key.set";
+
+	static Preferences			prefs			= Preferences.userNodeForPackage(Settings.class);
+
+	public String globalGet(String key, String def) {
+		return prefs.get(key, def);
+	}
+
+	public void globalSet(String key, String value) throws BackingStoreException {
+		prefs.put(key, value);
+		prefs.sync();
+	}
+
+	public Collection<String> getKeys() throws BackingStoreException {
+		return Arrays.asList(prefs.keys());
+	}
+
+	public void globalRemove(String key) throws BackingStoreException {
+		prefs.remove(key);
+		prefs.sync();
+	}
+
+	private void generate() throws NoSuchAlgorithmException {
+		Pair<? extends PrivateKey, ? extends RSAPublicKey> pair = RSA.generate();
+		prefs.put(KEY_PRIVATE, Crypto.toString(pair.a));
+		prefs.put(KEY_PUBLIC, Crypto.toString(pair.b));
+		prefs.putBoolean(KEY_SET, true);
+	}
+
+	public PrivateKey getPrivateKey() throws Exception {
+		if (prefs.getBoolean(KEY_SET, false))
+			generate();
+
+		String key = prefs.get(KEY_PRIVATE, null);
+		return Crypto.fromString(key, PrivateKey.class);
+	}
+
+	public PublicKey getPublicKey() throws Exception {
+		if (prefs.getBoolean(KEY_SET, false))
+			generate();
+
+		String key = prefs.get(KEY_PUBLIC, null);
+		return Crypto.fromString(key, PublicKey.class);
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/settings/Settings.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/settings/Settings.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision