blob: b7ebeb40525e8eefbdbe9f613207cb5b15ba1cb7 [file] [log] [blame]
/*
* $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;
}
}