Use local copy of latest bndlib code for pre-release testing purposes

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java
new file mode 100644
index 0000000..3efe8ee
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/AnalyzerPlugin.java
@@ -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;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java b/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java
new file mode 100644
index 0000000..e937110
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/BndListener.java
@@ -0,0 +1,23 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.concurrent.atomic.*;
+
+import aQute.libg.reporter.*;
+
+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;
+    }
+    
+    public void signal(Reporter reporter) {
+    	
+    }
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java
new file mode 100644
index 0000000..34c72c2
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/CommandPlugin.java
@@ -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);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java b/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java
new file mode 100644
index 0000000..626b68c
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/Compiler.java
@@ -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;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java b/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java
new file mode 100644
index 0000000..e6a88ff
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/DependencyContributor.java
@@ -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);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java b/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java
new file mode 100644
index 0000000..e1d92e1
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/Deploy.java
@@ -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;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java b/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java
new file mode 100644
index 0000000..a2af9b0
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/EclipseJUnitTester.java
@@ -0,0 +1,6 @@
+package aQute.bnd.service;
+
+public interface EclipseJUnitTester {
+	void setPort(int port);
+	void setHost( String host);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/IndexProvider.java b/bundleplugin/src/main/java/aQute/bnd/service/IndexProvider.java
new file mode 100644
index 0000000..5454c2d
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/IndexProvider.java
@@ -0,0 +1,13 @@
+package aQute.bnd.service;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Set;
+
+public interface IndexProvider {
+
+	List<URL> getIndexLocations() throws Exception;
+
+	Set<ResolutionPhase> getSupportedPhases();
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java
new file mode 100644
index 0000000..f858500
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/LauncherPlugin.java
@@ -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);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java
new file mode 100644
index 0000000..20a1849
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/MakePlugin.java
@@ -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;
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java b/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java
new file mode 100644
index 0000000..9ba5b04
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/OBRIndexProvider.java
@@ -0,0 +1,11 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+@Deprecated
+public interface OBRIndexProvider {
+	Collection<URL> getOBRIndexes() throws IOException;
+	Set<OBRResolutionMode> getSupportedModes();
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java b/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java
new file mode 100644
index 0000000..78f9801
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/OBRResolutionMode.java
@@ -0,0 +1,6 @@
+package aQute.bnd.service;
+
+@Deprecated
+public enum OBRResolutionMode {
+	build, runtime
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java b/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java
new file mode 100644
index 0000000..065fac8
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/Plugin.java
@@ -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);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java b/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java
new file mode 100644
index 0000000..e5e62e9
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/Refreshable.java
@@ -0,0 +1,8 @@
+package aQute.bnd.service;
+
+import java.io.*;
+
+public interface Refreshable {
+    boolean refresh();
+    File getRoot();
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/Registry.java b/bundleplugin/src/main/java/aQute/bnd/service/Registry.java
new file mode 100755
index 0000000..90fca36
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/Registry.java
@@ -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);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java
new file mode 100644
index 0000000..7a46849
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/RegistryPlugin.java
@@ -0,0 +1,9 @@
+package aQute.bnd.service;
+
+
+/**
+ * A plugin that wants a registry
+ */
+public interface RegistryPlugin {
+	void setRegistry(Registry registry);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java
new file mode 100644
index 0000000..e441a4c
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/RemoteRepositoryPlugin.java
@@ -0,0 +1,20 @@
+package aQute.bnd.service;
+
+import java.io.*;
+import java.util.*;
+
+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;
+	
+	File getCacheDirectory();
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java
new file mode 100644
index 0000000..13899f7
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/RepositoryListenerPlugin.java
@@ -0,0 +1,16 @@
+package aQute.bnd.service;
+
+import java.io.*;
+
+import aQute.lib.osgi.*;
+
+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);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java
new file mode 100644
index 0000000..91b0a7e
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/RepositoryPlugin.java
@@ -0,0 +1,91 @@
+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();
+
+	/**
+	 * Return a location identifier of this repository
+	 */
+
+	String getLocation();
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/ResolutionPhase.java b/bundleplugin/src/main/java/aQute/bnd/service/ResolutionPhase.java
new file mode 100644
index 0000000..0fd7ec9
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/ResolutionPhase.java
@@ -0,0 +1,5 @@
+package aQute.bnd.service;
+
+public enum ResolutionPhase {
+	build, runtime
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java b/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java
new file mode 100644
index 0000000..be7f79b
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/ResourceHandle.java
@@ -0,0 +1,12 @@
+package aQute.bnd.service;
+
+import java.io.*;
+
+public interface ResourceHandle {
+	
+	public enum Location { local, remote_cached, remote }
+	
+	String getName();
+	Location getLocation();
+	File request() throws IOException;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java b/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java
new file mode 100644
index 0000000..2e4e1d3
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/Scripter.java
@@ -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);
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java b/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java
new file mode 100644
index 0000000..aaef646
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/SignerPlugin.java
@@ -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;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java b/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java
new file mode 100644
index 0000000..5167827
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/action/Action.java
@@ -0,0 +1,7 @@
+package aQute.bnd.service.action;
+
+import aQute.bnd.build.*;
+
+public interface Action {
+    void execute( Project project, String action) throws Exception;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java b/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java
new file mode 100644
index 0000000..5a1c697
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/action/NamedAction.java
@@ -0,0 +1,6 @@
+package aQute.bnd.service.action;
+
+
+public interface NamedAction extends Action {
+    String getName();
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo b/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo
new file mode 100644
index 0000000..ec0efd4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/action/packageinfo
@@ -0,0 +1 @@
+version 1.43.1
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/diff/Delta.java b/bundleplugin/src/main/java/aQute/bnd/service/diff/Delta.java
new file mode 100644
index 0000000..eec4781
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/diff/Delta.java
@@ -0,0 +1,19 @@
+package aQute.bnd.service.diff;
+
+/**
+ * The Delta provides information about the {@link Diff} object. It tells the
+ * relation between the newer and older compared elements.
+ * 
+ */
+public enum Delta {
+
+	// ORDER IS IMPORTANT FOR TRANSITIONS TABLE!
+
+	/**
+	 * 
+	 */
+	IGNORED, // for all
+	UNCHANGED, CHANGED, MICRO, MINOR, MAJOR, // content
+	REMOVED, ADDED; // structural
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/diff/Diff.java b/bundleplugin/src/main/java/aQute/bnd/service/diff/Diff.java
new file mode 100644
index 0000000..43bf4e5
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/diff/Diff.java
@@ -0,0 +1,23 @@
+package aQute.bnd.service.diff;
+
+import java.util.*;
+
+public interface Diff {
+	interface Ignore {
+		boolean contains(Diff diff);
+	}
+	
+	Delta getDelta();
+	Delta getDelta(Ignore ignore);
+
+	Type getType();
+	String getName();
+	Tree getOlder();
+	Tree getNewer();
+
+	Collection<? extends Diff> getChildren();
+	
+	Diff get(String name);
+	
+	
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/diff/Differ.java b/bundleplugin/src/main/java/aQute/bnd/service/diff/Differ.java
new file mode 100644
index 0000000..869a237
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/diff/Differ.java
@@ -0,0 +1,13 @@
+package aQute.bnd.service.diff;
+
+import aQute.lib.osgi.*;
+
+/**
+ * Compare two Jars and report the differences.
+ */
+public interface Differ {
+	Tree tree(Analyzer source ) throws Exception;
+	Tree tree(Jar source) throws Exception;
+
+	Tree deserialize(Tree.Data data) throws Exception;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/diff/Tree.java b/bundleplugin/src/main/java/aQute/bnd/service/diff/Tree.java
new file mode 100644
index 0000000..7072ac1
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/diff/Tree.java
@@ -0,0 +1,29 @@
+package aQute.bnd.service.diff;
+
+public interface Tree {
+
+	public class Data {
+		public String	name;
+		public Type		type		= Type.METHOD;
+		public Delta	add			= Delta.MINOR;
+		public Delta	rem			= Delta.MAJOR;
+		public Data[]	children	= null;
+		public String	comment		= null;
+	}
+
+	Data serialize();
+
+	Tree[] getChildren();
+
+	String getName();
+
+	Type getType();
+
+	Delta ifAdded();
+
+	Delta ifRemoved();
+
+	Diff diff(Tree older);
+
+	Tree get(String name);
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/diff/Type.java b/bundleplugin/src/main/java/aQute/bnd/service/diff/Type.java
new file mode 100644
index 0000000..d71b9f4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/diff/Type.java
@@ -0,0 +1,10 @@
+package aQute.bnd.service.diff;
+
+public enum Type {
+	ACCESS, BUNDLE, API, MANIFEST, PACKAGE, CLASS, INTERFACE, ANNOTATION, ENUM, EXTENDS, IMPLEMENTS, FIELD, METHOD, ANNOTATED, PROPERTY, RESOURCE, CUSTOM, CLAUSE, HEADER, PARAMETER, CLASS_VERSION, RESOURCES, CONSTANT, RETURN, VERSION, DEPRECATED;
+
+	public boolean isInherited() {
+		// TODO Auto-generated method stub
+		return false;
+	} 
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/packageinfo b/bundleplugin/src/main/java/aQute/bnd/service/packageinfo
new file mode 100644
index 0000000..0ff7674
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/packageinfo
@@ -0,0 +1 @@
+version 1.45.0
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/url/TaggedData.java b/bundleplugin/src/main/java/aQute/bnd/service/url/TaggedData.java
new file mode 100644
index 0000000..53332f4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/url/TaggedData.java
@@ -0,0 +1,37 @@
+package aQute.bnd.service.url;
+
+import java.io.InputStream;
+
+/**
+ * Represents a data stream that has a tag associated with it; the primary
+ * use-case is an HTTP response stream with an ETag header.
+ * 
+ * @author Neil Bartlett
+ * 
+ */
+public class TaggedData {
+
+	private final String tag;
+	private final InputStream inputStream;
+
+	public TaggedData(String tag, InputStream inputStream) {
+		this.tag = tag;
+		this.inputStream = inputStream;
+	}
+
+	/**
+	 * Returns the ETag for the retrieved resource, or {@code null} if the ETag
+	 * was not provided by the server.
+	 */
+	public String getTag() {
+		return tag;
+	}
+
+	/**
+	 * Returns the input stream containing the resource data.
+	 */
+	public InputStream getInputStream() {
+		return inputStream;
+	}
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/url/URLConnector.java b/bundleplugin/src/main/java/aQute/bnd/service/url/URLConnector.java
new file mode 100644
index 0000000..e853509
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/url/URLConnector.java
@@ -0,0 +1,49 @@
+package aQute.bnd.service.url;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+public interface URLConnector {
+
+	/**
+	 * Connect to the specified URL.
+	 * 
+	 * @param url
+	 * @return
+	 * @throws IOException
+	 */
+	InputStream connect(URL url) throws IOException;
+
+	/**
+	 * Connect to the specified URL, also returning the ETag if available.
+	 * 
+	 * @param url
+	 *            The remote URL.
+	 * @return An instance of {@link TaggedData}; note that the
+	 *         {@link TaggedData#getTag()} method <strong>may</strong> return
+	 *         {@code null} if the resource has no tag.
+	 * @throws IOException
+	 * 
+	 * @since 1.1
+	 */
+	TaggedData connectTagged(URL url) throws IOException;
+
+	/**
+	 * Connect to the specified URL while providing the last known tag for the
+	 * remote resource; the response will be {@code null} if the remote resource
+	 * is unchanged.
+	 * 
+	 * @param url
+	 *            The remote URL.
+	 * @param tag
+	 *            The last known tag value for the resource.
+	 * @return An instance of {@link TaggedData}, or {@code null} if the
+	 *         resource has not modified (i.e., if it has the same tag value).
+	 * @throws IOException
+	 * 
+	 * @since 1.1
+	 */
+	TaggedData connectTagged(URL url, String tag) throws IOException;
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/url/packageinfo b/bundleplugin/src/main/java/aQute/bnd/service/url/packageinfo
new file mode 100644
index 0000000..7ae9673
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/url/packageinfo
@@ -0,0 +1 @@
+version 1.1
\ No newline at end of file