You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ma...@apache.org on 2009/06/27 17:53:26 UTC

svn commit: r788992 [19/25] - in /incubator/ace/trunk: gateway/ gateway/src/ gateway/src/net/ gateway/src/net/luminis/ gateway/src/net/luminis/liq/ gateway/src/net/luminis/liq/bootstrap/ gateway/src/net/luminis/liq/bootstrap/multigateway/ gateway/src/n...

Added: incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,375 @@
+/*
+ * $Id: RepositoryImpl.java 44 2007-07-13 20:49:41Z hargrave@us.ibm.com $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.impl.bundle.obr.resource;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.zip.*;
+
+import org.kxml2.io.KXmlParser;
+import org.osgi.service.obr.*;
+import org.xmlpull.v1.*;
+
+/**
+ * Implements the basic repository. A repository holds a set of resources.
+ * 
+ * 
+ * @version $Revision: 44 $
+ */
+public class RepositoryImpl implements Repository {
+	transient Set			resources		= new HashSet();
+	URL						url;
+	String					date;
+	Set						visited			= new HashSet();
+	final static Resource[]	EMPTY_RESOURCE	= new Resource[0];
+	String					name			= "Untitled";
+	long					lastModified;
+	Exception				exception;
+	int						ranking=0;
+
+	/**
+	 * Each repository is identified by a single URL.
+	 * 
+	 * A repository can hold referrals to other repositories. These referred
+	 * repositories are included at the point of referall.
+	 * 
+	 * @param url
+	 */
+	public RepositoryImpl(URL url) {
+		this.url = url;
+	}
+
+	/**
+	 * Refresh the repository from the URL.
+	 * 
+	 * @throws Exception
+	 */
+	public boolean refresh() {
+		exception = null;
+		try {
+			resources.clear();
+			parseDocument(url);
+			visited = null;
+			return true;
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+			exception = e;
+		}
+		return false;
+	}
+
+	/**
+	 * Parse the repository.
+	 * 
+	 * @param parser
+	 * @throws Exception
+	 */
+	private void parseRepository(XmlPullParser parser) throws Exception {
+		try {
+			parser.require(XmlPullParser.START_DOCUMENT, null, null);
+			parser.nextTag();
+			if (parser.getName().equals("bundles"))
+				parseOscar(parser);
+			else {
+				parser.require(XmlPullParser.START_TAG, null, "repository");
+				date = parser.getAttributeValue(null, "lastmodified");
+				name = parser.getAttributeValue(null, "name");
+				if (name == null)
+					name = "Untitled";
+
+				while (parser.nextTag() == XmlPullParser.START_TAG) {
+					if (parser.getName().equals("resource")) {
+						ResourceImpl resource = new ResourceImpl(this, parser);
+						resources.add(resource);
+					}
+					else if (parser.getName().equals("referral"))
+						referral(parser);
+					else
+						throw new IllegalArgumentException(
+								"Invalid tag in repository: " + url + " "
+										+ parser.getName());
+				}
+				parser.require(XmlPullParser.END_TAG, null, "repository");
+			}
+		}
+		catch (XmlPullParserException e) {
+			e.printStackTrace();
+			throw new IllegalArgumentException("XML unregognized around: "
+					+ e.getLineNumber() + " " + e.getMessage());
+		}
+	}
+
+	/**
+	 * Parse an old style OBR repository.
+	 * 
+	 * <dtd-version>1.0</dtd-version> <repository> <name>Oscar Bundle
+	 * Repository</name> <url>http://oscar-osgi.sourceforge.net/</url>
+	 * <date>Fri May 07 16:45:07 CEST 2004</date> <extern-repositories> <!--
+	 * Stefano Lenzi (kismet@interfree.it) -->
+	 * <url>http://domoware.isti.cnr.it/osgi-obr/niche-osgi-obr.xml</url>
+	 * <!--Manuel Palencia (santillan@dit.upm.es) --> <!--
+	 * <url>http://jmood.forge.os4os.org/repository.xml</url> --> <!-- Enrique
+	 * Rodriguez (erodriguez@apache.org) -->
+	 * <url>http://update.cainenable.org/repository.xml</url>
+	 * </extern-repositories> </repository> <bundle> <bundle-name>Bundle
+	 * Repository</bundle-name> <bundle-description> A bundle repository
+	 * service for Oscar. </bundle-description> <bundle-updatelocation>
+	 * http://oscar-osgi.sf.net/repo/bundlerepository/bundlerepository.jar
+	 * </bundle-updatelocation> <bundle-sourceurl>
+	 * http://oscar-osgi.sf.net/repo/bundlerepository/bundlerepository-src.jar
+	 * </bundle-sourceurl> <bundle-version>1.1.3</bundle-version>
+	 * <bundle-docurl> http://oscar-osgi.sf.net/repo/bundlerepository/
+	 * </bundle-docurl> <bundle-category>General</bundle-category>
+	 * <import-package package="org.osgi.framework"/> <export-package
+	 * package="org.ungoverned.osgi.service.bundlerepository"
+	 * specification-version="1.1.0"/> </bundle> *
+	 */
+	private void parseOscar(XmlPullParser parser) throws Exception {
+		parser.require(XmlPullParser.START_TAG, null, "bundles");
+		while (true) {
+			int event = parser.next();
+
+			// Error ..
+			if (event == XmlPullParser.TEXT)
+				event = parser.next();
+
+			if (event != XmlPullParser.START_TAG)
+				break;
+
+			ResourceImpl resource = new ResourceImpl(this);
+
+			if (parser.getName().equals("bundle")) {
+				while (parser.nextTag() == XmlPullParser.START_TAG) {
+					String key = parser.getName();
+					if (key.equals("import-package")) {
+						RequirementImpl requirement = new RequirementImpl(
+								"package");
+						
+						requirement.setOptional(false);
+						requirement.setMultiple(false);
+						
+						String p = parser.getAttributeValue(null, "package");
+						StringBuffer sb = new StringBuffer();
+						sb.append("(&(package=");
+						sb.append(p);
+						sb.append(")");
+						String version = parser.getAttributeValue(null,
+								"specification-version");
+						VersionRange v = new VersionRange("0");
+						if (version != null) {
+							sb.append("(version=");
+							sb.append(v= new VersionRange(version));
+							sb.append(")");
+						}
+						sb.append(")");
+						requirement.setFilter(sb.toString());
+						requirement.setComment("Import-Package: " + p + ";" + v );
+						resource.addRequirement(requirement);
+						
+						parser.nextTag();
+					}
+					else if (key.equals("export-package")) {
+						CapabilityImpl capability = new CapabilityImpl(
+								"package");
+						capability.addProperty("package", parser
+								.getAttributeValue(null, "package"));
+						String version = parser.getAttributeValue(null,
+								"specification-version");
+						if (version != null) {
+							capability.addProperty("version", new VersionRange(
+									version));
+						}
+						resource.addCapability(capability);
+						parser.nextTag();
+					}
+					else {
+						String value = parser.nextText().trim();
+						if (key.equals("bundle-sourceurl"))
+							resource.setSource(new URL(value));
+						else if (key.equals("bundle-docurl"))
+							resource.setDocumentation(new URL(value));
+						else if (key.equals("bundle-updatelocation"))
+							resource.setURL(new URL(value));
+						else if (key.equals("bundle-description"))
+							resource.setDescription(value);
+						else if (key.equals("bundle-category"))
+							resource.addCategory(value);
+						else if (key.equals("bundle-name")) {
+							resource.setName(value);
+							resource.setPresentationName(value);
+						}
+						else if (key.equals("bundle-version"))
+							resource.setVersion(new VersionRange(value));
+						else {
+							resource.put(key, value);
+						}
+					}
+				}
+				resources.add(resource);
+				parser.require(XmlPullParser.END_TAG, null, "bundle");
+			}
+			else if (parser.getName().equals("repository")) {
+				parser.require(XmlPullParser.START_TAG, null, "repository");
+				while (parser.nextTag() == XmlPullParser.START_TAG) {
+					String tag = parser.getName();
+					if (tag.equals("name")) {
+						String name = parser.nextText();
+						if (this.name == null)
+							this.name = name.trim();
+					}
+					else if (tag.equals("url"))
+						parser.nextText().trim();
+					else if (tag.equals("date"))
+						parser.nextText().trim();
+					else if (tag.equals("extern-repositories")) {
+						parser.require(XmlPullParser.START_TAG, null,
+								"extern-repositories");
+						while (parser.nextTag() == XmlPullParser.START_TAG) {
+							if (parser.getName().equals("url"))
+								parseDocument(new URL(parser.nextText().trim()));
+							else
+								throw new IllegalArgumentException(
+										"Invalid tag in repository while parsing extern repositories: "
+												+ url + " " + parser.getName());
+						}
+						parser.require(XmlPullParser.END_TAG, null,
+								"extern-repositories");
+					}
+					else
+						throw new IllegalArgumentException(
+								"Invalid tag in repository: " + url + " "
+										+ parser.getName());
+				}
+				parser.require(XmlPullParser.END_TAG, null, "repository");
+			}
+			else if (parser.getName().equals("dtd-version")) {
+				parser.nextText();
+			}
+			else
+				throw new IllegalArgumentException(
+						"Invalid tag in repository: " + url + " "
+								+ parser.getName());
+		}
+		parser.require(XmlPullParser.END_TAG, null, "bundles");
+	}
+
+	/**
+	 * We have a referral to another repository. Just create another parser and
+	 * read it inline.
+	 * 
+	 * @param parser
+	 */
+	void referral(XmlPullParser parser) {
+		// TODO handle depth!
+		try {
+			parser.require(XmlPullParser.START_TAG, null, "referral");
+			// String depth = parser.getAttributeValue(null, "depth");
+			String path = parser.getAttributeValue(null, "url");
+			URL url = new URL(this.url, path);
+			parseDocument(url);
+			parser.next();
+			parser.require(XmlPullParser.END_TAG, null, "referral");
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Parse a repository document.
+	 * 
+	 * @param url
+	 * @throws IOException
+	 * @throws XmlPullParserException
+	 * @throws Exception
+	 */
+	void parseDocument(URL url) throws IOException, XmlPullParserException,
+			Exception {
+		if (!visited.contains(url)) {
+			visited.add(url);
+			try {
+				System.out.println("Visiting: " + url);
+				InputStream in = null;
+				
+				if ( url.getPath().endsWith(".zip")) {
+					ZipInputStream zin = new ZipInputStream( url.openStream() );
+					ZipEntry entry = zin.getNextEntry();
+					while ( entry != null ) {
+						if ( entry.getName().equals("repository.xml")) {
+							in = zin;
+							break;
+						}
+						entry = zin.getNextEntry();
+					}
+				} else {
+					in = url.openStream();
+				}
+				Reader reader = new InputStreamReader(in);
+				XmlPullParser parser = new KXmlParser();
+				parser.setInput(reader);
+				parseRepository(parser);
+			} catch( MalformedURLException e ) {
+				System.out.println("Cannot create connection to url");
+			}
+		}
+	}
+
+	public URL getURL() {
+		return url;
+	}
+
+	/**
+	 * @return
+	 */
+	public Collection getResourceList() {
+		return resources;
+	}
+
+	public Resource[] getResources() {
+		return (Resource[]) getResourceList().toArray(EMPTY_RESOURCE);
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public Resource getResource(String id) {
+		for (Iterator i = getResourceList().iterator(); i.hasNext();) {
+			ResourceImpl resource = (ResourceImpl) i.next();
+			if (resource.getId().equals(id))
+				return resource;
+		}
+		return null;
+	}
+
+	public long getLastModified() {
+		return lastModified;
+	}
+
+	public int getRanking() {
+		return ranking;
+	}
+
+	public void setRanking(int ranking) {
+		this.ranking = ranking;
+	}
+
+}

Added: incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RequirementImpl.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RequirementImpl.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RequirementImpl.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/RequirementImpl.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,180 @@
+/*
+ * $Id: RequirementImpl.java 44 2007-07-13 20:49:41Z hargrave@us.ibm.com $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.impl.bundle.obr.resource;
+
+import org.osgi.service.obr.*;
+import org.xmlpull.v1.XmlPullParser;
+
+
+
+/**
+ * Implements the Requirement interface.
+ * 
+ * 
+ * @version $Revision: 44 $
+ */
+public class RequirementImpl implements Requirement {
+	int		id;
+	String	name;
+	String	filter="()";
+	FilterImpl	_filter;
+	String	comment;
+	boolean optional;
+	boolean multiple;
+	boolean extend;
+	
+	/**
+	 * Create a requirement with the given name.
+	 * 
+	 * @param name
+	 */
+	public RequirementImpl(String name) {
+		this.name = name;
+	}
+
+
+	/**
+	 * Parse the requirement from the pull parser.
+	 * 
+	 * @param parser
+	 * @throws Exception
+	 */
+	public RequirementImpl(XmlPullParser parser) throws Exception {
+		parser.require(XmlPullParser.START_TAG, null, null );
+		name = parser.getAttributeValue(null, "name");
+		filter = parser.getAttributeValue(null, "filter");
+		
+		String opt = parser.getAttributeValue(null,"optional");
+		String mul = parser.getAttributeValue(null,"multiple");
+		String ext = parser.getAttributeValue(null,"extend");
+		optional = "true".equalsIgnoreCase(opt);
+		multiple = "true".equalsIgnoreCase(mul);
+		extend = "true".equalsIgnoreCase(ext);
+		
+		
+		StringBuffer sb = new StringBuffer();
+		while ( parser.next() == XmlPullParser.TEXT ) {
+			sb.append( parser.getText() );
+		}
+		if ( sb.length() > 0 )
+			setComment(sb.toString().trim());
+			
+		parser.require(XmlPullParser.END_TAG, null, null );
+	}
+
+	public void setFilter(String filter) {
+		this.filter = filter;
+		_filter= null;
+	}
+
+	public String getFilter() {
+		return filter;
+	}
+
+	public Tag toXML(String name) {
+		Tag tag = toXML(this);
+		tag.rename(name);
+		return tag;
+	}
+
+
+	public String getName() {
+		return name;
+	}
+
+	public boolean isSatisfied(Capability capability) {
+		if (_filter == null)
+			_filter = new FilterImpl(filter);
+
+		boolean result = _filter.match(capability.getProperties());
+		return result;
+	}
+
+	@Override
+    public String toString() {
+		return name + " " + filter;
+	}
+
+
+	public String getComment() {
+		return comment;
+	}
+
+
+	public void setComment(String comment) {
+		this.comment=comment;
+	}
+
+
+	public static Tag toXML(Requirement requirement) {
+		Tag req = new Tag("require");
+		req.addAttribute("name", requirement.getName());
+		req.addAttribute("filter", requirement.getFilter());
+		
+		req.addAttribute("optional", requirement.isOptional()+"");
+		req.addAttribute("multiple", requirement.isMultiple()+"");
+		req.addAttribute("extend", requirement.isExtend()+"");
+		
+		if ( requirement.getComment() != null )
+			req.addContent(requirement.getComment());
+		
+		return req;
+	}
+
+
+	public boolean isMultiple() {
+		return multiple;
+	}
+
+
+	public boolean isOptional() {
+		return optional;
+	}
+
+
+	public void setOptional(boolean b) {
+		optional = b;
+	}
+
+	public void setMultiple(boolean b) {
+		multiple = b;
+	}
+
+
+	@Override
+    public boolean equals(Object o) {
+		if ( ! (o instanceof Requirement) )
+			return false;
+		
+		Requirement r2 = (Requirement)o;
+		return filter.equals(r2.getFilter()) && name.equals(r2.getName()); 
+	}
+	
+	@Override
+    public int hashCode() {
+		return filter.hashCode() ^ name.hashCode();
+	}
+	
+	public boolean isExtend() {
+		return extend;
+	}
+	
+	public void setExtend(boolean extend) {
+		this.extend = extend;
+	}
+}

Added: incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/ResourceImpl.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/ResourceImpl.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/ResourceImpl.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/ResourceImpl.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,384 @@
+/*
+ * $Id: ResourceImpl.java 44 2007-07-13 20:49:41Z hargrave@us.ibm.com $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.impl.bundle.obr.resource;
+
+import java.io.File;
+import java.net.URL;
+import java.util.*;
+
+import org.osgi.framework.Version;
+import org.osgi.service.obr.*;
+import org.xmlpull.v1.XmlPullParser;
+
+public class ResourceImpl implements Resource {
+	List			capabilities	= new ArrayList();
+	List			requirements	= new ArrayList();
+	URL				url;
+	String			symbolicName;
+	VersionRange		version;
+	List			categories		= new ArrayList();
+	long			size			= -1;
+	String			id;
+	static int		ID				= 1;
+	Map				map				= new HashMap();
+	RepositoryImpl	repository;
+	String			presentationName;
+	File			file;
+
+
+	public ResourceImpl(RepositoryImpl repository, String name,
+			VersionRange version) {
+		this.version = version;
+		if ( version == null)
+			this.version = new VersionRange("0");
+		this.symbolicName = name;
+		this.repository = repository;
+	}
+
+	public ResourceImpl(RepositoryImpl repository, XmlPullParser parser)
+			throws Exception {
+		this.repository = repository;
+		parser.require(XmlPullParser.START_TAG, null, "resource");
+		symbolicName = parser.getAttributeValue(null, "symbolicname");
+		if (symbolicName == null)
+			System.err.println("Hey, no symb name! "
+					+ parser.getAttributeValue(null, "uri"));
+
+		map.put(SYMBOLIC_NAME, symbolicName);
+		presentationName = parser.getAttributeValue(null, PRESENTATION_NAME);
+		if (presentationName != null)
+			map.put(PRESENTATION_NAME, presentationName);
+		String v = parser.getAttributeValue(null, "version");
+		if (v == null)
+			setVersion(new VersionRange("0"));
+		else
+			setVersion(new VersionRange(v));
+
+		setURL(toURL(parser.getAttributeValue(null, "uri")));
+
+		while (parser.nextTag() == XmlPullParser.START_TAG) {
+			if (parser.getName().equals("category")) {
+				categories.add(parser.getAttributeValue(null, "id").trim());
+			}
+			else if (parser.getName().equals("require"))
+				addRequirement(new RequirementImpl(parser));
+			else if (parser.getName().equals("capability"))
+				addCapability(new CapabilityImpl(parser));
+			else {
+				String text = parser.nextText();
+				if (text != null)
+					map.put(parser.getName(), text.trim());
+			}
+			parser.next();
+		}
+		parser.require(XmlPullParser.END_TAG, null, "resource");
+	}
+
+	public ResourceImpl(RepositoryImpl impl) {
+		this.repository = impl;
+	}
+
+    public ResourceImpl(RepositoryImpl impl, URL url) {
+        this.repository = impl;
+        setURL(url);
+    }
+    
+	private URL toURL(String attributeValue) throws Exception {
+		if (attributeValue == null)
+			return null;
+
+		return new URL(repository.getURL(), attributeValue);
+	}
+
+	public void addCategory(String category) {
+		categories.add(category);
+	}
+
+	public void addCapability(CapabilityImpl capability) {
+		if (capability != null)
+			capabilities.add(capability);
+	}
+
+	public void addRequirement(RequirementImpl requirement) {
+		if (requirement != null)
+			requirements.add(requirement);
+	}
+
+	public void setLicense(URL license) {
+		if (license != null)
+			map.put(LICENSE_URL, license);
+	}
+
+	public String getDescription() {
+		return (String) map.get(DESCRIPTION);
+	}
+
+	public void setDescription(String description) {
+		if (description != null)
+			map.put(DESCRIPTION, description);
+	}
+
+	public Capability[] getCapabilities() {
+		return (Capability[]) capabilities.toArray(new Capability[capabilities
+				.size()]);
+	}
+
+	public URL getLicense() {
+		return (URL) map.get(LICENSE_URL);
+	}
+
+	public String getSymbolicName() {
+		return symbolicName;
+	}
+
+	public Requirement[] getRequirements() {
+		return (Requirement[]) requirements
+				.toArray(new Requirement[requirements.size()]);
+	}
+
+	public Tag toXML() {
+		return toXML(this );
+	}
+
+	public static Tag toXML(Resource resource) {
+		return toXML(resource,true);
+	}
+
+	public static Tag toXML(Resource resource, boolean relative ) {
+		Tag meta = new Tag("resource");
+		URL url = resource.getURL();
+		String urlString = url.toExternalForm();
+		
+		if ( relative )
+			urlString = makeRelative(resource.getRepository().getURL(), url);
+		
+		meta.addAttribute("uri", urlString );
+		if (urlString.endsWith(".jar")) {
+		    meta.addAttribute(SYMBOLIC_NAME, resource.getSymbolicName());
+		    if (resource.getPresentationName() != null)
+		        meta
+		        .addAttribute(PRESENTATION_NAME, resource
+		                .getPresentationName());
+		    meta.addAttribute(VERSION, resource.getVersion().toString());
+		    meta.addAttribute("id", resource.getId());
+		    Map map = new TreeMap(resource.getProperties());
+		    for (int i = 0; i < Resource.KEYS.length; i++) {
+		        String key = KEYS[i];
+		        if (!(key.equals(URL) || key.equals(SYMBOLIC_NAME) || key
+		                .equals(VERSION) || key.equals(PRESENTATION_NAME))) {
+		            Object value = map.get(KEYS[i]);
+		            if (value != null) {
+		                if (value instanceof URL)
+		                    value = makeRelative(resource.getRepository().getURL(),(URL) value);
+		                meta.addContent(new Tag(key, value.toString()));
+		            }
+		        }
+		    }
+
+		    String[] categories = resource.getCategories();
+		    for (int i = 0; i < categories.length; i++) {
+		        String category = categories[i];
+		        meta.addContent(new Tag("category", new String[] {"id",
+		                category.toLowerCase()}));
+		    }
+
+		    Capability[] capabilities = resource.getCapabilities();
+		    for (int i = 0; i < capabilities.length; i++) {
+		        meta.addContent(CapabilityImpl.toXML(capabilities[i]));
+		    }
+
+		    Requirement[] requirements = resource.getRequirements();
+		    for (int i = 0; i < requirements.length; i++) {
+		        meta.addContent(RequirementImpl.toXML(requirements[i]));
+		    }
+		}
+		return meta;
+	}
+
+	public URL getURL() {
+		return url;
+	}
+
+	static String makeRelative(URL repository, URL url) {
+		try {
+			if (repository != null) {
+				String a = url.toExternalForm();
+				String b = repository.toExternalForm();
+				int index = b.lastIndexOf('/');
+				if ( index > 0 )
+					b = b.substring(0,index+1);
+				if (a.startsWith(b))
+					return a.substring(b.length());
+			}
+		}
+		catch (Exception e) {
+			// Ignore
+		}
+		return url.toExternalForm();
+	}
+
+	public void setURL(URL url) {
+		this.url = url;
+		if (url != null)
+			map.put(URL, url);
+	}
+	
+	public String getCopyright() {
+		return (String) map.get(COPYRIGHT);
+	}
+
+	public Version getVersion() {
+		if (version == null)
+			version = new VersionRange("0");
+		return version.low;
+	}
+
+	void setVersion(VersionRange version) {
+		if (version == null)
+			this.version = new VersionRange("0");
+		else
+			this.version = version;
+	}
+
+	public void setCopyright(String copyright) {
+		if (copyright != null)
+			map.put(COPYRIGHT, copyright);
+	}
+
+	public URL getDocumentation() {
+		return (URL) map.get(DOCUMENTATION_URL);
+	}
+
+	public void setDocumentation(URL documentation) {
+		if (documentation != null)
+			map.put(DOCUMENTATION_URL, documentation);
+	}
+
+	public URL getSource() {
+		return (URL) map.get(SOURCE_URL);
+	}
+
+	public void setSource(URL source) {
+		if (source != null)
+			map.put(SOURCE_URL, source);
+	}
+
+	public boolean satisfies(RequirementImpl requirement) {
+		for (Iterator i = capabilities.iterator(); i.hasNext();) {
+			CapabilityImpl capability = (CapabilityImpl) i.next();
+			if (requirement.isSatisfied(capability))
+				return true;
+		}
+		return false;
+	}
+
+	@Override
+    public String toString() {
+		return symbolicName + "-" + version;
+	}
+
+	public long getSize() {
+		return size;
+	}
+
+	public void setSize(long size) {
+		this.size = size;
+		map.put(SIZE, new Long(size));
+	}
+
+	public Collection getRequirementList() {
+		return requirements;
+	}
+
+	public Collection getCapabilityList() {
+		return capabilities;
+	}
+
+	@Override
+    public int hashCode() {
+	    if (url.toExternalForm().endsWith(".jar")) {
+	        return symbolicName.hashCode() ^ version.hashCode();
+	    }
+	    else {
+	        return url.hashCode();
+	    }
+	}
+
+	@Override
+    public boolean equals(Object o) {
+		try {
+			ResourceImpl other = (ResourceImpl) o;
+			return symbolicName.equals(other.symbolicName)
+					&& version.equals(other.version);
+		}
+		catch (ClassCastException e) {
+			return false;
+		}
+	}
+
+	public String[] getCategories() {
+		return (String[]) categories.toArray(new String[categories.size()]);
+	}
+
+	public Map getProperties() {
+		return Collections.unmodifiableMap(map);
+	}
+
+	public synchronized String getId() {
+		if ( id == null )
+			id = symbolicName + "/" + version;
+		return id;
+	}
+
+	public Repository getRepository() {
+		return repository;
+	}
+
+	void setName(String value) {
+		this.symbolicName = value;
+	}
+
+	void put(String name, Object value) {
+		map.put(name, value);
+	}
+
+	public void setPresentationName(String name) {
+		presentationName = name;
+		if (name != null)
+			map.put(PRESENTATION_NAME, name);
+	}
+
+	public String getPresentationName() {
+		return presentationName;
+	}
+
+	public void setFile(File zipFile) {
+		file = zipFile;
+	}
+
+	public Set getExtendList() {
+		Set set = new HashSet();
+		for (Iterator i = requirements.iterator(); i.hasNext();) {
+			RequirementImpl	impl = (RequirementImpl) i.next();
+			if ( impl.isExtend())
+				set.add(impl);
+		}
+		return set;
+	}
+
+}

Added: incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/StringSet.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/StringSet.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/StringSet.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/StringSet.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,32 @@
+/*
+ * $Id: StringSet.java 44 2007-07-13 20:49:41Z hargrave@us.ibm.com $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.osgi.impl.bundle.obr.resource;
+
+import java.util.*;
+
+public class StringSet extends HashSet {
+	static final long	serialVersionUID	= 1L;
+
+	public StringSet(String set) {
+		StringTokenizer st = new StringTokenizer(set, ",");
+		while (st.hasMoreTokens())
+			add(st.nextToken().trim());
+	}
+}

Added: incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/Tag.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/Tag.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/Tag.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/Tag.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,489 @@
+/*
+ * $Id: Tag.java 44 2007-07-13 20:49:41Z hargrave@us.ibm.com $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.osgi.impl.bundle.obr.resource;
+
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * The Tag class represents a minimal XML tree. It consist of a named element
+ * with a hashtable of named attributes. Methods are provided to walk the tree
+ * and get its constituents. The content of a Tag is a list that contains String
+ * objects or other Tag objects.
+ */
+public class Tag {
+	Tag						parent;
+	String					name;
+	Map						attributes	= new TreeMap();
+	Vector					content		= new Vector();
+
+	static SimpleDateFormat	format		= new SimpleDateFormat(
+												"yyyyMMddhhmmss.SSS");
+
+	/**
+	 * Construct a new Tag with a name.
+	 */
+	public Tag(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Construct a new Tag with a name.
+	 */
+	public Tag(String name, Map attributes) {
+		this.name = name;
+		this.attributes = attributes;
+	}
+
+	/**
+	 * Construct a new Tag with a name and a set of attributes. The attributes
+	 * are given as ( name, value ) ...
+	 */
+	public Tag(String name, String[] attributes) {
+		this.name = name;
+		for (int i = 0; i < attributes.length; i += 2)
+			addAttribute(attributes[i], attributes[i + 1]);
+	}
+
+	/**
+	 * Construct a new Tag with a single string as content.
+	 */
+	public Tag(String name, String content) {
+		this.name = name;
+		addContent(content);
+	}
+
+	/**
+	 * Add a new attribute.
+	 */
+	public void addAttribute(String key, String value) {
+		attributes.put(key, value);
+	}
+
+	/**
+	 * Add a new attribute.
+	 */
+	public void addAttribute(String key, Object value) {
+		if (value == null)
+			return;
+		attributes.put(key, value.toString());
+	}
+
+	/**
+	 * Add a new attribute.
+	 */
+	public void addAttribute(String key, int value) {
+		attributes.put(key, Integer.toString(value));
+	}
+
+	/**
+	 * Add a new date attribute. The date is formatted as the SimpleDateFormat
+	 * describes at the top of this class.
+	 */
+	public void addAttribute(String key, Date value) {
+		attributes.put(key, format.format(value));
+	}
+
+	/**
+	 * Add a new content string.
+	 */
+	public void addContent(String string) {
+		content.addElement(string);
+	}
+
+	/**
+	 * Add a new content tag.
+	 */
+	public void addContent(Tag tag) {
+		content.addElement(tag);
+		tag.parent = this;
+	}
+
+	/**
+	 * Return the name of the tag.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Return the attribute value.
+	 */
+	public String getAttribute(String key) {
+		return (String) attributes.get(key);
+	}
+
+	/**
+	 * Return the attribute value or a default if not defined.
+	 */
+	public String getAttribute(String key, String deflt) {
+		String answer = getAttribute(key);
+		return answer == null ? deflt : answer;
+	}
+
+	/**
+	 * Answer the attributes as a Dictionary object.
+	 */
+	public Map getAttributes() {
+		return attributes;
+	}
+
+	/**
+	 * Return the contents.
+	 */
+	public Vector getContents() {
+		return content;
+	}
+
+	/**
+	 * Return a string representation of this Tag and all its children
+	 * recursively.
+	 */
+	@Override
+    public String toString() {
+		StringWriter sw = new StringWriter();
+		print(0, new PrintWriter(sw));
+		return sw.toString();
+	}
+
+	/**
+	 * Return only the tags of the first level of descendants that match the
+	 * name.
+	 */
+	public Vector getContents(String tag) {
+		Vector out = new Vector();
+		for (Enumeration e = content.elements(); e.hasMoreElements();) {
+			Object o = e.nextElement();
+			if (o instanceof Tag && ((Tag) o).getName().equals(tag))
+				out.addElement(o);
+		}
+		return out;
+	}
+
+	/**
+	 * Return the whole contents as a String (no tag info and attributes).
+	 */
+	public String getContentsAsString() {
+		StringBuffer sb = new StringBuffer();
+		getContentsAsString(sb);
+		return sb.toString();
+	}
+
+	/**
+	 * convenient method to get the contents in a StringBuffer.
+	 */
+	public void getContentsAsString(StringBuffer sb) {
+		for (Enumeration e = content.elements(); e.hasMoreElements();) {
+			Object o = e.nextElement();
+			if (o instanceof Tag)
+				((Tag) o).getContentsAsString(sb);
+			else
+				sb.append(o.toString());
+		}
+	}
+
+	/**
+	 * Print the tag formatted to a PrintWriter.
+	 */
+	public void print(int indent, PrintWriter pw) {
+		pw.print("\n");
+		spaces(pw, indent);
+		pw.print('<');
+		pw.print(name);
+
+		for (Iterator e = attributes.keySet().iterator(); e.hasNext();) {
+			String key = (String) e.next();
+			String value = escape((String) attributes.get(key));
+			pw.print(' ');
+			pw.print(key);
+			pw.print("=");
+			String quote = "'";
+			if (value.indexOf(quote) >= 0)
+				quote = "\"";
+			pw.print(quote);
+			pw.print(value);
+			pw.print(quote);
+		}
+
+		if (content.size() == 0)
+			pw.print('/');
+		else {
+			pw.print('>');
+			for (Enumeration e = content.elements(); e.hasMoreElements();) {
+				Object content = e.nextElement();
+				if (content instanceof String) {
+					formatted(pw, indent + 2, 60, escape((String) content));
+				}
+				else if (content instanceof Tag) {
+					Tag tag = (Tag) content;
+					tag.print(indent + 2, pw);
+				}
+			}
+			pw.print("\n");
+			spaces(pw, indent);
+			pw.print("</");
+			pw.print(name);
+		}
+		pw.print('>');
+	}
+
+	/**
+	 * Convenience method to print a string nicely and does character conversion
+	 * to entities.
+	 */
+	void formatted(PrintWriter pw, int left, int width, String s) {
+		int pos = width + 1;
+		s = s.trim();
+
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+			if (i == 0 || (Character.isWhitespace(c) && pos > width - 3)) {
+				pw.print("\n");
+				spaces(pw, left);
+				pos = 0;
+			}
+			switch (c) {
+				case '<' :
+					pw.print("&lt;");
+					pos += 4;
+					break;
+				case '>' :
+					pw.print("&gt;");
+					pos += 4;
+					break;
+				case '&' :
+					pw.print("&amp;");
+					pos += 5;
+					break;
+				default :
+					pw.print(c);
+					pos++;
+					break;
+			}
+
+		}
+	}
+
+	/**
+	 * Escape a string, do entity conversion.
+	 */
+	String escape(String s) {
+		if  ( s == null )
+			return "?null?";
+		
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+			switch (c) {
+				case '<' :
+					sb.append("&lt;");
+					break;
+				case '>' :
+					sb.append("&gt;");
+					break;
+				case '&' :
+					sb.append("&amp;");
+					break;
+				default :
+					sb.append(c);
+					break;
+			}
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * Make spaces.
+	 */
+	void spaces(PrintWriter pw, int n) {
+		while (n-- > 0)
+			pw.print(' ');
+	}
+
+	/**
+	 * root/preferences/native/os
+	 */
+	public Tag[] select(String path) {
+		return select(path, (Tag) null);
+	}
+
+	public Tag[] select(String path, Tag mapping) {
+		Vector v = new Vector();
+		select(path, v, mapping);
+		Tag[] result = new Tag[v.size()];
+		v.copyInto(result);
+		return result;
+	}
+
+	void select(String path, Vector results, Tag mapping) {
+		if (path.startsWith("//")) {
+			int i = path.indexOf('/', 2);
+			String name = path.substring(2, i < 0 ? path.length() : i);
+
+			for (Enumeration e = content.elements(); e.hasMoreElements();) {
+				Object o = e.nextElement();
+				if (o instanceof Tag) {
+					Tag child = (Tag) o;
+					if (match(name, child, mapping))
+						results.add(child);
+					child.select(path, results, mapping);
+				}
+
+			}
+			return;
+		}
+
+		if (path.length() == 0) {
+			results.addElement(this);
+			return;
+		}
+
+		int i = path.indexOf("/");
+		String elementName = path;
+		String remainder = "";
+		if (i > 0) {
+			elementName = path.substring(0, i);
+			remainder = path.substring(i + 1);
+		}
+
+		for (Enumeration e = content.elements(); e.hasMoreElements();) {
+			Object o = e.nextElement();
+			if (o instanceof Tag) {
+				Tag child = (Tag) o;
+				if (child.getName().equals(elementName)
+						|| elementName.equals("*"))
+					child.select(remainder, results, mapping);
+			}
+		}
+	}
+
+	public boolean match(String search, Tag child, Tag mapping) {
+		String target = child.getName();
+		String sn = null;
+		String tn = null;
+
+		if (search.equals("*"))
+			return true;
+
+		int s = search.indexOf(':');
+		if (s > 0) {
+			sn = search.substring(0, s);
+			search = search.substring(s + 1);
+		}
+		int t = target.indexOf(':');
+		if (t > 0) {
+			tn = target.substring(0, t);
+			target = target.substring(t + 1);
+		}
+
+		if (!search.equals(target)) // different tag names
+			return false;
+
+		if (mapping == null) {
+			return tn == sn || (sn != null && sn.equals(tn));
+		}
+		else {
+			String suri = sn == null ? mapping.getAttribute("xmlns") : mapping
+					.getAttribute("xmlns:" + sn);
+			String turi = tn == null ? child.findRecursiveAttribute("xmlns")
+					: child.findRecursiveAttribute("xmlns:" + tn);
+			return turi == suri
+					|| (turi != null && suri != null && turi.equals(suri));
+		}
+	}
+
+	public String getString(String path) {
+		String attribute = null;
+		int index = path.indexOf("@");
+		if (index >= 0) {
+			// attribute
+			attribute = path.substring(index + 1);
+
+			if (index > 0) {
+				// prefix path
+				path = path.substring(index - 1); // skip -1
+			}
+			else
+				path = "";
+		}
+		Tag tags[] = select(path);
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < tags.length; i++) {
+			if (attribute == null)
+				tags[i].getContentsAsString(sb);
+			else
+				sb.append(tags[i].getAttribute(attribute));
+		}
+		return sb.toString();
+	}
+
+	public String getStringContent() {
+		StringBuffer sb = new StringBuffer();
+		for (Enumeration e = content.elements(); e.hasMoreElements();) {
+			Object c = e.nextElement();
+			if (!(c instanceof Tag))
+				sb.append(c);
+		}
+		return sb.toString();
+	}
+
+	public String getNameSpace() {
+		return getNameSpace(name);
+	}
+
+	public String getNameSpace(String name) {
+		int index = name.indexOf(':');
+		if (index > 0) {
+			String ns = name.substring(0, index);
+			return findRecursiveAttribute("xmlns:" + ns);
+		}
+		else
+			return findRecursiveAttribute("xmlns");
+	}
+
+	public String findRecursiveAttribute(String name) {
+		String value = getAttribute(name);
+		if (value != null)
+			return value;
+		if (parent != null)
+			return parent.findRecursiveAttribute(name);
+		return null;
+	}
+
+	public String getLocalName() {
+		int index = name.indexOf(':');
+		if (index <= 0)
+			return name;
+
+		return name.substring(index + 1);
+	}
+
+	public void rename(String string) {
+		name = string;
+	}
+
+
+	public static void convert( Collection c, String type, Tag parent ) {
+		for ( Iterator i=c.iterator(); i.hasNext(); ) {
+			Map	map = (Map) i.next();
+			parent.addContent( new Tag(type, map) );
+		}
+	}
+
+}

Added: incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/VersionRange.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/VersionRange.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/VersionRange.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/impl/bundle/obr/resource/VersionRange.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,122 @@
+/*
+ * $Id: VersionRange.java 46 2008-01-17 19:05:21Z peter.kriens@aqute.biz $
+ * 
+ * Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.impl.bundle.obr.resource;
+
+import java.util.regex.*;
+
+import org.osgi.framework.*;
+
+public class VersionRange implements Comparable {
+	Version high;
+	Version low;
+	char start = '[';
+	char end = ']';
+
+	static String V = "[0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[a-zA-Z0-9_-]+)?)?)?";
+	static Pattern RANGE = Pattern.compile("(\\(|\\[)\\s*(" + V + ")\\s*,\\s*(" + V
+			+ ")\\s*(\\)|\\])");
+
+	public VersionRange(String string) {
+		string = string.trim();
+		Matcher m = RANGE.matcher(string);
+		if (m.matches()) {
+			start = m.group(1).charAt(0);
+			low = new Version(m.group(2));
+			high = new Version(m.group(6));
+			end = m.group(10).charAt(0);
+			if (low.compareTo(high) >= 0)
+				throw new IllegalArgumentException(
+						"Low Range is higher than High Range: " + low + "-"
+								+ high);
+
+		} else
+			high = low = new Version(string);
+	}
+
+	public boolean isRange() {
+		return high != low;
+	}
+
+	public boolean includeLow() {
+		return start == '[';
+	}
+
+	public boolean includeHigh() {
+		return end == ']';
+	}
+
+	@Override
+    public String toString() {
+		if (high == low)
+			return high.toString();
+
+		StringBuffer sb = new StringBuffer();
+		sb.append(start);
+		sb.append(low);
+		sb.append(',');
+		sb.append(high);
+		sb.append(end);
+		return sb.toString();
+	}
+
+	@Override
+    public boolean equals(Object other) {
+		if (other instanceof VersionRange) {
+			return compareTo(other)==0;
+		}
+		return false;
+	}
+
+	@Override
+    public int hashCode() {
+		return low.hashCode() * high.hashCode();
+	}
+
+	public int compareTo(Object other) {
+		VersionRange range = (VersionRange) other;
+		VersionRange a = this, b = range;
+		if (range.isRange()) {
+			a = range;
+			b = this;
+		} else {
+			if ( !isRange() )
+				return low.compareTo(range.high);
+		}
+		int l = a.low.compareTo(b.low);
+		boolean ll = false;
+		if (a.includeLow())
+			ll = l <= 0;
+		else
+			ll = l < 0;
+
+		if (!ll)
+			return -1;
+
+		int h = a.high.compareTo(b.high);
+		if (a.includeHigh())
+			ll = h >= 0;
+		else
+			ll = h > 0;
+
+		if (ll)
+			return 0;
+		else
+			return 1;
+	}
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/Capability.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/Capability.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/Capability.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/Capability.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,48 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Capability.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+import java.util.Map;
+
+/**
+ * A named set of properties representing some capability that is provided by
+ * its owner.
+ * 
+ * @version $Revision: 1.3 $
+ */
+public interface Capability
+{
+    /**
+     * Return the name of the capability.
+     * 
+     */
+    String getName();
+
+    /**
+     * Return the set of properties.
+     * 
+     * Notice that the value of the properties is a list of values.
+     * 
+     * @return a Map<String,List>
+     */
+    Map getProperties();
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/CapabilityProvider.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/CapabilityProvider.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/CapabilityProvider.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/CapabilityProvider.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,49 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/CapabilityProvider.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+/**
+ * This service interface allows third parties to provide capabilities that are
+ * present on the system but not encoded in the bundle's manifests. For example,
+ * a capability provider could provide:
+ * <ol>
+ * <li>A Set of certificates</li>
+ * <li>Dimensions of the screen</li>
+ * <li>Amount of memory</li>
+ * <li>...</li>
+ * </ol>
+ * 
+ * @version $Revision: 1.3 $
+ */
+public interface CapabilityProvider
+{
+    /**
+     * Return a set of capabilities.
+     * 
+     * These capabilities are considered part of the platform. Bundles can
+     * require these capabilities during selection. All capabilities from
+     * different providers are considered part of the platform.
+     * 
+     * @return Set of capabilities
+     */
+    Capability[] getCapabilities();
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/Repository.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/Repository.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/Repository.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/Repository.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,53 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Repository.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+import java.net.URL;
+
+/**
+ * Represents a repository.
+ * 
+ * @version $Revision: 1.3 $
+ */
+public interface Repository
+{
+    /**
+     * Return the associated URL for the repository.
+     * 
+     */
+    URL getURL();
+
+    /**
+     * Return the resources for this repository.
+     */
+    Resource[] getResources();
+
+    /**
+     * Return the name of this reposotory.
+     * 
+     * @return a non-null name
+     */
+    String getName();
+
+    long getLastModified();
+
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryAdmin.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryAdmin.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryAdmin.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryAdmin.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,104 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/RepositoryAdmin.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+import java.net.URL;
+
+/**
+ * Provides centralized access to the distributed repository.
+ * 
+ * A repository contains a set of <i>resources</i>. A resource contains a
+ * number of fixed attributes (name, version, etc) and sets of:
+ * <ol>
+ * <li>Capabilities - Capabilities provide a named aspect: a bundle, a display,
+ * memory, etc.</li>
+ * <li>Requirements - A named filter expression. The filter must be satisfied
+ * by one or more Capabilties with the given name. These capabilities can come
+ * from other resources or from the platform. If multiple resources provide the
+ * requested capability, one is selected. (### what algorithm? ###)</li>
+ * <li>Requests - Requests are like requirements, except that a request can be
+ * fullfilled by 0..n resources. This feature can be used to link to resources
+ * that are compatible with the given resource and provide extra functionality.
+ * For example, a bundle could request all its known fragments. The UI
+ * associated with the repository could list these as optional downloads.</li>
+ * 
+ * @version $Revision: 1.3 $
+ */
+public interface RepositoryAdmin
+{
+    /**
+     * Discover any resources that match the given filter.
+     * 
+     * This is not a detailed search, but a first scan of applicable resources.
+     * 
+     * ### Checking the capabilities of the filters is not possible because that
+     * requires a new construct in the filter.
+     * 
+     * The filter expression can assert any of the main headers of the resource.
+     * The attributes that can be checked are:
+     * 
+     * <ol>
+     * <li>name</li>
+     * <li>version (uses filter matching rules)</li>
+     * <li>description</li>
+     * <li>category</li>
+     * <li>copyright</li>
+     * <li>license</li>
+     * <li>source</li>
+     * </ol>
+     * 
+     * @param filterExpr
+     *            A standard OSGi filter
+     * @return List of resources matching the filters.
+     */
+    Resource[] discoverResources(String filterExpr);
+
+    /**
+     * Create a resolver.
+     * 
+     * @param resource
+     * @return
+     */
+    Resolver resolver();
+
+    /**
+     * Add a new repository to the federation.
+     * 
+     * The url must point to a repository XML file.
+     * 
+     * @param repository
+     * @return
+     * @throws Exception
+     */
+    Repository addRepository(URL repository) throws Exception;
+
+    boolean removeRepository(URL repository);
+
+    /**
+     * List all the repositories.
+     * 
+     * @return
+     */
+    Repository[] listRepositories();
+
+    Resource getResource(String respositoryId);
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryPermission.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryPermission.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryPermission.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/RepositoryPermission.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,40 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/RepositoryPermission.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+import java.security.BasicPermission;
+
+/**
+ * TODO OBR - Implement repository permission.
+ * 
+ * @version $Revision: 1.3 $
+ */
+public class RepositoryPermission extends BasicPermission
+{
+
+    public RepositoryPermission(String name)
+    {
+        super(name);
+
+    }
+
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/Requirement.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/Requirement.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/Requirement.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/Requirement.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,53 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Requirement.java,v 1.4 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+/**
+ * A named requirement specifies the need for certain capabilities with the same
+ * name.
+ * 
+ * @version $Revision: 1.4 $
+ */
+public interface Requirement
+{
+
+    /**
+     * Return the name of the requirement.
+     */
+    String getName();
+
+    /**
+     * Return the filter.
+     * 
+     */
+    String getFilter();
+
+    boolean isMultiple();
+
+    boolean isOptional();
+
+    boolean isExtend();
+
+    String getComment();
+
+    boolean isSatisfied(Capability capability);
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/Resolver.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/Resolver.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/Resolver.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/Resolver.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,44 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Resolver.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+public interface Resolver
+{
+
+    void add(Resource resource);
+
+    Requirement[] getUnsatisfiedRequirements();
+
+    Resource[] getOptionalResources();
+
+    Requirement[] getReason(Resource resource);
+
+    Resource[] getResources(Requirement requirement);
+
+    Resource[] getRequiredResources();
+
+    Resource[] getAddedResources();
+
+    boolean resolve();
+
+    void deploy(boolean start);
+}
\ No newline at end of file

Added: incubator/ace/trunk/server/src/org/osgi/service/obr/Resource.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/server/src/org/osgi/service/obr/Resource.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/server/src/org/osgi/service/obr/Resource.java (added)
+++ incubator/ace/trunk/server/src/org/osgi/service/obr/Resource.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,86 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Resource.java,v 1.5 2006/03/16 14:56:17 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This document is an experimental draft to enable interoperability
+// between bundle repositories. There is currently no commitment to 
+// turn this draft into an official specification.  
+package org.osgi.service.obr;
+
+import java.net.URL;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+
+/**
+ * A resource is an abstraction of a downloadable thing, like a bundle.
+ * 
+ * Resources have capabilities and requirements. All a resource's requirements
+ * must be satisfied before it can be installed.
+ * 
+ * @version $Revision: 1.5 $
+ */
+public interface Resource
+{
+    final String LICENSE_URL = "license";
+
+    final String DESCRIPTION = "description";
+
+    final String DOCUMENTATION_URL = "documentation";
+
+    final String COPYRIGHT = "copyright";
+
+    final String SOURCE_URL = "source";
+
+    final String SYMBOLIC_NAME = "symbolicname";
+
+    final String PRESENTATION_NAME = "presentationname";
+
+    final String ID = "id";
+
+    final String VERSION = "version";
+
+    final String URL = "url";
+
+    final String SIZE = "size";
+
+    final static String[] KEYS = { DESCRIPTION, SIZE, ID, LICENSE_URL,
+            DOCUMENTATION_URL, COPYRIGHT, SOURCE_URL, PRESENTATION_NAME,
+            SYMBOLIC_NAME, VERSION, URL };
+
+    // get readable name
+
+    Map getProperties();
+
+    String getSymbolicName();
+
+    String getPresentationName();
+
+    Version getVersion();
+
+    String getId();
+
+    URL getURL();
+
+    Requirement[] getRequirements();
+
+    Capability[] getCapabilities();
+
+    String[] getCategories();
+
+    Repository getRepository();
+}
\ No newline at end of file

Added: incubator/ace/trunk/test/ext/cobertura/asm-2.2.1.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/cobertura/asm-2.2.1.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/cobertura/asm-2.2.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/cobertura/asm-tree-2.2.1.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/cobertura/asm-tree-2.2.1.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/cobertura/asm-tree-2.2.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/cobertura/cobertura.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/cobertura/cobertura.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/cobertura/cobertura.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/cobertura/jakarta-oro-2.0.8.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/cobertura/jakarta-oro-2.0.8.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/cobertura/jakarta-oro-2.0.8.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/cobertura/log4j-1.2.9.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/cobertura/log4j-1.2.9.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/cobertura/log4j-1.2.9.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/commons/commons-cli-1.1.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/commons/commons-cli-1.1.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/commons/commons-cli-1.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/easymock.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/easymock.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/easymock.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/ext/testng-5.5-jdk15.jar
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/ext/testng-5.5-jdk15.jar?rev=788992&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/ace/trunk/test/ext/testng-5.5-jdk15.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/AdminTestUtil.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/AdminTestUtil.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/AdminTestUtil.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/AdminTestUtil.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,35 @@
+package net.luminis.liq.client.repository.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class AdminTestUtil {
+
+    public static byte[] copy(InputStream in) throws IOException {
+        byte[] result = new byte[in.available()];
+        in.read(result);
+        return result;
+    }
+
+    public static boolean byteArraysEqual(byte[] left, byte[] right) {
+        if (left.length != right.length) {
+            return false;
+        }
+        for (int i = 0; i < right.length; i++) {
+            if (left[i] != right[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static byte[] copy(byte[] input) {
+        byte[] result = new byte[input.length];
+        for (int i = 0; i < input.length; i++) {
+            result[i] = input[i];
+        }
+        return result;
+    }
+
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/ArtifactTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/ArtifactTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/ArtifactTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/ArtifactTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,165 @@
+package net.luminis.liq.client.repository.impl;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.luminis.liq.client.repository.helper.ArtifactHelper;
+import net.luminis.liq.client.repository.helper.ArtifactPreprocessor;
+import net.luminis.liq.client.repository.helper.bundle.BundleHelper;
+import net.luminis.liq.client.repository.helper.bundle.impl.BundleHelperImpl;
+import net.luminis.liq.client.repository.object.ArtifactObject;
+import net.luminis.liq.test.utils.TestUtils;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Tests the behavior of the ArtifactObject class, most prominently, checking whether
+ * delegation to the Helpers is done at the right moments.
+ */
+public class ArtifactTest {
+
+    private ArtifactRepositoryImpl m_artifactRepository;
+
+    @BeforeMethod(alwaysRun = true)
+    public void init() {
+        BundleContext bc = TestUtils.createMockObjectAdapter(BundleContext.class, new Object() {
+            @SuppressWarnings("unused")
+            public Filter createFilter(String filter) throws InvalidSyntaxException {
+                return new org.apache.felix.framework.FilterImpl(filter);
+            }
+        });
+
+        m_artifactRepository = new ArtifactRepositoryImpl(TestUtils.createNullObject(ChangeNotifier.class));
+        TestUtils.configureObject(m_artifactRepository, LogService.class);
+        TestUtils.configureObject(m_artifactRepository, BundleContext.class, bc);
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testAttributeChecking() {
+        ArtifactHelper helper = new MockHelper("yourURL");
+
+        try {
+            createArtifact("myMime", "myUrl", null, null);
+            assert false : "There is no helper for this type of artifact.";
+        }
+        catch (IllegalArgumentException iae) {
+            // expected
+        }
+
+        m_artifactRepository.addHelper("myMime", helper);
+
+        ArtifactObject obj = createArtifact("myMime", "myUrl", null, null);
+
+        assert obj.getURL().equals("yourURL");
+
+        try {
+            m_artifactRepository.getHelper("yourMime");
+            assert false : "We have not registered this helper.";
+        }
+        catch (IllegalArgumentException iae) {
+            // expected
+        }
+    }
+
+    @Test( groups = { TestUtils.UNIT } )
+    public void testResourceProcessorFiltering() throws InvalidSyntaxException {
+        m_artifactRepository.addHelper("myMime", new MockHelper());
+        m_artifactRepository.addHelper(BundleHelper.MIMETYPE, new BundleHelperImpl());
+
+        ArtifactObject normalBundle = createArtifact(BundleHelper.MIMETYPE, "normalBundle", "normalBundle", null);
+
+        ArtifactObject resourceProcessor1 = createArtifact(BundleHelper.MIMETYPE, "resourceProcessor1", "resourceProcessor1", "somePID");
+        ArtifactObject resourceProcessor2 = createArtifact(BundleHelper.MIMETYPE, "resourceProcessor2", "resourceProcessor2", "someOtherPID");
+
+        ArtifactObject myArtifact = createArtifact("myMime", "myArtifact", null, null);
+
+        assert m_artifactRepository.get().size() == 2 : "We expect to find two artifacts, but we find " + m_artifactRepository.get().size();
+
+        List<ArtifactObject> list = m_artifactRepository.get(m_artifactRepository.createFilter("(!(" + BundleHelper.KEY_SYMBOLICNAME + "=normalBundle))"));
+        assert (list.size() == 1) && list.contains(myArtifact) : "We expect to find one artifact when filtering, but we find " + list.size();
+
+        list = m_artifactRepository.getResourceProcessors();
+        assert (list.size() == 2) && list.contains(resourceProcessor1) && list.contains(resourceProcessor2) : "We expect to find both our resource processors when asking for them; we find " + list.size() + " artifacts.";
+
+       m_artifactRepository.get(m_artifactRepository.createFilter("(" + BundleHelper.MIMETYPE + "=my\\(Mi\\*me)"));
+    }
+
+    private ArtifactObject createArtifact(String mimetype, String URL, String symbolicName, String processorPID) {
+        Map<String, String> attributes = new HashMap<String, String>();
+        attributes.put(ArtifactObject.KEY_MIMETYPE, mimetype);
+        attributes.put(ArtifactObject.KEY_URL, URL);
+        Map<String, String> tags = new HashMap<String, String>();
+
+        if (symbolicName != null) {
+            attributes.put(BundleHelper.KEY_SYMBOLICNAME, symbolicName);
+        }
+        if (processorPID != null) {
+            attributes.put(BundleHelper.KEY_RESOURCE_PROCESSOR_PID, processorPID);
+        }
+
+        return m_artifactRepository.create(attributes, tags);
+    }
+}
+
+/**
+ * Helper for testing the ArtifactObject. In the constructor, a <code>replaceURL</code> can
+ * be passed in to test the attribute normalization.
+ */
+class MockHelper implements ArtifactHelper {
+    private final String m_replaceURL;
+
+    MockHelper() {
+        this(null);
+    }
+
+    MockHelper(String replaceURL) {
+        m_replaceURL = replaceURL;
+    }
+
+    public Map<String, String> checkAttributes(Map<String, String> attributes) {
+        if ((m_replaceURL != null) && attributes.containsKey(ArtifactObject.KEY_URL)) {
+            attributes.put(ArtifactObject.KEY_URL, m_replaceURL);
+        }
+        return attributes;
+    }
+
+    public Comparator<ArtifactObject> getComparator() {
+        return null;
+    }
+
+    public String[] getDefiningKeys() {
+        return new String[0];
+    }
+
+    public String[] getMandatoryAttributes() {
+        return new String[0];
+    }
+
+    public boolean canUse(ArtifactObject object) {
+        return false;
+    }
+
+    public <TYPE extends ArtifactObject> String getAssociationFilter(TYPE obj, Map<String, String> properties) {
+        return null;
+    }
+
+    public <TYPE extends ArtifactObject> int getCardinality(TYPE obj, Map<String, String> properties) {
+        return 0;
+    }
+
+    public ArtifactPreprocessor getPreprocessor() {
+        return null;
+    }
+}
+
+
+
+
+

Added: incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/CachedRepositoryImplTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/CachedRepositoryImplTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/CachedRepositoryImplTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/CachedRepositoryImplTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,108 @@
+package net.luminis.liq.client.repository.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.luminis.liq.repository.Repository;
+import net.luminis.liq.repository.ext.BackupRepository;
+import net.luminis.liq.repository.ext.CachedRepository;
+import net.luminis.liq.repository.impl.CachedRepositoryImpl;
+import net.luminis.liq.test.utils.TestUtils;
+
+import org.testng.annotations.Test;
+
+public class CachedRepositoryImplTest {
+
+    /**
+     * Initial checkout: the remote repository contains some data for a given version,
+     * we make the cached repository do a checkout, and check whether all data arrives at the
+     * right places: in getLocal, and in the backup repository.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testInitialCheckout() throws IllegalArgumentException, IOException {
+        Repository m_repository = new MockRepository();
+        byte[] testContent = new byte[] {'i', 'n', 'i', 't', 'i', 'a', 'l'};
+        m_repository.commit(new ByteArrayInputStream(testContent), 0);
+        BackupRepository m_backupRepository = new MockBackupRepository();
+
+        CachedRepository m_cachedRepository = new CachedRepositoryImpl(null, m_repository, m_backupRepository, 0);
+
+        InputStream input = m_cachedRepository.checkout(1);
+        byte[] inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from checkout: " + new String(inputBytes);
+        input = m_cachedRepository.getLocal(false);
+        inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from getLocal: " + new String(inputBytes);
+        input = m_backupRepository.read();
+        inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from the backup repository: " + new String(inputBytes);
+    }
+
+    /**
+     * There are two types of commit, one that takes an input stream, and one that
+     * simply flushes whatever is in the current to the remote repository.
+     * After each commit, we should be able to renew the cached repository,
+     * and checkout the data we put in before.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testCommit() throws IllegalArgumentException, IOException {
+        Repository m_repository = new MockRepository();
+        BackupRepository m_backupRepository = new MockBackupRepository();
+
+        CachedRepository m_cachedRepository = new CachedRepositoryImpl(null, m_repository, m_backupRepository, 0);
+        byte[] testContent = new byte[] {'i', 'n', 'i', 't', 'i', 'a', 'l'};
+
+        InputStream input = new ByteArrayInputStream(testContent);
+        m_cachedRepository.commit(input, 0);
+
+        m_cachedRepository = new CachedRepositoryImpl(null, m_repository, m_backupRepository, 0);
+        input = m_cachedRepository.checkout(1);
+        byte[] inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from checkout: " + new String(inputBytes);
+
+        byte[] newTestContent = new byte[] {'n', 'e', 'w'};
+
+        m_cachedRepository.writeLocal(new ByteArrayInputStream(newTestContent));
+
+        m_cachedRepository.commit();
+
+        m_cachedRepository = new CachedRepositoryImpl(null, m_repository, m_backupRepository, 0);
+        input = m_cachedRepository.checkout(2);
+        inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, newTestContent) : "We got something different than 'new' from checkout: " + new String(inputBytes);
+    }
+
+    /**
+     * After checking out and changing stuff, we want to revert to the old version.
+     * @throws IOException
+     * @throws IllegalArgumentException
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testRevert() throws IllegalArgumentException, IOException {
+        Repository m_repository = new MockRepository();
+        BackupRepository m_backupRepository = new MockBackupRepository();
+
+        CachedRepository m_cachedRepository = new CachedRepositoryImpl(null, m_repository, m_backupRepository, 0);
+        byte[] testContent = new byte[] {'i', 'n', 'i', 't', 'i', 'a', 'l'};
+
+        InputStream input = new ByteArrayInputStream(testContent);
+        m_cachedRepository.commit(input, 0);
+
+        m_cachedRepository = new CachedRepositoryImpl(null, m_repository, m_backupRepository, 0);
+        input = m_cachedRepository.checkout(1);
+
+        byte[] newTestContent = new byte[] {'n', 'e', 'w'};
+
+        m_cachedRepository.writeLocal(new ByteArrayInputStream(newTestContent));
+        input = m_cachedRepository.getLocal(false);
+        byte[] inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, newTestContent) : "We got something different than 'new' from getLocal: " + new String(inputBytes);
+
+        m_cachedRepository.revert();
+        input = m_cachedRepository.getLocal(false);
+        inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from getLocal: " + new String(inputBytes);
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/FilebasedBackupRepositoryTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/FilebasedBackupRepositoryTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/FilebasedBackupRepositoryTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/FilebasedBackupRepositoryTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,58 @@
+package net.luminis.liq.client.repository.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.luminis.liq.repository.impl.FilebasedBackupRepository;
+import net.luminis.liq.test.utils.TestUtils;
+
+import org.testng.annotations.Test;
+
+public class FilebasedBackupRepositoryTest {
+
+    /**
+     * A basic scenario: we write, backup, write again, and revert.
+     */
+    @Test( groups = { TestUtils.UNIT } )
+    public void testFilebasedBackupRepository() throws IOException {
+        File current = File.createTempFile("testFilebasedBackupRepository", null);
+        File backup = File.createTempFile("testFilebasedBackupRepository", null);
+        current.deleteOnExit();
+        backup.deleteOnExit();
+
+        FilebasedBackupRepository rep = new FilebasedBackupRepository(current, backup);
+
+        byte[] testContent = new byte[] {'i', 'n', 'i', 't', 'i', 'a', 'l'};
+
+        // write initial content
+        rep.write(new ByteArrayInputStream(testContent));
+
+        // read initial content
+        InputStream input = rep.read();
+        byte[] inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from read: " + new String(inputBytes);
+
+        // backup what's in the repository
+        rep.backup();
+
+        // write new content
+        byte[] newTestContent = new byte[] {'n', 'e', 'w'};
+        rep.write(new ByteArrayInputStream(newTestContent));
+
+        // read current content
+        input = rep.read();
+        inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, newTestContent) : "We got something different than 'new' from read: " + new String(inputBytes);
+
+        // revert to previous (initial) content
+        rep.restore();
+
+        // read current content
+        input = rep.read();
+        inputBytes = AdminTestUtil.copy(input);
+        assert AdminTestUtil.byteArraysEqual(inputBytes, testContent) : "We got something different than 'initial' from read: " + new String(inputBytes);
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockBackupRepository.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockBackupRepository.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockBackupRepository.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockBackupRepository.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,40 @@
+package net.luminis.liq.client.repository.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.luminis.liq.repository.ext.BackupRepository;
+
+public class MockBackupRepository implements BackupRepository {
+    private byte[] m_current;
+    private byte[] m_backup;
+
+    @Override
+    public boolean backup() throws IOException {
+        if (m_current == null) {
+            return false;
+        }
+        m_backup = AdminTestUtil.copy(m_current);
+        return true;
+    }
+
+    @Override
+    public InputStream read() throws IOException {
+        return new ByteArrayInputStream(m_current);
+    }
+
+    @Override
+    public boolean restore() throws IOException {
+        if (m_backup == null) {
+            return false;
+        }
+        m_current = AdminTestUtil.copy(m_backup);
+        return true;
+    }
+
+    @Override
+    public void write(InputStream data) throws IOException {
+        m_current = AdminTestUtil.copy(data);
+    }
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockCachedRepository.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockCachedRepository.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockCachedRepository.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/client/repository/impl/MockCachedRepository.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,72 @@
+package net.luminis.liq.client.repository.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.luminis.liq.repository.SortedRangeSet;
+import net.luminis.liq.repository.ext.CachedRepository;
+
+public class MockCachedRepository implements CachedRepository {
+
+    @Override
+    public InputStream checkout(boolean fail) throws IOException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean commit() throws IOException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public InputStream getLocal(boolean fail) throws IOException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean revert() throws IOException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public void writeLocal(InputStream data) throws IOException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public InputStream checkout(long version) throws IOException, IllegalArgumentException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean commit(InputStream data, long fromVersion) throws IOException, IllegalArgumentException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public SortedRangeSet getRange() throws IOException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean isCurrent() throws IOException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public long getHighestRemoteVersion() throws IOException {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public long getMostRecentVersion() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+}