FELIX-370:
- Moved maven-obr-plugin from clement sandbox to trunk
- Fixed problem with repository containg space in path (on Win32 is default)
- Update maven-bundle-plugin in order to use maven-obr-plugin
General:
- Some iPOJO module compiling as bundle where defined in the plugins profile
- Wrong parent POM in some upnp module
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@578326 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/pom.xml b/bundleplugin/pom.xml
index f99debc..9869d4e 100644
--- a/bundleplugin/pom.xml
+++ b/bundleplugin/pom.xml
@@ -28,19 +28,27 @@
</parent>
<modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.felix</groupId>
+
<artifactId>maven-bundle-plugin</artifactId>
<version>1.1.0-SNAPSHOT</version>
-
<packaging>maven-plugin</packaging>
+
<name>Maven Bundle Plugin</name>
- <description> provides a maven plugin that allows that builds the jar by
- embedding packages from the classpath (wildcarded). Plus a zillion
- other features. See http://www.aqute.biz/php/tools/bnd.php
- </description>
+ <description>
+ Provides a maven plugin which allows the creation of an OSGi bundle by
+ embedding used packages as class or jars by inspecting the classpath used to
+ compile the bundle. Plus a zillion other features.
+ The plugin relies on the bnd tools, so to gather more information you can look
+ at is documentation http://www.aqute.biz/php/tools/bnd.php
+ </description>
<dependencies>
<dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-obr-plugin</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
<groupId>biz.aQute</groupId>
<artifactId>bndlib</artifactId>
<version>0.0.189</version>
diff --git a/bundleplugin/src/main/resources/META-INF/plexus/components.xml b/bundleplugin/src/main/resources/META-INF/plexus/components.xml
index 1eb9b8e..cfe5bbd 100644
--- a/bundleplugin/src/main/resources/META-INF/plexus/components.xml
+++ b/bundleplugin/src/main/resources/META-INF/plexus/components.xml
@@ -34,8 +34,14 @@
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
<test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
<package>org.apache.felix:maven-bundle-plugin:bundle</package>
- <install>org.apache.maven.plugins:maven-install-plugin:install</install>
- <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+ <install>
+ org.apache.maven.plugins:maven-install-plugin:install,
+ org.apache.felix:maven-obr-plugin:repository
+ </install>
+ <deploy>
+ org.apache.maven.plugins:maven-deploy-plugin:deploy,
+ org.apache.felix:maven-obr-plugin:deploy
+ </deploy>
</phases>
<!-- END SNIPPET: bundle-lifecycle -->
</lifecycle>
diff --git a/maven-obr-plugin/pom.xml b/maven-obr-plugin/pom.xml
new file mode 100644
index 0000000..b6244a3
--- /dev/null
+++ b/maven-obr-plugin/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <artifactId>felix</artifactId>
+ <groupId>org.apache.felix</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>maven-obr-plugin</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>maven-plugin</packaging>
+
+ <name>OBR Maven Plugin</name>
+ <description>
+ Provides a maven plugin which allows the automatic cration and update of an
+ OSGi Bundle Repository complaint to OSGi RFC 0112.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>net.sf.kxml</groupId>
+ <artifactId>kxml2</artifactId>
+ <version>2.2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>${groupId}</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>${groupId}</groupId>
+ <artifactId>org.apache.felix.bundlerepository</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ </dependencies>
+
+</project>
+
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Capability.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Capability.java
new file mode 100644
index 0000000..a8f55cc
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Capability.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * This class describe and store capability node.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Capability {
+
+ /**
+ * m_name: name of the capability.
+ */
+ private String m_name;
+
+ /**
+ * m_p: List of PElement.
+ */
+ private List m_p = new ArrayList();
+
+ /**
+ * get the name attribute.
+ *
+ * @return name attribute
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * set the name attribute.
+ *
+ * @param name new name value
+ *
+ */
+ public void setName(String name) {
+ this.m_name = name;
+ }
+
+ /**
+ * return the capabilities.
+ *
+ * @return List of PElement
+ */
+ public List getP() {
+ return m_p;
+ }
+
+ /**
+ * set the capabilities.
+ *
+ * @param mp List of PElement
+ *
+ */
+ public void setP(List mp) {
+ this.m_p = mp;
+ }
+
+ /**
+ * add one element in List.
+ *
+ * @param pelement PElement
+ *
+ */
+ public void addP(PElement pelement) {
+ m_p.add(pelement);
+ }
+
+ /**
+ * transform this object to Node.
+ *
+ * @param father father document for create Node
+ * @return node
+ */
+ public Node getNode(Document father) {
+ Element capability = father.createElement("capability");
+ capability.setAttribute("name", this.getName());
+ for (int i = 0; i < this.getP().size(); i++) {
+ capability.appendChild(((PElement) (this.getP().get(i))).getNode(father));
+ }
+ return capability;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Category.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Category.java
new file mode 100644
index 0000000..3032271
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Category.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * describe and store category node.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+
+public class Category {
+ /**
+ * id of the category.
+ */
+ private String m_id;
+
+ /**
+ * get the id attribute.
+ *
+ * @return id
+ */
+ public String getId() {
+ return m_id;
+ }
+
+ /**
+ * set the id attribute.
+ * @param id new id value
+ */
+ public void setId(String id) {
+ this.m_id = id;
+ }
+
+ /**
+ * transform this object to node.
+ * @param father father document for create Node
+ * @return node
+ */
+ public Node getNode(Document father) {
+ Element category = father.createElement("category");
+ category.setAttribute("id", this.getId());
+ return category;
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Config.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Config.java
new file mode 100644
index 0000000..08bc867
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Config.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+/**
+ * this class is used to store some user information about configuration of the plugin.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class Config {
+
+ /**
+ * use relative path or not.
+ */
+ private boolean m_pathRelative; // use relative or absolute path in repository.xml
+
+ /**
+ * deploy file or not.
+ */
+ private boolean m_fileRemote; // deploy file on remote server
+
+ /**
+ * constructor: set default configuration: use relative path and don't upload file.
+ *
+ */
+ public Config() {
+ // default configuration
+ m_pathRelative = true;
+ m_fileRemote = false;
+ }
+
+ /**
+ * set relativePath attribute.
+ * @param value new value of attribute
+ */
+ public void setPathRelative(boolean value) {
+ m_pathRelative = value;
+ }
+
+ /**
+ * set fileRemote attribute.
+ * @param value new value of attribute
+ */
+ public void setRemotely(boolean value) {
+ m_fileRemote = value;
+ }
+
+ /**
+ * get use path relative.
+ * @return true if plugin use relative path, else false
+ */
+ public boolean isPathRelative() {
+ return m_pathRelative;
+ }
+
+ /**
+ * get if use upload file.
+ * @return true if the file will be uploaded, else false
+ */
+ public boolean isRemotely() {
+ return m_fileRemote;
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ExtractBindexInfo.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ExtractBindexInfo.java
new file mode 100644
index 0000000..6d0be6e
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ExtractBindexInfo.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.osgi.impl.bundle.obr.resource.BundleInfo;
+import org.osgi.impl.bundle.obr.resource.CapabilityImpl;
+import org.osgi.impl.bundle.obr.resource.RepositoryImpl;
+import org.osgi.impl.bundle.obr.resource.RequirementImpl;
+import org.osgi.impl.bundle.obr.resource.ResourceImpl;
+import org.osgi.impl.bundle.obr.resource.VersionImpl;
+
+/**
+ * this class is used to configure bindex and get information built by bindex about targeted bundle.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ExtractBindexInfo {
+
+ /**
+ * attribute get from bindex which describe targeted resource.
+ */
+ private ResourceImpl m_resource;
+
+ /**
+ * configure bindex and build information.
+ * @param repoFilename URI on OBR descriptor file
+ * @param outFile path on targeted jar-file
+ * @throws MojoExecutionException occurs if bindex configuration failed
+ */
+ public ExtractBindexInfo(URI repoFilename, String outFile) throws MojoExecutionException {
+
+ this.m_resource = null;
+ RepositoryImpl repository = null;
+ try {
+ repository = new RepositoryImpl(new File(repoFilename).getAbsoluteFile().toURL());
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("MalformedURLException");
+ }
+ BundleInfo info = null;
+ try {
+ info = new BundleInfo(repository, new File(outFile));
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("Exception");
+ }
+
+ try {
+ m_resource = info.build();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("Exception");
+ }
+ }
+
+ /**
+ * transform logical operator in xml syntax.
+ * @param filter string which contains logical operator
+ * @return string in correct xml syntax
+ */
+ private String parseFilter(String filter) {
+ filter.replaceAll("&", "&");
+ filter.replaceAll(">=", ">");
+
+ return filter;
+ }
+
+ /**
+ * extract capabilities from bindex information.
+ * @return bundle capabilities List
+ */
+ public List getCapabilities() {
+ List list = new ArrayList();
+ Collection res = m_resource.getCapabilityList();
+ Iterator it = res.iterator();
+ while (it.hasNext()) {
+ Capability capability = new Capability();
+ CapabilityImpl ci = (CapabilityImpl) it.next();
+ capability.setName(ci.getName());
+ // System.out.println(ci.getName()) ;
+ if (!(ci.getName().compareTo("bundle") == 0)) {
+ Map properties = ci.getProperties();
+ for (Iterator k = properties.keySet().iterator(); k.hasNext();) {
+ PElement p = new PElement();
+ String key = (String) k.next();
+ List values = (List) properties.get(key);
+ for (Iterator v = values.iterator(); v.hasNext();) {
+ Object value = v.next();
+ p.setN(key);
+ if (value != null) {
+ p.setV(value.toString());
+ } else {
+ System.out.println("Missing value " + key);
+ }
+ String type = null;
+ if (value instanceof Number) {
+ type = "number";
+ } else {
+ if (value.getClass() == VersionImpl.class) { type = "version"; }
+ }
+ if (type != null) {
+ p.setT(type);
+ }
+ }
+ capability.addP(p);
+ }
+
+ list.add(capability);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * extract requirement from bindex information.
+ * @return bundle requirement List
+ */
+ public List getRequirement() {
+ List list = new ArrayList();
+ Collection res = m_resource.getRequirementList();
+ Iterator it = res.iterator();
+ while (it.hasNext()) {
+ RequirementImpl ci = (RequirementImpl) it.next();
+ Require require = new Require();
+
+ require.setExtend(String.valueOf(ci.isExtend()));
+ require.setMultiple(String.valueOf(ci.isMultiple()));
+ require.setOptional(String.valueOf(ci.isOptional()));
+ require.setName(ci.getName());
+ require.setFilter(this.parseFilter(ci.getFilter()));
+ require.setValue(ci.getComment());
+ list.add(require);
+ }
+ return list;
+ }
+
+ /**
+ * extract symbolic name from bindex information.
+ * @return bundle symbolic name
+ */
+ public String getSymbolicName() {
+ return m_resource.getSymbolicName();
+ }
+
+ /**
+ * extract version from bindex information.
+ * @return bundle version
+ */
+ public String getVersion() {
+ if (m_resource.getVersion() != null) {
+ return m_resource.getVersion().toString();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * extract presentation name from bindex information.
+ * @return bundle presentation name
+ */
+ public String getPresentationName() {
+ return m_resource.getPresentationName();
+ }
+
+ /**
+ * extract copyright from bindex information.
+ * @return bundle copyright
+ */
+ public String getCopyright() {
+ return m_resource.getCopyright();
+ }
+
+ /**
+ * extract description from bindex information.
+ * @return bundle description
+ */
+ public String getDescription() {
+ return m_resource.getDescription();
+ }
+
+ /**
+ * extract documentation from bindex information.
+ * @return bundle documentation
+ */
+ public String getDocumentation() {
+ if (m_resource.getDocumentation() != null) {
+ return m_resource.getDocumentation().toString();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * extract license from bindex information.
+ * @return bundle license
+ */
+ public String getLicense() {
+ if (m_resource.getLicense() != null) {
+ return m_resource.getLicense().toString();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * extract source from bindex information.
+ * @return bundle source
+ */
+ public String getSource() {
+ if (m_resource.getSource() != null) {
+ return m_resource.getSource().toString();
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrDeploy.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrDeploy.java
new file mode 100644
index 0000000..ace1e30
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrDeploy.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+
+/**
+ * deploy the bundle to a remote site.
+ * this goal is used when you compile a project with a pom file
+ * @goal deployment
+ * @phase deploy
+ * @requiresDependencyResolution compile
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+
+public class ObrDeploy extends AbstractMojo {
+
+ /**
+ * setting of maven.
+ *
+ * @parameter expression="${settings}"
+ * @require
+ */
+ private Settings m_settings;
+
+ /**
+ * name of the repository xml descriptor file.
+ *
+ * @parameter expression="${repository-name}" default-value="repository.xml"
+ */
+ private String m_repositoryName;
+
+ /**
+ * The local Maven repository.
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ */
+ private ArtifactRepository m_localRepo;
+
+ /**
+ * Project in use.
+ *
+ * @parameter expression="${project}"
+ * @require
+ */
+ private MavenProject m_project;
+
+ /**
+ * Wagon Manager.
+ * @component
+ */
+ private WagonManager m_wagonManager;
+
+ /**
+ * obr file define by the user.
+ *
+ * @parameter expression="${ignore-lock}"
+ *
+ */
+ private boolean m_ignoreLock;
+
+ /**
+ * used to store pathfile in local repo.
+ */
+ private String m_fileInLocalRepo;
+
+ /**
+ * Enable/Disable this goal
+ * @description If true evrything the goal do nothing, the goal just skip over
+ * @parameter expression="${maven.obr.installToRemoteOBR}" default-value="false"
+ */
+ private boolean installToRemoteOBR;
+
+
+ /**
+ * main method for this goal.
+ * @implements org.apache.maven.plugin.Mojo.execute
+ * @throws MojoExecutionException if the plugin failed
+ * @throws MojoFailureException if the plugin failed
+ */
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ getLog().info("Obr-deploy start:");
+ if(!installToRemoteOBR)
+ {
+ getLog().info("maven-obr-plugin:deploy goal is disable due to one of the following reason:");
+ getLog().info(" - 'installToRemoteOBR' configuration set to false");
+ getLog().info(" - JVM property maven.obr.installToRemoteOBR set to false");
+ return;
+ }
+ ArtifactRepository ar = m_project.getDistributionManagementArtifactRepository();
+
+ // locate the obr.xml file
+ String obrXmlFile = null;
+ List l = m_project.getResources();
+ for (int i = 0; i < l.size(); i++) {
+ File f = new File(((Resource) l.get(i)).getDirectory() + File.separator + "obr.xml");
+ if (f.exists()) {
+ obrXmlFile = ((Resource) l.get(i)).getDirectory() + File.separator + "obr.xml";
+ break;
+ }
+ }
+
+ // the obr.xml file is not present
+ if (obrXmlFile == null) {
+ getLog().warn("obr.xml is not present, use default");
+ }
+
+ File repoDescriptorFile = null;
+
+ // init the wagon connection
+ RemoteFileManager remoteFile = new RemoteFileManager(ar, m_wagonManager, m_settings, getLog());
+ remoteFile.connect();
+
+ // create a non-empty file used to lock the repository descriptor file
+ File lockFile = null;
+ Writer output = null;
+ try {
+ lockFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), null);
+ output = new BufferedWriter(new FileWriter(lockFile));
+ output.write("locked");
+ output.close();
+ } catch (IOException e) {
+ getLog().error("Unable to create temporary file");
+ throw new MojoFailureException("IOException");
+ }
+
+ if (m_ignoreLock) {
+ try {
+ remoteFile.put(lockFile, m_repositoryName + ".lock");
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+
+ } else {
+ int countError = 0;
+ while (remoteFile.isLockedFile(remoteFile, m_repositoryName) && countError < 2) {
+ countError++;
+ getLog().warn("File is locked, retry in 10s");
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ getLog().warn("Sleep interupted");
+ }
+ }
+
+ if (countError == 2) {
+ getLog().error("File: " + m_repositoryName + " is locked. Try -Dignore-lock=true if you want force uploading");
+ throw new MojoFailureException("fileLocked");
+ }
+ }
+
+ // file is not locked, so we lock it now
+ try {
+ remoteFile.put(lockFile, m_repositoryName + ".lock");
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+
+ try {
+ repoDescriptorFile = remoteFile.get(m_repositoryName);
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ // file doesn't exist! create a new one
+ getLog().warn("file specified does not exist: " + m_repositoryName);
+ getLog().warn("Create a new repository descriptor file " + m_repositoryName);
+ try {
+ File f = File.createTempFile(String.valueOf(System.currentTimeMillis()), null);
+ repoDescriptorFile = new File(f.getParent() + File.separator + String.valueOf(System.currentTimeMillis()) + ".xml");
+ } catch (IOException e1) {
+ getLog().error("canno't create temporary file");
+ e1.printStackTrace();
+ return;
+ }
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("IOException");
+ }
+
+ Config userConfig = new Config();
+ userConfig.setPathRelative(true);
+ userConfig.setRemotely(true);
+
+ PathFile file = null;
+
+ // get the path to local maven repository
+ file = new PathFile(PathFile.uniformSeparator(m_settings.getLocalRepository()) + File.separator + PathFile.uniformSeparator(m_localRepo.pathOf(m_project.getArtifact())));
+ if (file.isExists()) {
+ m_fileInLocalRepo = file.getOnlyAbsoluteFilename();
+ } else {
+ getLog().error("file not found in local repository: " + m_settings.getLocalRepository() + File.separator + m_localRepo.pathOf(m_project.getArtifact()));
+ return;
+ }
+
+ file = new PathFile("file:/" + repoDescriptorFile.getAbsolutePath());
+
+ ObrUpdate obrUpdate = new ObrUpdate(file, obrXmlFile, m_project, m_fileInLocalRepo, PathFile.uniformSeparator(m_settings.getLocalRepository()), userConfig, getLog());
+
+ obrUpdate.updateRepository();
+
+ // the reposiroty descriptor file is modified, we upload it on the remote repository
+ try {
+ remoteFile.put(repoDescriptorFile, m_repositoryName);
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+ } catch (ResourceDoesNotExistException e) {
+ getLog().error("Resource does not exist:" + repoDescriptorFile.getName());
+ e.printStackTrace();
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+ repoDescriptorFile.delete();
+
+ // we remove lockFile activation
+ lockFile = null;
+ try {
+ lockFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), null);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("IOException");
+ }
+ try {
+ remoteFile.put(lockFile, m_repositoryName + ".lock");
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+ } catch (ResourceDoesNotExistException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+
+ remoteFile.disconnect();
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrDeployFile.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrDeployFile.java
new file mode 100644
index 0000000..1296a56
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrDeployFile.java
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+
+/**
+ * deploy the bundle to a ftp site.
+ * this goal is used when you upload a jar file (in command line)
+ * @goal deploy-file
+ * @phase deploy
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ObrDeployFile extends AbstractMojo {
+
+ /**
+ * setting of maven.
+ *
+ * @parameter expression="${settings}"
+ * @require
+ */
+
+ private Settings m_settings;
+
+ /**
+ * name of the repository xml descriptor file.
+ *
+ * @parameter expression="${repository-name}" default-value="repository.xml"
+ */
+ private String m_repositoryName;
+
+ /**
+ * The local Maven repository.
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ */
+ private ArtifactRepository m_localRepo;
+
+ /**
+ * Project in use.
+ *
+ * @parameter expression="${project}"
+ * @require
+ */
+ private MavenProject m_project;
+
+ /**
+ * Wagon Manager.
+ * @component
+ */
+ private WagonManager m_wagonManager;
+
+ /**
+ * obr file define by the user.
+ *
+ * @parameter expression="${obr-file}"
+ *
+ */
+ private String m_obrFile;
+
+ /**
+ * obr file define by the user.
+ *
+ * @parameter expression="${ignore-lock}"
+ *
+ */
+ private boolean m_ignoreLock;
+
+ /**
+ * used to store pathfile in local repo.
+ */
+ private String m_fileInLocalRepo;
+
+ /**
+ * main method for this goal.
+ * @implements org.apache.maven.plugin.Mojo.execute
+ * @throws MojoExecutionException if the plugin failed
+ * @throws MojoFailureException if the plugin failed
+ */
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ getLog().info("Obr-deploy-file start:");
+
+ ArtifactRepository ar = m_project.getDistributionManagementArtifactRepository();
+
+ // locate the obr.xml file
+ PathFile fileObrXml = new PathFile(m_obrFile);
+ if (!fileObrXml.isExists()) {
+ getLog().warn("obr.xml file not found, use default");
+ }
+
+ File repoDescriptorFile = null;
+
+ RemoteFileManager remoteFile = new RemoteFileManager(ar, m_wagonManager, m_settings, getLog());
+
+ remoteFile.connect();
+
+ // create a non-empty file used to lock the repository descriptor file
+ File lockFile = null;
+ Writer output = null;
+ try {
+ lockFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), null);
+ output = new BufferedWriter(new FileWriter(lockFile));
+ output.write("locked");
+ output.close();
+ } catch (IOException e) {
+ getLog().error("Unable to create temporary file");
+ throw new MojoFailureException("IOException");
+ }
+
+ if (m_ignoreLock) {
+ try {
+ remoteFile.put(lockFile, m_repositoryName + ".lock");
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+
+ } else {
+ int countError = 0;
+ while (remoteFile.isLockedFile(remoteFile, m_repositoryName) && countError < 2) {
+ countError++;
+ getLog().warn("File is locked, retry in 10s");
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ getLog().warn("Sleep Interupted");
+ }
+ }
+
+ if (countError == 2) {
+ getLog().error("File: " + m_repositoryName + " is locked. Try -Dignore-lock=true if you want to force uploading");
+ throw new MojoFailureException("fileLocked");
+ }
+ }
+
+ // file is not locked, so we lock it now
+ try {
+ remoteFile.put(lockFile, m_repositoryName + ".lock");
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+
+ try {
+ repoDescriptorFile = remoteFile.get(m_repositoryName);
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ // file doesn't exist! create a new one
+ getLog().warn("file specified does not exist: " + m_repositoryName);
+ getLog().warn("Create a new repository descriptor file " + m_repositoryName);
+ try {
+ File f = File.createTempFile(String.valueOf(System.currentTimeMillis()), null);
+ repoDescriptorFile = new File(f.getParent() + File.separator + String.valueOf(System.currentTimeMillis()) + ".xml");
+ } catch (IOException e1) {
+ getLog().error("canno't create temporary file");
+ e1.printStackTrace();
+ return;
+ }
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("IOException");
+ }
+
+ Config userConfig = new Config();
+ userConfig.setPathRelative(true);
+ userConfig.setRemotely(true);
+
+ PathFile file = null;
+
+ // get the path to local maven repository
+ file = new PathFile(PathFile.uniformSeparator(m_settings.getLocalRepository()) + File.separator + PathFile.uniformSeparator(m_localRepo.pathOf(m_project.getArtifact())));
+ if (file.isExists()) {
+ m_fileInLocalRepo = file.getOnlyAbsoluteFilename();
+ } else {
+ getLog().error("file not found in local repository: " + m_settings.getLocalRepository() + File.separator + m_localRepo.pathOf(m_project.getArtifact()));
+ return;
+ }
+
+ file = new PathFile("file:/" + repoDescriptorFile.getAbsolutePath());
+
+ ObrUpdate obrUpdate = new ObrUpdate(file, fileObrXml.getOnlyAbsoluteFilename(), m_project, m_fileInLocalRepo, PathFile.uniformSeparator(m_settings.getLocalRepository()), userConfig, getLog());
+
+ obrUpdate.updateRepository();
+
+ // the reposiroty descriptor file is modified, we upload it on the remote repository
+ try {
+ remoteFile.put(repoDescriptorFile, m_repositoryName);
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+ } catch (ResourceDoesNotExistException e) {
+ getLog().error("Resource does not exist:" + repoDescriptorFile.getName());
+ e.printStackTrace();
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+ repoDescriptorFile.delete();
+
+ // we remove lockFile activation
+ lockFile = null;
+ try {
+ lockFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), null);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("IOException");
+ }
+ try {
+ remoteFile.put(lockFile, m_repositoryName + ".lock");
+ } catch (TransferFailedException e) {
+ getLog().error("Transfer failed");
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+ } catch (ResourceDoesNotExistException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("ResourceDoesNotExistException");
+ } catch (AuthorizationException e) {
+ getLog().error("Authorization failed");
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ }
+ remoteFile.disconnect();
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrInstall.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrInstall.java
new file mode 100644
index 0000000..496aafa
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrInstall.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+
+/**
+ * construct the repository.xml with a project Maven compiled
+ *
+ * @goal repository
+ * @phase install
+ * @requiresDependencyResolution compile
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ObrInstall extends AbstractMojo {
+ /**
+ * The local Maven repository.
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ */
+ private ArtifactRepository m_localRepo;
+
+ /**
+ * path to the repository.xml.
+ *
+ * @parameter expression="${repository-path}"
+ * @require
+ */
+ private String m_repositoryPath;
+
+ /**
+ * Project in use.
+ *
+ * @parameter expression="${project}"
+ * @require
+ */
+
+ private MavenProject m_project;
+
+ /**
+ * setting of maven.
+ *
+ * @parameter expression="${settings}"
+ * @require
+ */
+
+ private Settings m_settings;
+
+ /**
+ * Enable/Disable this goal
+ * @description If true evrything the goal do nothing, the goal just skip over
+ * @parameter expression="${maven.obr.installToLocalOBR}" default-value="true"
+ */
+ private boolean installToLocalOBR;
+
+
+ /**
+ * path to file in the maven local repository.
+ */
+ private String m_fileInLocalRepo;
+
+ /**
+ * main method for this goal.
+ * @implements org.apache.maven.plugin.Mojo.execute
+ * @throws MojoExecutionException if the plugin failed
+ */
+ public void execute() throws MojoExecutionException {
+ getLog().info("Obr Plugin starts:");
+ if(!installToLocalOBR)
+ {
+ getLog().info("maven-obr-plugin:repository goal is disable due to one of the following reason:");
+ getLog().info(" - 'installToLocalOBR' configuration set to false");
+ getLog().info(" - JVM property maven.obr.installToLocalOBR set to false");
+ return;
+ }
+
+ if (m_repositoryPath == null) {
+ m_repositoryPath = "file:/" + m_localRepo.getBasedir() + File.separator + "repository.xml";
+ getLog().warn("-DpathRepo is not define, use default repository: " + m_repositoryPath);
+ }
+
+ PathFile file = new PathFile(m_repositoryPath);
+ if (file.isExists()) {
+ if (!m_repositoryPath.startsWith("file:/")) { m_repositoryPath = "file:/" + m_repositoryPath; }
+ }
+
+ // locate the obr.xml file
+ String obrXmlFile = null;
+ List l = m_project.getResources();
+ for (int i = 0; i < l.size(); i++) {
+ File f = new File(((Resource) l.get(i)).getDirectory() + File.separator + "obr.xml");
+ if (f.exists()) {
+ obrXmlFile = ((Resource) l.get(i)).getDirectory() + File.separator + "obr.xml";
+ break;
+ }
+ }
+ // the obr.xml file is not present
+ if (obrXmlFile == null) {
+ getLog().warn("obr.xml is not present, use default");
+ }
+
+ // get the path to local maven repository
+ file = new PathFile(PathFile.uniformSeparator(m_settings.getLocalRepository()) +
+ File.separator + PathFile.uniformSeparator(m_localRepo.pathOf(m_project.getArtifact())));
+
+ if (file.isExists()) {
+ m_fileInLocalRepo = file. getOnlyAbsoluteFilename();
+ } else {
+ getLog().error("file not found in local repository: " + m_settings.getLocalRepository() + File.separator + m_localRepo.pathOf(m_project.getArtifact()));
+ getLog().error("file not found in local repository: "
+ + m_localRepo.getBasedir() + File.separator + m_localRepo.pathOf(m_project.getArtifact()));
+ return;
+ }
+
+ // verify the repository.xml
+ PathFile fileRepo = new PathFile(m_repositoryPath);
+ if (fileRepo.isRelative()) { fileRepo.setBaseDir(m_settings.getLocalRepository()); }
+
+ // create the folder to the repository
+ PathFile repoExist = new PathFile(fileRepo.getAbsolutePath());
+ if (!repoExist.isExists()) { fileRepo.createPath(); }
+
+ // build the user configuration (use default)
+ Config user = new Config();
+
+ getLog().debug("Maven2 Local File repository = "+fileRepo.getAbsoluteFilename());
+ getLog().debug("OBR repository = "+obrXmlFile);
+
+ ObrUpdate obrUpdate = new ObrUpdate(fileRepo, obrXmlFile, m_project, m_fileInLocalRepo, PathFile.uniformSeparator(m_settings.getLocalRepository()), user, getLog());
+ try {
+ obrUpdate.updateRepository();
+ } catch (MojoExecutionException e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("MojoFailureException");
+ }
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrInstallFile.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrInstallFile.java
new file mode 100644
index 0000000..812ae87
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrInstallFile.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.File;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+
+/**
+ * construct the repository.xml from a compiled bundle.
+ * @description construct the repository.xml from a compiled bundle.
+ * @goal install-file
+ * @requiresProject false
+ * @phase install
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ObrInstallFile extends AbstractMojo {
+ /**
+ * The local Maven repository.
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ */
+ private ArtifactRepository m_localRepo;
+
+ /**
+ * path to the repository.xml.
+ *
+ * @parameter expression="${repository-path}"
+ * @require
+ */
+ private String m_repositoryPath;
+
+ /**
+ * setting of maven.
+ *
+ * @parameter expression="${settings}"
+ * @require
+ */
+ private Settings m_settings;
+
+ /**
+ * Artifact Id.
+ * @description symbolic name define by the user
+ * @parameter expression="${artifactId}"
+ */
+ private String m_artifactId;
+
+ /**
+ * Group Id.
+ * @description groupId define by the user
+ * @parameter expression="${groupId}"
+ */
+ private String m_groupId;
+
+ /**
+ * Version.
+ * @description version define by the user
+ * @parameter expression="${version}"
+ */
+ private String m_version;
+
+ /**
+ * Packaging.
+ * @description packaging define by the user
+ * @parameter expression="${packaging}"
+ */
+ private String m_packaging;
+
+ /**
+ * OBR File.
+ * @description obr file define by the user
+ * @parameter expression="${obr-file}"
+ */
+ private String m_obrFile;
+
+ /**
+ * store user information in a project.
+ */
+ private MavenProject m_project;
+
+ /**
+ * main method for this goal.
+ * @implements org.apache.maven.plugin.Mojo.execute
+ * @throws MojoExecutionException if the plugin failed
+ * @throws MojoFailureException if the plugin failed
+ */
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ getLog().info("Install-File Obr starts:");
+
+ m_project = new MavenProject();
+ m_project.setArtifactId(m_artifactId);
+ m_project.setGroupId(m_groupId);
+ m_project.setVersion(m_version);
+ m_project.setPackaging(m_packaging);
+
+ PathFile fileOut;
+
+ if (m_groupId == null) {
+ getLog().error("-DgroupId=VALUE is required");
+ return;
+ }
+ if (m_artifactId == null) {
+ getLog().error("-Dartifactid=VALUE is required");
+ return;
+ }
+ if (m_version == null) {
+ getLog().error("-Dversion=VALUE is required");
+ return;
+ }
+ if (m_packaging == null) {
+ getLog().error("-Dpackaging=VALUE is required");
+ return;
+ }
+
+ // copy the file to the local repository
+ PathFile repoLocal = new PathFile(m_localRepo.getBasedir());
+
+ // get the target file in mvn repo
+ fileOut = new PathFile(PathFile.uniformSeparator(m_settings.getLocalRepository()) + File.separator + m_groupId.replace('.', File.separatorChar) + File.separator + m_artifactId + File.separator + m_version + File.separator + m_artifactId
+ + "-" + m_version + "." + m_packaging);
+
+ if (!fileOut.isExists()) {
+ getLog().error("file doesn't exist: " + fileOut.getAbsoluteFilename());
+ return;
+ } else {
+ getLog().info("Target file: " + fileOut.getAbsoluteFilename());
+ }
+
+ if (m_repositoryPath == null) {
+ m_repositoryPath = "file:" + repoLocal.getOnlyAbsoluteFilename() + "repository.xml";
+ getLog().warn("-DpathRepo is not define, use default repository: " + m_repositoryPath);
+ }
+
+ PathFile fileRepo = new PathFile(m_repositoryPath);
+ if (fileRepo.isRelative()) {
+ fileRepo.setBaseDir(m_settings.getLocalRepository());
+ }
+
+ // create the folder to the repository
+ PathFile repoExist = new PathFile(fileRepo.getAbsolutePath());
+ if (!repoExist.isExists()) {
+ fileRepo.createPath();
+ }
+
+ PathFile fileObrXml = new PathFile(m_obrFile);
+ if (!fileObrXml.isExists()) {
+ getLog().warn("obr.xml file not found, use default");
+ }
+
+ // build the user config
+ Config userConfig = new Config();
+
+ ObrUpdate obrUpdate = new ObrUpdate(fileRepo, fileObrXml.getOnlyAbsoluteFilename(), m_project, fileOut.getOnlyAbsoluteFilename(), m_localRepo.getBasedir(), userConfig, getLog());
+ obrUpdate.updateRepository();
+
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java
new file mode 100644
index 0000000..a3de7b2
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java
@@ -0,0 +1,517 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * this class parse the old repository.xml file build the bundle resource description and update the repository.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+
+public class ObrUpdate {
+ /**
+ * generate the date format to insert it in repository descriptor file.
+ */
+ static SimpleDateFormat m_format = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
+
+ /**
+ * logger for this plugin.
+ */
+ private Log m_logger;
+
+ /**
+ * name and path to the repository descriptor file.
+ */
+ private URI m_repoFilename;
+
+ /**
+ * name and path to the obr.xml file.
+ */
+ private String m_obrXml;
+
+ /**
+ * name and path to the bundle jar file.
+ */
+ private String m_outputFile;
+
+ /**
+ * maven project description.
+ */
+ private MavenProject m_project;
+
+ /**
+ * user configuration information.
+ */
+ private Config m_userConfig;
+
+ /**
+ * used to build another xml document.
+ */
+ private DocumentBuilder m_constructor;
+
+ /**
+ * root on parent document.
+ */
+ private Document m_repoDoc;
+
+ /**
+ * used to determine the first free id.
+ */
+ private boolean[] m_idTab;
+
+ /**
+ * first Node on repository descriptor tree.
+ */
+ private Node m_root;
+
+ /**
+ * used to extract bindex bundle information.
+ */
+ private ExtractBindexInfo m_ebi;
+
+ /**
+ * used to store bundle information.
+ */
+ private ResourcesBundle m_resourceBundle;
+
+ /**
+ * pathfile to the repository descriptor file.
+ */
+ private PathFile m_repo;
+
+ /**
+ * initialize information.
+ * @param repoFilename path to the repository descriptor file
+ * @param obrXml path and filename to the obr.xml file
+ * @param project maven project description
+ * @param outputFile path to the bundle jar file
+ * @param localRepo only path to the local repository
+ * @param userConfig user information
+ * @param log plugin logger
+ */
+ public ObrUpdate(PathFile repoFilename, String obrXml, MavenProject project, String outputFile, String localRepo, Config userConfig, Log log) {
+ // this.m_localRepo = localRepo;
+ this.m_outputFile = outputFile;
+ this.m_repoFilename = repoFilename.getUri();
+ this.m_obrXml = obrXml;
+ this.m_project = project;
+ this.m_logger = log;
+
+ this.m_userConfig = userConfig;
+ // init the tab
+ m_idTab = new boolean[0];
+
+ m_resourceBundle = new ResourcesBundle(log);
+
+ if (userConfig.isRemotely()) {
+ this.m_repo = new PathFile(localRepo);
+ } else {
+ this.m_repo = repoFilename;
+ }
+ // System.err.println("Construct: "+repoFilename.getAbsoluteFilename());
+ }
+
+ /**
+ * update the repository descriptor file. parse the old repository descriptor file, get the old reference of the bundle or determine the id for a new bundle, extract information from bindex set the new information in descriptor file and save it.
+ * @throws MojoExecutionException if the plugin failed
+ */
+ public void updateRepository() throws MojoExecutionException {
+
+ m_logger.debug(" (f) m_obrXml = " + m_obrXml);
+ m_logger.debug(" (f) m_outputFile = " + m_outputFile);
+ m_logger.debug(" (f) m_repoFilename = " + m_repoFilename);
+
+ m_constructor = initConstructor();
+
+ if (m_constructor == null) {
+ return;
+ }
+
+ // get the file size
+ PathFile pf = new PathFile(m_outputFile);
+ File fout = pf.getFile();
+ pf.setBaseDir(m_repo.getOnlyAbsolutePath());
+ if (fout.exists()) {
+ m_resourceBundle.setSize(String.valueOf(fout.length()));
+ if (m_userConfig.isPathRelative()) {
+ m_resourceBundle.setUri(pf.getOnlyRelativeFilename().replace('\\', '/'));
+ } else {
+ m_resourceBundle.setUri("file:" + m_outputFile);
+ }
+ } else {
+ m_logger.error("file doesn't exist: " + m_outputFile);
+ return;
+ }
+
+ // parse repository
+ if (parseRepositoryXml() == -1) { return; }
+
+ // parse the obr.xml file
+ if (m_obrXml != null) {
+ // URL url = getClass().getResource("/SchemaObr.xsd");
+ // TODO validate obr.xml file
+
+ Document obrXmlDoc = parseFile(m_obrXml, m_constructor);
+ if (obrXmlDoc == null) { return; }
+ Node obrXmlRoot = (Element) obrXmlDoc.getDocumentElement();
+ // sort the obr file
+ sortObrXml(obrXmlRoot);
+ }
+
+ // use bindex to extract bundle information
+ try {
+ m_ebi = new ExtractBindexInfo(m_repoFilename, m_outputFile);
+ } catch (MojoExecutionException e) {
+ m_logger.error("unable to build Bindex informations");
+ e.printStackTrace();
+ throw new MojoExecutionException("MojoFailureException");
+ }
+
+ m_resourceBundle.construct(m_project, m_ebi);
+
+ if (!walkOnTree(m_root)) {
+ // the correct resource node was not found, we must create it
+ // we calcul the new id
+ int id = -1;
+ for (int i = 1; i < m_idTab.length; i++) {
+ if (!m_idTab[i]) {
+ id = i;
+ break;
+ }
+ }
+ if (id == -1) { id = m_idTab.length; }
+
+ searchRepository(m_root, id);
+ }
+
+ // the repository.xml file have been modified, so we save it
+ writeToFile(m_repoFilename, m_root);
+ }
+
+ /**
+ * init the document builder from xerces.
+ * @return DocumentBuilder ready to create new document
+ */
+ private DocumentBuilder initConstructor() {
+ DocumentBuilder constructor = null;
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ try {
+ constructor = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ m_logger.error("unable to create a new xml document");
+ e.printStackTrace();
+ }
+ return constructor;
+
+ }
+
+ /**
+ * Parse the reporitory descriptor file.
+ *
+ * @return 0 if the bundle is already in the descriptor, else -1
+ * @throws MojoExecutionException if the plugin failed
+ */
+ private int parseRepositoryXml() throws MojoExecutionException {
+
+ File fout = new File(m_repoFilename);
+ if (!fout.exists()) {
+ // create the repository.xml
+ try {
+
+ fout.createNewFile();
+ m_logger.info("Created new repository.xml file in "+fout.getAbsolutePath());
+ } catch (IOException e) {
+ m_logger.error("Cannot create file " + fout.getAbsolutePath());
+ e.printStackTrace();
+ return -1;
+ }
+
+ Document doc = m_constructor.newDocument();
+ // create xml tree
+ Date d = new Date();
+ d.setTime(System.currentTimeMillis());
+ Element root = doc.createElement("repository");
+ root.setAttribute("lastmodified", m_format.format(d));
+ root.setAttribute("name", "MyRepository");
+ try {
+ writeToFile(m_repoFilename, root);
+ } catch (MojoExecutionException e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("MojoExecutionException");
+ }
+ }
+
+ // now we parse the repository.xml file
+ m_repoDoc = parseFile(fout.getAbsolutePath(), m_constructor);
+ if (m_repoDoc == null) { return -1; }
+
+ m_root = (Element) m_repoDoc.getDocumentElement();
+ return 0;
+
+ }
+
+ /**
+ * transform a xml file to a xerces Document.
+ * @param filename path to the xml file
+ * @param constructor DocumentBuilder get from xerces
+ * @return Document which describe this file
+ */
+ private Document parseFile(String filename, DocumentBuilder constructor) {
+ if (constructor == null) { return null; }
+ // The document is the root of the DOM tree.
+ m_logger.info("Try to open: " + filename);
+ Document doc = null;
+ try {
+ doc = constructor.parse(new File(filename));
+ } catch (SAXException e) {
+ e.printStackTrace();
+ return null;
+ } catch (IOException e) {
+ m_logger.error("cannot open file: " + filename);
+ e.printStackTrace();
+ return null;
+ }
+ return doc;
+ }
+
+ /**
+ * put the information from obr.xml into ressourceBundle object.
+ * @param node Node to the OBR.xml file
+ */
+ private void sortObrXml(Node node) {
+ if (node.getNodeName().compareTo("require") == 0) {
+ Require newRequireNode = new Require();
+ NamedNodeMap list = node.getAttributes();
+ try {
+ newRequireNode.setExtend(list.getNamedItem("extend").getNodeValue());
+ newRequireNode.setMultiple(list.getNamedItem("multiple").getNodeValue());
+ newRequireNode.setOptional(list.getNamedItem("optional").getNodeValue());
+ newRequireNode.setFilter(list.getNamedItem("filter").getNodeValue());
+ newRequireNode.setName(list.getNamedItem("name").getNodeValue());
+ } catch (NullPointerException e) {
+ m_logger.error("the obr.xml file seems to be invalid in a \"require\" tag (one or more attributes are missing)");
+ // e.printStackTrace();
+ }
+ newRequireNode.setValue(node.getTextContent());
+ m_resourceBundle.addRequire(newRequireNode);
+ } else if (node.getNodeName().compareTo("capability") == 0) {
+ Capability newCapability = new Capability();
+ try {
+ newCapability.setName(node.getAttributes().getNamedItem("name").getNodeValue());
+ } catch (NullPointerException e) {
+ m_logger.error("attribute \"name\" is missing in obr.xml in a \"capability\" tag");
+ e.printStackTrace();
+ }
+ NodeList list = node.getChildNodes();
+ for (int i = 0; i < list.getLength(); i++) {
+ PElement p = new PElement();
+ Node n = list.item(i);
+ Node item = null;
+ // System.err.println(n.getNodeName());
+ if (n.getNodeName().compareTo("p") == 0) {
+
+ p.setN(n.getAttributes().getNamedItem("n").getNodeValue());
+ item = n.getAttributes().getNamedItem("t");
+ if (item != null) { p.setT(item.getNodeValue()); }
+ item = n.getAttributes().getNamedItem("v");
+ if (item != null) { p.setV(item.getNodeValue()); }
+
+ newCapability.addP(p);
+ }
+ }
+ m_resourceBundle.addCapability(newCapability);
+ } else if (node.getNodeName().compareTo("category") == 0) {
+ Category newCategory = new Category();
+ newCategory.setId(node.getAttributes().getNamedItem("id").getNodeValue());
+ m_resourceBundle.addCategory(newCategory);
+ } else {
+ NodeList list = node.getChildNodes();
+ for (int i = 0; i < list.getLength(); i++) {
+ sortObrXml(list.item(i));
+ }
+ }
+ }
+
+ /**
+ * write a Node in a xml file.
+ * @param outputFilename URI to the output file
+ * @param treeToBeWrite Node root of the tree to be write in file
+ * @throws MojoExecutionException if the plugin failed
+ */
+ private void writeToFile(URI outputFilename, Node treeToBeWrite) throws MojoExecutionException {
+ // init the transformer
+ Transformer transformer = null;
+ TransformerFactory tfabrique = TransformerFactory.newInstance();
+ try {
+ transformer = tfabrique.newTransformer();
+ } catch (TransformerConfigurationException e) {
+ m_logger.error("Unable to write to file: " + outputFilename.toString());
+ e.printStackTrace();
+ throw new MojoExecutionException("TransformerConfigurationException");
+ }
+ Properties proprietes = new Properties();
+ proprietes.put("method", "xml");
+ proprietes.put("version", "1.0");
+ proprietes.put("encoding", "ISO-8859-1");
+ proprietes.put("standalone", "yes");
+ proprietes.put("indent", "yes");
+ proprietes.put("omit-xml-declaration", "no");
+ transformer.setOutputProperties(proprietes);
+
+ DOMSource input = new DOMSource(treeToBeWrite);
+
+ File fichier = new File(outputFilename);
+ FileOutputStream flux = null;
+ try {
+ flux = new FileOutputStream(fichier);
+ } catch (FileNotFoundException e) {
+ m_logger.error("Unable to write to file: " + fichier.getName());
+ e.printStackTrace();
+ throw new MojoExecutionException("FileNotFoundException");
+ }
+ Result output = new StreamResult(flux);
+ try {
+ transformer.transform(input, output);
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("TransformerException");
+ }
+
+ try {
+ flux.flush();
+ flux.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new MojoExecutionException("IOException");
+ }
+
+ }
+
+ /**
+ * walk on the tree until the targeted node was found.
+ * @param node targeted node
+ * @return true if the requiered node was found else false.
+ */
+ private boolean walkOnTree(Node node) {
+
+ if (node.getNodeName().compareTo("resource") == 0) {
+ return resource(node);
+ } else { // look at the repository node (first in the file)
+ if (node.getNodeName().compareTo("repository") == 0) {
+ Date d = new Date();
+ d.setTime(System.currentTimeMillis());
+ NamedNodeMap nList = node.getAttributes();
+ Node n = nList.getNamedItem("lastmodified");
+ n.setNodeValue(m_format.format(d));
+ }
+ NodeList list = node.getChildNodes();
+ if (list.getLength() > 0) {
+ for (int i = 0; i < list.getLength(); i++) {
+ if (walkOnTree(list.item(i))) { return true; }
+ }
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * put the resource bundle in the tree.
+ * @param node Node on the xml file
+ * @param id id of the bundle ressource
+ */
+ private void searchRepository(Node node, int id) {
+ if (node.getNodeName().compareTo("repository") == 0) {
+ m_resourceBundle.setId(String.valueOf(id));
+ node.appendChild(m_resourceBundle.getNode(m_repoDoc));
+ return;
+ } else {
+ NodeList list = node.getChildNodes();
+ if (list.getLength() > 0) {
+ for (int i = 0; i < list.getLength(); i++) {
+ searchRepository(list.item(i), id);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * compare two node and update the array which compute the smallest free id.
+ * @param node : node
+ * @return true if the node is the same bundle than the ressourceBundle, else false.
+ */
+ private boolean resource(Node node) {
+
+ // this part save all the id free if we need to add resource
+ int id = Integer.parseInt(node.getAttributes().getNamedItem("id").getNodeValue());
+ if (id >= m_idTab.length) {
+ // resize tab
+ boolean[] bt = new boolean[id + 1];
+ for (int i = 0; i < id + 1; i++) {
+ if (m_idTab.length > i && m_idTab[i]) {
+ bt[i] = true;
+ } else {
+ bt[i] = false;
+ }
+ }
+
+ m_idTab = bt;
+ }
+ m_idTab[id] = true;
+
+ NamedNodeMap map = node.getAttributes();
+
+ if (m_resourceBundle.isSameBundleResource(map.getNamedItem("symbolicname").getNodeValue(), map.getNamedItem("presentationname").getNodeValue(), map.getNamedItem("version").getNodeValue())) {
+ m_resourceBundle.setId(String.valueOf(id));
+ node.getParentNode().replaceChild(m_resourceBundle.getNode(m_repoDoc), node);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/PElement.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/PElement.java
new file mode 100644
index 0000000..de881da
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/PElement.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * this class describe the p element in a capability tag.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class PElement {
+ /**
+ * store the v tag (value).
+ */
+ private String m_v;
+
+ /**
+ * store the t tag (type).
+ */
+ private String m_t;
+
+ /**
+ * store the n tag (name).
+ */
+ private String m_n;
+
+ /**
+ * get the n tag.
+ * @return attribute n
+ */
+ public String getN() {
+ return m_n;
+ }
+
+ /**
+ * set the n tage.
+ * @param n new value
+ */
+ public void setN(String n) {
+ this.m_n = n;
+ }
+
+ /**
+ * get the t tag.
+ * @return attribute t
+ */
+ public String getT() {
+ return m_t;
+ }
+
+ /**
+ * set the t tag.
+ * @param t new value
+ */
+ public void setT(String t) {
+ this.m_t = t;
+ }
+
+ /**
+ * get the v tag.
+ * @return attribute v
+ */
+ public String getV() {
+ return m_v;
+ }
+
+ /**
+ * set the v tag.
+ * @param v new value
+ */
+ public void setV(String v) {
+ this.m_v = v;
+ }
+
+ /**
+ * transform this object to node.
+ * @param father father document for create Node
+ * @return node
+ */
+ public Node getNode(Document father) {
+ Element p = father.createElement("p");
+ p.setAttribute("n", this.getN());
+ if (this.getT() != null) { p.setAttribute("t", this.getT()); }
+
+ if (this.getV() != null) { p.setAttribute("v", this.getV()); }
+
+ return p;
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/PathFile.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/PathFile.java
new file mode 100644
index 0000000..1f516f2
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/PathFile.java
@@ -0,0 +1,544 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.channels.FileChannel;
+
+/**
+ * this class provide some functions to simplify file manipulation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PathFile {
+
+ /**
+ * full filename.
+ */
+ private String m_fullFilename;
+
+ /**
+ * store only the filename of the file.
+ */
+ private String m_fileName;
+
+ /**
+ * store only the path of this file.
+ */
+ private String m_pathFile;
+
+ /**
+ * store the base Directory in case of relative path.
+ */
+ private String m_baseDir;
+
+ /**
+ * store the protocol used (ie:file, http...).
+ */
+ private String m_protocol;
+
+ /**
+ * if the path is relative or absolute.
+ */
+ private boolean m_relative;
+
+ /**
+ * if this file is a folder.
+ */
+ private boolean m_folder;
+
+ /**
+ * if the file exist or not.
+ */
+ private boolean m_exist;
+
+ /**
+ * if this file is a file (not a folder).
+ */
+ private boolean m_file;
+
+ /**
+ * if this filename is valid or incomplete.
+ */
+ private boolean m_valid;
+
+ /**
+ * build all the attribute information.
+ * @param filename path to the file
+ */
+ public PathFile(String filename) {
+
+ this.m_fullFilename = filename;
+ if (filename == null) {
+ this.m_valid = false;
+ return;
+ }
+ this.m_valid = true;
+ m_protocol = extractProtocol(filename);
+ m_pathFile = extractPathFile(filename);
+ if (m_pathFile.startsWith("//")) {
+ // avoid problems on Unix like system
+ m_pathFile = m_pathFile.substring(1);
+ }
+ m_fileName = extractFileName(filename);
+ m_relative = extractRelative();
+ if (!m_relative && (getProtocol().compareTo("file") == 0 || getProtocol().compareTo("") == 0)) {
+ File f = new File(getOnlyAbsoluteFilename());
+ m_file = f.isFile();
+ m_folder = f.isDirectory();
+ m_exist = f.exists();
+ if (m_folder) {
+ m_pathFile = m_pathFile + m_fileName + File.separator;
+ m_fileName = "";
+ }
+ }
+ if (m_exist) {
+ m_protocol = "file";
+ } else {
+ if (m_fileName.compareTo("") == 0) {
+ m_folder = true;
+ m_file = false;
+ } else {
+ m_folder = false;
+ m_file = true;
+ }
+
+ }
+
+ // add the '/' before the complete path if it is absolute path
+ if (!this.isRelative() && !m_pathFile.startsWith("/")) { m_pathFile = "/".concat(m_pathFile); }
+
+ }
+
+ /**
+ * get if the filename is relative or absolute.
+ * @return true if the path is relative, else false
+ */
+ private boolean extractRelative() {
+ if (m_pathFile.startsWith("." + File.separator, 1) || m_pathFile.startsWith(".." + File.separator, 1)) {
+ m_pathFile = m_pathFile.substring(1);
+ m_valid = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * get only the name from the filname.
+ * @param fullFilename full filename
+ * @return the name of the file or folder
+ */
+ private String extractFileName(String fullFilename) {
+ int index = fullFilename.lastIndexOf(File.separator);
+ return fullFilename.substring(index + 1, fullFilename.length());
+ }
+
+ /**
+ * get the path form the filename.
+ * @param fullFilename full filename
+ * @return the path of the file
+ */
+ private String extractPathFile(String fullFilename) {
+ String substring;
+ if (extractFileName(fullFilename).compareTo("") == 0) {
+ // it is a folder
+ substring = fullFilename;
+ } else {
+ substring = fullFilename.substring(0, fullFilename.indexOf(extractFileName(fullFilename)));
+ }
+
+ if (getProtocol().compareTo("") != 0) {
+ substring = substring.substring(5);
+ }
+
+ return substring;
+ }
+
+ /**
+ * determine which protocol is used.
+ * @param filename the full fileneme
+ * @return "file" or "http" or ""
+ */
+ private String extractProtocol(String filename) {
+ if (filename.startsWith("file:")) { return "file"; }
+ if (filename.startsWith("http:")) { return "http"; }
+ return "";
+ }
+
+ /**
+ * set the base directory.
+ * @param baseDir new value for the base directory
+ */
+ public void setBaseDir(String baseDir) {
+ this.m_baseDir = baseDir;
+ if (isRelative() && this.m_fullFilename != null) {
+ this.m_valid = true;
+ if (getProtocol().compareTo("file") == 0 || getProtocol().compareTo("") == 0) {
+ File f = new File(getOnlyAbsoluteFilename());
+ m_file = f.isFile();
+ m_folder = f.isDirectory();
+ m_exist = f.exists();
+ }
+ if (m_exist) {
+ m_protocol = "file";
+ }
+ }
+
+ }
+
+ /**
+ * get the base directory.
+ * @return base directory
+ */
+ public String getBaseDir() {
+ return this.m_baseDir;
+ }
+
+ public boolean isValid() {
+ return m_valid;
+ }
+
+ public boolean isRelative() {
+ return m_relative;
+ }
+
+ public boolean isExists() {
+ return m_exist;
+ }
+
+ public boolean isFile() {
+ return m_file;
+ }
+
+ public boolean isFolder() {
+ return m_folder;
+ }
+
+ /**
+ * get a File which points on the same file.
+ * @return a File object
+ */
+ public File getFile() {
+ if (!this.isValid()) { return null; }
+ String path = PathFile.uniformSeparator(this.getOnlyAbsoluteFilename());
+ if (File.separatorChar == '\\') { path = path.replace('\\', '/'); }
+ File f = new File(path);
+ return f;
+ }
+
+ /**
+ * get an URI which points on the same file.
+ * @return an URI object
+ */
+ public URI getUri() {
+ if (!this.isValid()) { return null; }
+ String path = PathFile.uniformSeparator(getAbsoluteFilename());
+ if (File.separatorChar == '\\') {
+ path = path.replace("\\", "/");
+ path = path.replace(" ", "%20");
+ }
+
+ URI uri = null;
+ try {
+ uri = new URI(path);
+ } catch (URISyntaxException e) {
+ System.err.println("Malformed URI: " + path);
+ System.err.println(e.getMessage());
+ return null;
+ }
+ return uri;
+ }
+
+ /**
+ * get protocol + relative path of this file.
+ * @return the relative path or null if it is not valid
+ */
+ public String getRelativePath() {
+ if (!this.isValid()) { return null; }
+
+ return getProtocol() + ":/" + getOnlyRelativePath();
+ }
+
+ /**
+ * get only (without protocol) relative path of this file.
+ * @return the relative path or null if it is not valid
+ */
+ public String getOnlyRelativePath() {
+ if (!this.isValid()) { return null; }
+ if (this.isRelative()) {
+ return m_pathFile;
+
+ } else {
+ if (m_baseDir != null) {
+ // System.err.println(m_pathFile);
+ // System.err.println(m_baseDir);
+ if (m_pathFile.startsWith(m_baseDir)) {
+ /*
+ * String ch1 = m_pathFile; String ch2 = m_baseDir; System.err.println(ch1); System.err.println(ch2); System.err.println("."+File.separator+ch1.substring(ch2.length()));
+ */
+ return "." + File.separator + m_pathFile.substring(m_baseDir.length());
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * calcul absolute path from relative path.
+ * @param baseDir base directory
+ * @param path path to convert
+ * @return the absolute path or null
+ */
+ private String calculAbsolutePath(String baseDir, String path) {
+ if (path.startsWith(".." + File.separatorChar)) {
+ String base = baseDir;
+ int lastIndex;
+ lastIndex = base.lastIndexOf(File.separator);
+ if (lastIndex == base.length()) {
+ base = base.substring(0, base.length() - 1);
+ lastIndex = base.lastIndexOf(File.separator);
+ }
+ if (lastIndex < base.length()) {
+ return calculAbsolutePath(base.substring(0, lastIndex + 1), path.substring(3));
+ } else {
+ return null;
+ }
+ } else if (path.startsWith("." + File.separatorChar)) {
+ String res;
+ if (File.separatorChar == '\\') {
+ res = path.replaceFirst(".", baseDir.replace('\\', '/'));
+ } else {
+ res = path.replaceFirst(".", baseDir);
+ }
+
+ return PathFile.uniformSeparator(res);
+ } else {
+ return PathFile.uniformSeparator(baseDir + path);
+ }
+ }
+
+ /**
+ * get only (without protocol) absolute path (without filename).
+ * @return absolute path
+ */
+ public String getOnlyAbsolutePath() {
+ if (!this.isValid()) { return null; }
+ if (isRelative()) {
+ return calculAbsolutePath(m_baseDir, m_pathFile);
+ } else {
+ return m_pathFile;
+ }
+ }
+
+ /**
+ * get protocol + absolute path (without filename).
+ * @return absolute path
+ */
+ public String getAbsolutePath() {
+
+ if (isRelative()) {
+ return getProtocol() + ":/" + calculAbsolutePath(m_baseDir, m_pathFile);
+ } else {
+ if (getProtocol().compareTo("") == 0 || m_pathFile == null) {
+ return m_pathFile;
+ } else {
+ return getProtocol() + ":" + m_pathFile;
+ }
+ }
+ }
+
+ /**
+ * get only (without protocol) absolute path + filename.
+ * @return absolute filename
+ */
+ public String getOnlyAbsoluteFilename() {
+ if (getOnlyAbsolutePath() != null && getFilename() != null) {
+ return getOnlyAbsolutePath() + getFilename();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * get protocol + absolute path + filename.
+ * @return absolute filenama
+ */
+ public String getAbsoluteFilename() {
+ if (getAbsolutePath() != null && getFilename() != null) {
+ return getAbsolutePath() + getFilename();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * get only (without protocol) relative path + filename.
+ * @return relative filename
+ */
+ public String getOnlyRelativeFilename() {
+ if (!this.isValid()) { return ""; }
+
+ return getOnlyRelativePath() + getFilename();
+
+ }
+
+ /**
+ * get protocol + relative path + filename.
+ * @return relative filename
+ */
+ public String getRelativeFilename() {
+ if (!this.isValid()) { return ""; }
+
+ if (this.isRelative()) {
+ return getRelativePath() + getFilename();
+ } else {
+ return getAbsoluteFilename();
+ }
+ }
+
+ public String getFilename() {
+ return m_fileName;
+ }
+
+ public String getProtocol() {
+ return m_protocol;
+ }
+
+ /**
+ * create all the directories not also present in the current path.
+ * @return true if all directories was created, else false
+ */
+ public boolean createPath() {
+ File path = new File(this.getOnlyAbsolutePath());
+ if (path.exists()) { return true; }
+ return path.mkdirs();
+ }
+
+ /**
+ * create all the directories not also present in the current path and the file.
+ * @return true it was created, else false
+ */
+ public boolean createFile() {
+ File path = new File(this.getOnlyAbsolutePath());
+ if (!path.exists()) {
+ if (!this.createPath()) { return false; }
+ }
+ path = new File(this.getOnlyAbsoluteFilename());
+ try {
+ return path.createNewFile();
+ } catch (IOException e) {
+ return false;
+ }
+
+ }
+
+ /**
+ * delete the current file.
+ * @return true if it was deleted, else false
+ */
+ public boolean delete() {
+ File path = new File(this.getAbsoluteFilename());
+ if (path.exists()) {
+ return path.delete();
+ } else {
+ return true;
+ }
+
+ }
+
+ /**
+ * replace all '\' by '\\' in the given string.
+ * @param path string where replace the search pattern
+ * @return string replaced
+ */
+ public static String doubleSeparator(String path) {
+ // double the '\' in the path
+ if (path != null && File.separatorChar == '\\') {
+ return path.replace("\\", "\\\\");
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * file separator('\' or '/') by the one of the current system.
+ * @param path string where replace the search pattern
+ * @return string replaced
+ */
+ public static String uniformSeparator(String path) {
+ if (File.separatorChar == '\\') {
+ if (path.startsWith("/")) {
+ return path.substring(1).replace('/', File.separatorChar);
+ } else {
+ return path.replace('/', File.separatorChar);
+ }
+ } else {
+ return path.replace('\\', File.separatorChar);
+ }
+ }
+
+ /**
+ * copy file from src to dest.
+ * @param src source file
+ * @param dest destination file
+ * @return true if the file was correctly copied, else false
+ */
+ public static boolean copyFile(PathFile src, PathFile dest) {
+ FileChannel in = null;
+ FileChannel out = null;
+
+ if (!src.isExists()) {
+ System.err.println("src file must exist: " + src.getAbsoluteFilename());
+ return false;
+ }
+ if (!dest.isExists()) {
+ dest.createFile();
+ }
+ try {
+ in = new FileInputStream(src.getOnlyAbsoluteFilename()).getChannel();
+ out = new FileOutputStream(dest.getOnlyAbsoluteFilename()).getChannel();
+
+ in.transferTo(0, in.size(), out);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/RemoteFileManager.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/RemoteFileManager.java
new file mode 100644
index 0000000..df2ddf0
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/RemoteFileManager.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.artifact.manager.WagonConfigurationException;
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.wagon.ConnectionException;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.UnsupportedProtocolException;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.authentication.AuthenticationException;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+import org.apache.maven.wagon.observers.Debug;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+import org.apache.maven.wagon.repository.Repository;
+
+/**
+ * this class is used to manage all connections by wagon.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class RemoteFileManager {
+
+ /**
+ * save the connection.
+ */
+ private Wagon m_wagon;
+
+ /**
+ * the wagon manager.
+ */
+ private WagonManager m_wagonManager;
+
+ /**
+ * artifact repository.
+ */
+ private ArtifactRepository m_artifactRepository;
+
+ /**
+ * the project settings.
+ */
+ private Settings m_settings;
+
+ /**
+ * logger instance.
+ */
+ private Log m_log;
+
+ /**
+ * initialize main information.
+ * @param ar ArtifactRepository provides by maven
+ * @param wm WagonManager provides by maven
+ * @param settings settings of the current project provides by maven
+ * @param log logger
+ */
+ public RemoteFileManager(ArtifactRepository ar, WagonManager wm, Settings settings, Log log) {
+ m_artifactRepository = ar;
+ m_wagonManager = wm;
+ m_settings = settings;
+ m_log = log;
+ m_wagon = null;
+ }
+
+ /**
+ * disconnect the current object.
+ *
+ */
+ public void disconnect() {
+ if (m_wagon == null) {
+ m_log.error("must be connected first!");
+ return;
+ }
+ try {
+ m_wagon.disconnect();
+ } catch (ConnectionException e) {
+ m_log.error("Error disconnecting wagon - ignored", e);
+ }
+ }
+
+ /**
+ * connect the current object to artifact repository given in constructor.
+ * @throws MojoExecutionException if connection failed
+ */
+ public void connect() throws MojoExecutionException {
+ String url = m_artifactRepository.getUrl();
+ String id = m_artifactRepository.getId();
+
+ Repository repository = new Repository(id, url);
+
+ try {
+ m_wagon = m_wagonManager.getWagon(repository);
+ //configureWagon(m_wagon, repository.getId());
+ } catch (UnsupportedProtocolException e) {
+ throw new MojoExecutionException("Unsupported protocol: '" + repository.getProtocol() + "'", e);
+ } catch (WagonConfigurationException e) {
+ throw new MojoExecutionException("Unable to configure Wagon: '" + repository.getProtocol() + "'", e);
+ }
+
+ try {
+ Debug debug = new Debug();
+ m_wagon.addTransferListener(debug);
+
+ ProxyInfo proxyInfo = getProxyInfo(m_settings);
+ if (proxyInfo != null) {
+ m_wagon.connect(repository, m_wagonManager.getAuthenticationInfo(id), proxyInfo);
+ } else {
+ m_wagon.connect(repository, m_wagonManager.getAuthenticationInfo(id));
+ }
+
+ } catch (ConnectionException e) {
+ throw new MojoExecutionException("Error uploading file", e);
+ } catch (AuthenticationException e) {
+ throw new MojoExecutionException("Error uploading file", e);
+ }
+ }
+
+ /**
+ * get a file from the current repository connected.
+ * @param url url to the targeted file
+ * @return get a file descriptor on the requiered resource
+ * @throws IOException if an IO error occurs
+ * @throws TransferFailedException if the transfer failed
+ * @throws ResourceDoesNotExistException if the targeted resource doesn't exist
+ * @throws AuthorizationException if the connection authorization failed
+ */
+ public File get(String url) throws IOException, TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
+
+ if (m_wagon == null) {
+ m_log.error("must be connected first!");
+ return null;
+ }
+
+ File file = File.createTempFile(String.valueOf(System.currentTimeMillis()), "tmp");
+ m_wagon.get(url, file);
+ return file;
+ }
+
+ /**
+ * put a file on the current repository connected.
+ * @param file file to upload
+ * @param url url to copy file
+ * @throws TransferFailedException if the transfer failed
+ * @throws ResourceDoesNotExistException if the targeted resource doesn't exist
+ * @throws AuthorizationException if the connection authorization failed
+ */
+ public void put(File file, String url) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
+ if (m_wagon == null) {
+ m_log.error("must be connected first!");
+ return;
+ }
+ m_wagon.put(file, url);
+ }
+
+ /**
+ * Convenience method to map a Proxy object from the user system settings to a ProxyInfo object.
+ * @param settings project settings given by maven
+ * @return a proxyInfo object instancied or null if no active proxy is define in the settings.xml
+ */
+ public static ProxyInfo getProxyInfo(Settings settings) {
+ ProxyInfo proxyInfo = null;
+ if (settings != null && settings.getActiveProxy() != null) {
+ Proxy settingsProxy = settings.getActiveProxy();
+
+ proxyInfo = new ProxyInfo();
+ proxyInfo.setHost(settingsProxy.getHost());
+ proxyInfo.setType(settingsProxy.getProtocol());
+ proxyInfo.setPort(settingsProxy.getPort());
+ proxyInfo.setNonProxyHosts(settingsProxy.getNonProxyHosts());
+ proxyInfo.setUserName(settingsProxy.getUsername());
+ proxyInfo.setPassword(settingsProxy.getPassword());
+ }
+
+ return proxyInfo;
+ }
+
+ /**
+ * this method indicates if the targeted file is locked or not.
+ * @param remote connection manager
+ * @param fileName name targeted
+ * @return true if thr reuiered file is locked, else false
+ * @throws MojoFailureException if the plugin failed
+ */
+ public boolean isLockedFile(RemoteFileManager remote, String fileName) throws MojoFailureException {
+ File file = null;
+ try {
+ file = remote.get(fileName + ".lock");
+ } catch (TransferFailedException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("TransferFailedException");
+
+ } catch (ResourceDoesNotExistException e) {
+ return false;
+ } catch (AuthorizationException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("AuthorizationException");
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new MojoFailureException("IOException");
+ }
+ if (file != null && file.length() == 0) { return false; }
+ return true;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Require.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Require.java
new file mode 100644
index 0000000..d46e463
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/Require.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * this class store a Require tag.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Require {
+
+ /**
+ * store the extend attribute.
+ */
+ private String m_extend;
+
+ /**
+ * store the multiple attribute.
+ */
+ private String m_multiple;
+
+ /**
+ * store the optional attribute.
+ */
+ private String m_optional;
+
+ /**
+ * store the name attribute.
+ */
+ private String m_name;
+
+ /**
+ * store the filter attribute.
+ */
+ private String m_filter;
+
+ /**
+ * store the value of the tag.
+ */
+ private String m_value;
+
+ /**
+ * get the extend attribute.
+ * @return a string which contains the value of the boolean
+ */
+ public String getExtend() {
+ return m_extend;
+ }
+
+ /**
+ * set the extend attribute.
+ * @param extend new value for the extend attribute
+ */
+ public void setExtend(String extend) {
+ this.m_extend = extend;
+ }
+
+ /**
+ * get the filter attribute.
+ * @return m_filter value
+ */
+ public String getFilter() {
+ return m_filter;
+ }
+
+ /**
+ * set the filter attribute.
+ * @param filter new value for filter
+ */
+ public void setFilter(String filter) {
+ this.m_filter = filter;
+ }
+
+ /**
+ * get multiple attribute.
+ * @return m_multiple value
+ */
+ public String getMultiple() {
+ return m_multiple;
+ }
+
+ /**
+ * set multiple attribute.
+ * @param multiple new value for m_multiple
+ */
+ public void setMultiple(String multiple) {
+ this.m_multiple = multiple;
+ }
+
+ /**
+ * get name attribute.
+ * @return m_name value
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * set name attribute.
+ * @param name new value for m_name
+ */
+ public void setName(String name) {
+ this.m_name = name;
+ }
+
+ /**
+ * get the optional attribute.
+ * @return m_optional value
+ */
+ public String getOptional() {
+ return m_optional;
+ }
+
+ /**
+ * set the optional attribute.
+ * @param optionnal new value for m_optional
+ */
+ public void setOptional(String optionnal) {
+ this.m_optional = optionnal;
+ }
+
+ /**
+ * get value of the tag.
+ * @return value of this tag
+ */
+ public String getValue() {
+ return m_value;
+ }
+
+ /**
+ * set the value of the tag.
+ * @param value new value for this tag
+ */
+ public void setValue(String value) {
+ this.m_value = value;
+ }
+
+ /**
+ * transform this object to Node.
+ *
+ * @param father father document for create Node
+ * @return node
+ */
+ public Node getNode(Document father) {
+ Element require = father.createElement("require");
+ require.setAttribute("name", this.getName());
+ require.setAttribute("filter", this.getFilter());
+ require.setAttribute("extend", this.getExtend());
+ require.setAttribute("multiple", this.getMultiple());
+ require.setAttribute("optional", this.getOptional());
+ require.setTextContent(this.getValue());
+
+ return require;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ResourcesBundle.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ResourcesBundle.java
new file mode 100644
index 0000000..7a3744c
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ResourcesBundle.java
@@ -0,0 +1,520 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.sandbox.obr.plugin;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * this class describe all information by bundle.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResourcesBundle {
+ /**
+ * store the bundle symbolic name.
+ */
+ private String m_symbolicName;
+
+ /**
+ * store the bundle presentation name.
+ */
+ private String m_presentationName;
+
+ /**
+ * store the bundle version.
+ */
+ private String m_version;
+
+ /**
+ * store the bundle URI.
+ */
+ private String m_uri;
+
+ /**
+ * store the bundle description.
+ */
+ private String m_description;
+
+ /**
+ * store the bundle size.
+ */
+ private String m_size;
+
+ /**
+ * store the bundle documentation.
+ */
+ private String m_documentation;
+
+ /**
+ * store the bundle source.
+ */
+ private String m_source;
+
+ /**
+ * store the bundle license.
+ */
+ private String m_license;
+
+ /**
+ * store the bundle id.
+ */
+ private String m_id;
+
+ /**
+ * store the bundle categories.
+ */
+ private List m_category = new ArrayList();
+
+ /**
+ * store the bundle capabilities.
+ */
+ private List m_capability = new ArrayList();
+
+ /**
+ * store the bundle requirement.
+ */
+ private List m_require = new ArrayList();
+
+ /**
+ * get the plugin logger.
+ */
+ private Log m_logger;
+
+ /**
+ * initialize logger.
+ * @param log log use by plugin
+ */
+ public ResourcesBundle(Log log) {
+ m_logger = log;
+ }
+
+ public List getCapability() {
+ return m_capability;
+ }
+
+ public void setCapability(List capability) {
+ this.m_capability = capability;
+ }
+
+ public List getCategory() {
+ return m_category;
+ }
+
+ public void setCategory(List category) {
+ this.m_category = category;
+ }
+
+ public String getLicense() {
+ return m_license;
+ }
+
+ public void setLicense(String license) {
+ this.m_license = license;
+ }
+
+ public String getDescription() {
+ return m_description;
+ }
+
+ public void setDescription(String description) {
+ this.m_description = description;
+ }
+
+ public String getDocumentation() {
+ return m_documentation;
+ }
+
+ public void setDocumentation(String documentation) {
+ this.m_documentation = documentation;
+ }
+
+ public String getPresentationName() {
+ return m_presentationName;
+ }
+
+ public void setPresentationName(String name) {
+ m_presentationName = name;
+ }
+
+ public String getSize() {
+ return m_size;
+ }
+
+ public void setSize(String size) {
+ this.m_size = size;
+ }
+
+ public String getSymbolicName() {
+ return m_symbolicName;
+ }
+
+ public void setSymbolicName(String name) {
+ m_symbolicName = name;
+ }
+
+ public String getUri() {
+ return m_uri;
+ }
+
+ public void setUri(String url) {
+ this.m_uri = url;
+ }
+
+ public String getVersion() {
+ return m_version;
+ }
+
+ public void setVersion(String version) {
+ this.m_version = version;
+ }
+
+ public List getRequire() {
+ return m_require;
+ }
+
+ public void setRequire(List require) {
+ this.m_require = require;
+ }
+
+ public String getSource() {
+ return m_source;
+ }
+
+ public void setSource(String source) {
+ this.m_source = source;
+ }
+
+ public String getId() {
+ return m_id;
+ }
+
+ public void setId(String id) {
+ this.m_id = id;
+ }
+
+ /**
+ * add a new capability for this bundle description.
+ * @param capability the Capability to add
+ */
+ public void addCapability(Capability capability) {
+ m_capability.add(capability);
+ }
+
+ /**
+ * add a new requirement for this bundle description.
+ * @param require th Require to add
+ */
+ public void addRequire(Require require) {
+ m_require.add(require);
+ }
+
+ /**
+ * add a new category for this bundle decription.
+ * @param category the Category to add
+ */
+ public void addCategory(Category category) {
+ m_category.add(category);
+ }
+
+ /**
+ * transform this object to Node.
+ * tranform all sub-object to node also
+ * @param father father document for create Node
+ * @return node
+ */
+ public Node getNode(Document father) {
+ // return the complete resource tree
+ if (!this.isValid() || this.getId() == null) {
+ m_logger.error("those properties was not defined:" + this.getInvalidProperties());
+ return null;
+ }
+
+ Element resource = father.createElement("resource");
+ Element description = father.createElement("description");
+ Element size = father.createElement("size");
+ Element documentation = father.createElement("documentation");
+ Element source = father.createElement("source");
+ Element license = father.createElement("license");
+
+ resource.setAttribute("id", this.getId());
+ resource.setAttribute("symbolicname", this.getSymbolicName());
+ resource.setAttribute("presentationname", this.getPresentationName());
+ resource.setAttribute("uri", this.getUri());
+ resource.setAttribute("version", this.getVersion());
+
+ description.setTextContent(this.getDescription());
+ resource.appendChild(description);
+
+ size.setTextContent(this.getSize());
+ resource.appendChild(size);
+
+ if (this.getDocumentation() != null) {
+ documentation.setTextContent(this.getDocumentation());
+ resource.appendChild(documentation);
+ }
+
+ if (this.getSource() != null) {
+ source.setTextContent(this.getSource());
+ resource.appendChild(source);
+ }
+
+ if (this.getLicense() != null) {
+ license.setTextContent(this.getLicense());
+ resource.appendChild(license);
+ }
+
+ List list = (ArrayList) this.getNodeCategories(father);
+ for (int i = 0; i < list.size(); i++) {
+ resource.appendChild((Node) list.get(i));
+ }
+
+ list = (ArrayList) this.getNodeCapabilities(father);
+ for (int i = 0; i < list.size(); i++) {
+ resource.appendChild((Node) list.get(i));
+ }
+
+ list = (ArrayList) this.getNodeRequirement(father);
+ for (int i = 0; i < list.size(); i++) {
+ resource.appendChild((Node) list.get(i));
+ }
+
+ return resource;
+ }
+
+ /**
+ * this method gets information form pom.xml to complete missing data from those given by user.
+ * @param project project information given by maven
+ * @param ebi bundle information extracted from bindex
+ * @return true
+ */
+ public boolean construct(MavenProject project, ExtractBindexInfo ebi) {
+
+ if (ebi.getPresentationName() != null) {
+ this.setPresentationName(ebi.getPresentationName());
+ if (project.getName() != null) { m_logger.warn("pom property override:<presentationname> " + project.getName()); }
+ } else {
+ this.setPresentationName(project.getName());
+ }
+
+ if (ebi.getSymbolicName() != null) {
+ this.setSymbolicName(ebi.getSymbolicName());
+ if (project.getArtifactId() != null) { m_logger.warn("pom property override:<symbolicname> " + project.getArtifactId()); }
+ } else {
+ this.setSymbolicName(project.getArtifactId());
+ }
+
+ if (ebi.getVersion() != null) {
+ this.setVersion(ebi.getVersion());
+ if (project.getVersion() != null) { m_logger.warn("pom property override:<version> " + project.getVersion()); }
+ } else {
+ this.setVersion(project.getVersion());
+ }
+
+ if (ebi.getDescription() != null) {
+ this.setDescription(ebi.getDescription());
+ if (project.getDescription() != null) { m_logger.warn("pom property override:<description> " + project.getDescription()); }
+ } else {
+ this.setDescription(project.getDescription());
+ }
+
+ if (ebi.getDocumentation() != null) {
+ this.setDocumentation(ebi.getDocumentation());
+ if (project.getUrl() != null) { m_logger.warn("pom property override:<documentation> " + project.getUrl()); }
+ } else {
+ this.setDocumentation(project.getUrl());
+ }
+
+ if (ebi.getSource() != null) {
+ this.setSource(ebi.getSource());
+ if (project.getScm() != null) { m_logger.warn("pom property override:<source> " + project.getScm()); }
+ } else {
+ String src = null;
+ if (project.getScm() != null) { src = project.getScm().getUrl(); }
+ this.setSource(src);
+ }
+
+ if (ebi.getLicense() != null) {
+ this.setLicense(ebi.getLicense());
+ String lic = null;
+ List l = project.getLicenses();
+ Iterator it = l.iterator();
+ while (it.hasNext()) {
+ if (it.next() != null) {
+ m_logger.warn("pom property override:<source> " + lic);
+ break;
+ }
+ }
+ } else {
+ String lic = null;
+ List l = project.getLicenses();
+ Iterator it = l.iterator();
+ while (it.hasNext()) {
+ lic = it.next() + ";";
+ }
+
+ this.setLicense(lic);
+ }
+
+ // create the first capability (ie : bundle)
+ Capability capability = new Capability();
+ capability.setName("bundle");
+ PElement p = new PElement();
+ p.setN("manifestversion");
+ p.setV("2");
+ capability.addP(p);
+
+ p = new PElement();
+ p.setN("presentationname");
+ p.setV(this.getPresentationName());
+ capability.addP(p);
+
+ p = new PElement();
+ p.setN("symbolicname");
+ p.setV(this.getSymbolicName());
+ capability.addP(p);
+
+ p = new PElement();
+ p.setN("version");
+ p.setT("version");
+ p.setV(this.getVersion());
+ capability.addP(p);
+
+ this.addCapability(capability);
+
+ List capabilities = (ArrayList) ebi.getCapabilities();
+ for (int i = 0; i < capabilities.size(); i++) {
+ this.addCapability((Capability) capabilities.get(i));
+ }
+
+ List requirement = (ArrayList) ebi.getRequirement();
+ for (int i = 0; i < requirement.size(); i++) {
+ this.addRequire((Require) requirement.get(i));
+ }
+
+ // we also add the goupId
+ Category category = new Category();
+ category.setId(project.getGroupId());
+ this.addCategory(category);
+
+ return true;
+ }
+
+ /**
+ * return if the bundle resource is complete.
+ * @return false if an information is missing, else true
+ */
+ public boolean isValid() {
+ // we must verify require properties are present
+ return this.getPresentationName() != null
+ && this.getSymbolicName() != null
+ && this.getVersion() != null
+ && this.getUri() != null
+ && this.getSize() != null;
+ }
+
+ /**
+ * test if this bundle has the same symbolicname, presentationname and version number.
+ * @param symbolicName symbolicName to compare with current bundle
+ * @param presentationName presentationName to compare with current bundlde
+ * @param version version to compare with current bundle
+ * @return true if the information are the same, else false
+ */
+ public boolean isSameBundleResource(String symbolicName, String presentationName, String version) {
+ if (this.isValid()) {
+ boolean result;
+ result = (symbolicName.compareTo(this.getSymbolicName()) == 0) && (version.compareTo(this.getVersion()) == 0) && (presentationName.compareTo(this.getPresentationName()) == 0);
+ return result;
+
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * return a list of categories transformed to node.
+ * @param father father document to create node from same document
+ * @return List of Node
+ */
+ private List getNodeCategories(Document father) {
+ List listNode = new ArrayList();
+ List listCategory = (ArrayList) this.getCategory();
+ for (int i = 0; i < listCategory.size(); i++) {
+ listNode.add(((Category) listCategory.get(i)).getNode(father));
+ }
+ return listNode;
+ }
+
+ /**
+ * return a list of capabilities transformed to node.
+ * @param father father document to create node from same document
+ * @return List of Node
+ */
+ private List getNodeCapabilities(Document father) {
+ List listNode = new ArrayList();
+ List listCapability = (ArrayList) this.getCapability();
+ for (int i = 0; i < listCapability.size(); i++) {
+ listNode.add(((Capability) listCapability.get(i)).getNode(father));
+ }
+ return listNode;
+ }
+
+ /**
+ * return a list of requirement transformed to node.
+ * @param father father document to create node from same document
+ * @return List of Node.
+ */
+ private List getNodeRequirement(Document father) {
+ List listNode = new ArrayList();
+ List listRequirement = (ArrayList) this.getRequire();
+ for (int i = 0; i < listRequirement.size(); i++) {
+ listNode.add(((Require) listRequirement.get(i)).getNode(father));
+ }
+ return listNode;
+ }
+
+ /**
+ * return the list of properties not define in this bundle resource.
+ * @return list of properties not define
+ */
+ private String getInvalidProperties() {
+ if (this.isValid()) {
+ if (this.getId() == null) {
+ return "id";
+ } else {
+ return "";
+ }
+ }
+ String result = "";
+ if (this.getPresentationName() == null) { result = result + "presentationName;"; }
+ if (this.getSymbolicName() == null) { result = result + "symbolicName;"; }
+ if (this.getVersion() == null) { result = result + "version;"; }
+ if (this.getUri() == null) { result = result + "Uri;"; }
+ if (this.getSize() == null) { result = result + "Size"; }
+ return result;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/BundleInfo.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/BundleInfo.java
new file mode 100644
index 0000000..5da803b
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/BundleInfo.java
@@ -0,0 +1,490 @@
+package org.osgi.impl.bundle.obr.resource;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import java.util.zip.*;
+
+import org.osgi.service.obr.Resource;
+
+/**
+ * Convert a bundle to a generic resource description and store its local
+ * dependencies (like for example a license file in the JAR) in a zip file.
+ *
+ * @version $Revision: 1.18 $
+ */
+public class BundleInfo {
+ Manifest manifest;
+ File bundleJar;
+ ZipFile jar;
+ String license;
+ Properties localization;
+ RepositoryImpl repository;
+
+ /**
+ * Parse a zipFile from the file system. We only need the manifest and the
+ * localization. So a zip file is used to minimze memory consumption.
+ *
+ * @param bundleJar Path name
+ * @throws Exception Any errors that occur
+ */
+ public BundleInfo(RepositoryImpl repository, File bundleJar) throws Exception {
+ this.bundleJar = bundleJar;
+ this.repository = repository;
+
+ if (!this.bundleJar.exists())
+ throw new FileNotFoundException(bundleJar.toString());
+
+ jar = new ZipFile(bundleJar);
+ ZipEntry entry = jar.getEntry("META-INF/MANIFEST.MF");
+ if (entry == null)
+ throw new FileNotFoundException("No Manifest in "
+ + bundleJar.toString());
+ manifest = new Manifest(jar.getInputStream(entry));
+ }
+
+ public BundleInfo(Manifest manifest) throws Exception {
+ this.manifest = manifest;
+ }
+
+ /**
+ * Convert the bundle to a Resource. All URIs are going to be abslute, but
+ * could be local.
+ *
+ * @return the resource
+ * @throws Exception
+ */
+ public ResourceImpl build() throws Exception {
+ ResourceImpl resource;
+ // Setup the manifest
+ // and create a resource
+ resource = new ResourceImpl(repository, manifest.getSymbolicName(), manifest
+ .getVersion());
+
+ try {
+
+ // Calculate the location URL of the JAR
+ URL location = new URL("jar:" + bundleJar.toURL().toString() + "!/");
+ resource.setURL(bundleJar.toURL());
+ resource.setFile(bundleJar);
+
+ doReferences(resource, location);
+ doSize(resource);
+ doCategories(resource);
+ doImportExportServices(resource);
+ doDeclarativeServices(resource);
+ doFragment(resource);
+ doRequires(resource);
+ doBundle(resource);
+ doExports(resource);
+ doImports(resource);
+ doExecutionEnvironment(resource);
+
+ return resource;
+ }
+ finally {
+ try {
+ jar.close();
+ }
+ catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Check the size and add it.
+ *
+ * @param resource
+ */
+ void doSize(ResourceImpl resource) {
+ long size = bundleJar.length();
+ if (size > 0)
+ resource.setSize(size);
+ }
+
+ /**
+ * Find the categories, break them up and add them.
+ *
+ * @param resource
+ */
+ void doCategories(ResourceImpl resource) {
+ for (int i = 0; i < manifest.getCategories().length; i++) {
+ String category = manifest.getCategories()[i];
+ resource.addCategory(category);
+ }
+ }
+
+ void doReferences(ResourceImpl resource, URL location) {
+ // Presentation name
+ String name = translated("Bundle-Name");
+ if (name != null)
+ resource.setPresentationName(name);
+
+ // Handle license. -l allows a global license
+ // set when no license is included.
+
+ String license = translated("Bundle-License");
+ if (license != null)
+ resource.setLicense(toURL(location, license));
+ else if (this.license != null)
+ resource.setLicense(toURL(location, this.license));
+
+ String description = translated("Bundle-Description");
+ if (description != null)
+ resource.setDescription(description);
+
+ String copyright = translated("Bundle-Copyright");
+ if (copyright != null)
+ resource.setCopyright(copyright);
+
+ String documentation = translated("Bundle-DocURL");
+ if (documentation != null)
+ resource.setDocumentation(toURL(location, documentation));
+
+ String source = manifest.getValue("Bundle-Source");
+ if (source != null)
+ resource.setSource(toURL(location, source));
+ }
+
+ URL toURL(URL location, String source) {
+ try {
+ return new URL(location, source);
+ }
+ catch (Exception e) {
+ System.err.println("Error in converting url: " + location + " : "
+ + source);
+ return null;
+ }
+ }
+
+ void doDeclarativeServices(ResourceImpl resource) throws Exception {
+ String serviceComponent = manifest.getValue("service-component");
+ if (serviceComponent == null)
+ return;
+
+ StringTokenizer st = new StringTokenizer(serviceComponent, " ,\t");
+ String parts[] = new String[st.countTokens()];
+ for (int i = 0; i < parts.length; i++)
+ parts[i] = st.nextToken();
+
+ for (int i = 0; i < parts.length; i++) {
+ ZipEntry entry = jar.getEntry(parts[i]);
+ if (entry == null) {
+ System.err.println("Bad Service-Component header: "
+ + serviceComponent + ", no such file " + parts[i]);
+ }
+ InputStream in = jar.getInputStream(entry);
+ // TODO parse declarative services files.
+ in.close();
+ }
+ }
+
+ void doImportExportServices(ResourceImpl resource) throws IOException {
+ String importServices = manifest.getValue("import-service");
+ if (importServices != null) {
+ List entries = manifest.getEntries(importServices);
+ for (Iterator i = entries.iterator(); i.hasNext();) {
+ ManifestEntry entry = (ManifestEntry) i.next();
+ RequirementImpl ri = new RequirementImpl("service");
+ ri.setFilter(createServiceFilter(entry));
+ ri.setComment("Import Service " + entry.getName());
+
+ // TODO the following is arbitrary
+ ri.setOptional(true);
+ ri.setMultiple(false);
+ resource.addRequirement(ri);
+ }
+ }
+
+ String exportServices = manifest.getValue("export-service");
+ if (exportServices != null) {
+ List entries = manifest.getEntries(exportServices);
+ for (Iterator i = entries.iterator(); i.hasNext();) {
+ ManifestEntry entry = (ManifestEntry) i.next();
+ CapabilityImpl cap = createServiceCapability(entry);
+ resource.addCapability(cap);
+ }
+ }
+ }
+
+ String translated(String key) {
+ return translate(manifest.getValue(key));
+ }
+
+ void doFragment(ResourceImpl resource) {
+ // Check if we are a fragment
+ ManifestEntry entry = manifest.getHost();
+ if (entry == null) {
+ return;
+ }
+ else {
+ // We are a fragment, create a requirement
+ // to our host.
+ RequirementImpl r = new RequirementImpl("bundle");
+ StringBuffer sb = new StringBuffer();
+ sb.append("(&(symbolicname=");
+ sb.append(entry.getName());
+ sb.append(")(version>=");
+ sb.append(entry.getVersion());
+ sb.append("))");
+ r.setFilter(sb.toString());
+ r.setComment("Required Host " + entry.getName() );
+ r.setExtend(true);
+ r.setOptional(false);
+ r.setMultiple(false);
+ resource.addRequirement(r);
+
+ // And insert a capability that we are available
+ // as a fragment. ### Do we need that with extend?
+ CapabilityImpl capability = new CapabilityImpl("fragment");
+ capability.addProperty("host", entry.getName());
+ capability.addProperty("version", entry.getVersion());
+ resource.addCapability(capability);
+ }
+ }
+
+ void doRequires(ResourceImpl resource) {
+ List entries = manifest.getRequire();
+ if (entries == null)
+ return;
+
+ for (Iterator i = entries.iterator(); i.hasNext();) {
+ ManifestEntry entry = (ManifestEntry) i.next();
+ RequirementImpl r = new RequirementImpl("bundle");
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("(&(symbolicname=");
+ sb.append(entry.getName());
+ sb.append(")(version>=");
+ sb.append(entry.getVersion());
+ sb.append("))");
+ r.setFilter(sb.toString());
+ r.setComment("Require Bundle " + entry.getName() + "; "
+ + entry.getVersion());
+ if (entry.directives == null
+ || "true".equalsIgnoreCase((String) entry.directives
+ .get("resolution")))
+ r.setOptional(false);
+ else
+ r.setOptional(true);
+ resource.addRequirement(r);
+ }
+ }
+
+ void doExecutionEnvironment(ResourceImpl resource) {
+ String[] parts = manifest.getRequiredExecutionEnvironments();
+ if (parts == null)
+ return;
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("(|");
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ sb.append("(ee=");
+ sb.append(part);
+ sb.append(")");
+ }
+ sb.append(")");
+
+ RequirementImpl req = new RequirementImpl("ee");
+ req.setFilter(sb.toString());
+ req.setComment("Execution Environment " + sb.toString());
+ resource.addRequirement(req);
+ }
+
+ void doImports(ResourceImpl resource) {
+ List requirements = new ArrayList();
+ List packages = manifest.getImports();
+ if (packages == null)
+ return;
+
+ for (Iterator i = packages.iterator(); i.hasNext();) {
+ ManifestEntry pack = (ManifestEntry) i.next();
+ RequirementImpl requirement = new RequirementImpl("package");
+
+ createImportFilter(requirement, "package", pack);
+ requirement.setComment("Import package " + pack);
+ requirements.add(requirement);
+ }
+ for (Iterator i = requirements.iterator(); i.hasNext();)
+ resource.addRequirement((RequirementImpl) i.next());
+ }
+
+ String createServiceFilter(ManifestEntry pack) {
+ StringBuffer filter = new StringBuffer();
+ filter.append("(service=");
+ filter.append(pack.getName());
+ filter.append(")");
+ return filter.toString();
+ }
+
+ void createImportFilter(RequirementImpl req, String name, ManifestEntry pack) {
+ StringBuffer filter = new StringBuffer();
+ filter.append("(&(");
+ filter.append(name);
+ filter.append("=");
+ filter.append(pack.getName());
+ filter.append(")");
+ VersionImpl version = pack.getVersion();
+ if (version != null) {
+ VersionRange range = version.getRange();
+ if (range != null) {
+ filter.append("(version");
+ filter.append(">");
+ if (range.getIncludeMinimum())
+ filter.append("=");
+ filter.append(range.getMinimum());
+ filter.append(")");
+
+ filter.append("(version");
+ filter.append("<");
+ if (range.getIncludeMaximum())
+ filter.append("=");
+ filter.append(range.getMaximum());
+ filter.append(")");
+ }
+ else {
+ filter.append("(version>=");
+ filter.append(pack.getVersion());
+ filter.append(")");
+ }
+ }
+ Map attributes = pack.getAttributes();
+ Set attrs = doImportPackageAttributes(req, filter, attributes);
+ if (attrs.size() > 0) {
+ String del = "";
+ filter.append("(mandatory:<*");
+ for (Iterator i = attrs.iterator(); i.hasNext();) {
+ filter.append(del);
+ filter.append(i.next());
+ del = ", ";
+ }
+ filter.append(")");
+ }
+ filter.append(")");
+ req.setFilter(filter.toString());
+ }
+
+ Set doImportPackageAttributes(RequirementImpl req, StringBuffer filter,
+ Map attributes) {
+ HashSet set = new HashSet();
+
+ if (attributes != null)
+ for (Iterator i = attributes.keySet().iterator(); i.hasNext();) {
+ String attribute = (String) i.next();
+ String value = (String) attributes.get(attribute);
+ if (attribute.equalsIgnoreCase("specification-version")
+ || attribute.equalsIgnoreCase("version"))
+ continue;
+ else if (attribute.equalsIgnoreCase("resolution:")) {
+ req.setOptional(value.equalsIgnoreCase("optional"));
+ }
+ if (attribute.endsWith(":")) {
+ // Ignore
+ }
+ else {
+ filter.append("(");
+ filter.append(attribute);
+ filter.append("=");
+ filter.append(attributes.get(attribute));
+ filter.append(")");
+ set.add(attribute);
+ }
+ }
+ return set;
+ }
+
+ void doBundle(ResourceImpl resource) {
+ CapabilityImpl capability = new CapabilityImpl("bundle");
+ capability.addProperty("symbolicname", manifest.getSymbolicName());
+ if (manifest.getValue("Bundle-Name") != null)
+ capability.addProperty(
+ Resource.PRESENTATION_NAME,
+ translated("Bundle-Name"));
+ capability.addProperty("version", manifest.getVersion());
+ capability
+ .addProperty("manifestversion", manifest.getManifestVersion());
+
+ /**
+ * Is this needed TODO
+ */
+ ManifestEntry host = manifest.getHost();
+ if (host != null) {
+ capability.addProperty("host", host.getName());
+ if (host.getVersion() != null)
+ capability.addProperty("version", host.getVersion());
+ }
+ resource.addCapability(capability);
+ }
+
+ void doExports(ResourceImpl resource) {
+ List capabilities = new ArrayList();
+ List packages = manifest.getExports();
+ if (packages != null) {
+ for (Iterator i = packages.iterator(); i.hasNext();) {
+ ManifestEntry pack = (ManifestEntry) i.next();
+ CapabilityImpl capability = createCapability("package", pack);
+ capabilities.add(capability);
+ }
+ }
+ for (Iterator i = capabilities.iterator(); i.hasNext();)
+ resource.addCapability((CapabilityImpl) i.next());
+ }
+
+ CapabilityImpl createServiceCapability(ManifestEntry pack) {
+ CapabilityImpl capability = new CapabilityImpl("service");
+ capability.addProperty("service", pack.getName());
+ return capability;
+ }
+
+ CapabilityImpl createCapability(String name, ManifestEntry pack) {
+ CapabilityImpl capability = new CapabilityImpl(name);
+ capability.addProperty(name, pack.getName());
+ capability.addProperty("version", pack.getVersion());
+ Map attributes = pack.getAttributes();
+ if (attributes != null)
+ for (Iterator at = attributes.keySet().iterator(); at.hasNext();) {
+ String key = (String) at.next();
+ if (key.equalsIgnoreCase("specification-version")
+ || key.equalsIgnoreCase("version"))
+ continue;
+ else {
+ Object value = attributes.get(key);
+ capability.addProperty(key, value);
+ }
+ }
+ return capability;
+ }
+
+ String translate(String s) {
+ if (s == null)
+ return null;
+
+ if (!s.startsWith("%")) {
+ return s;
+ }
+
+ if (localization == null)
+ try {
+ localization = new Properties();
+ String path = manifest
+ .getValue("Bundle-Localization", "bundle");
+ path += ".properties";
+ InputStream in = jar.getInputStream(new ZipEntry(path));
+ if (in != null) {
+ localization.load(in);
+ in.close();
+ }
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ s = s.substring(1);
+ return localization.getProperty(s, s);
+ }
+
+ File getZipFile() {
+ return bundleJar;
+ }
+}
\ No newline at end of file
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/CapabilityImpl.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/CapabilityImpl.java
new file mode 100644
index 0000000..34b0460
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/CapabilityImpl.java
@@ -0,0 +1,92 @@
+package org.osgi.impl.bundle.obr.resource;
+
+import java.util.*;
+
+import org.osgi.service.obr.Capability;
+import org.xmlpull.v1.XmlPullParser;
+
+
+
+public class CapabilityImpl implements Capability {
+ String name;
+ Map properties = new TreeMap();
+
+ public CapabilityImpl(String name) {
+ this.name = name;
+ }
+
+ public CapabilityImpl(XmlPullParser parser) throws Exception {
+ parser.require(XmlPullParser.START_TAG, null, "capability");
+ name = parser.getAttributeValue(null,"name");
+ while ( parser.nextTag() == XmlPullParser.START_TAG ) {
+ if ( parser.getName().equals("p")) {
+ String name = parser.getAttributeValue(null,"n");
+ String value = parser.getAttributeValue(null,"v");
+ String type = parser.getAttributeValue(null,"t");
+ Object v = value;
+
+ if ( "nummeric".equals(type))
+ v = new Long(value);
+ else if ( "version".equals(type))
+ v = new VersionImpl(value);
+ addProperty(name,v);
+ }
+ parser.next();
+ parser.require(XmlPullParser.END_TAG, null, "p" );
+ }
+ parser.require(XmlPullParser.END_TAG, null, "capability" );
+ }
+
+
+ public void addProperty(String key, Object value) {
+ List values = (List) properties.get(key);
+ if (values == null) {
+ values = new ArrayList();
+ properties.put(key, values);
+ }
+ values.add(value);
+ }
+
+ public Tag toXML() {
+ return toXML(this);
+ }
+
+ public static Tag toXML(Capability capability) {
+ Tag tag = new Tag("capability");
+ tag.addAttribute("name", capability.getName());
+ Map properties = capability.getProperties();
+ for ( Iterator k= properties.keySet().iterator(); k.hasNext(); ) {
+ String key = (String) k.next();
+ List values = (List) properties.get(key);
+ for ( Iterator v = values.iterator(); v.hasNext(); ) {
+ Object value = v.next();
+ Tag p = new Tag("p");
+ tag.addContent(p);
+ p.addAttribute("n", key);
+ if ( value != null )
+ p.addAttribute("v", value.toString());
+ else
+ System.out.println("Missing value " + key);
+ String type = null;
+ if (value instanceof Number )
+ type = "number";
+ else if (value.getClass() == VersionImpl.class)
+ type = "version";
+ if (type != null)
+ p.addAttribute("t", type);
+ }
+ }
+ return tag;
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+
+ public Map getProperties() {
+ return properties;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/FilterImpl.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/FilterImpl.java
new file mode 100644
index 0000000..d6fc637
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/FilterImpl.java
@@ -0,0 +1,431 @@
+/**
+ * Copyright (c) 2000 Gatespace AB. All Rights Reserved.
+ *
+ * Gatespace grants Open Services Gateway Initiative (OSGi) an irrevocable,
+ * perpetual, non-exclusive, worldwide, paid-up right and license to
+ * reproduce, display, perform, prepare and have prepared derivative works
+ * based upon and distribute and sublicense this material and derivative
+ * works thereof as set out in the OSGi MEMBER AGREEMENT as of January 24
+ * 2000, for use in accordance with Section 2.2 of the BY-LAWS of the
+ * OSGi MEMBER AGREEMENT.
+ */
+
+package org.osgi.impl.bundle.obr.resource;
+
+import java.lang.reflect.*;
+import java.math.BigInteger;
+import java.util.*;
+
+public class FilterImpl {
+ final char WILDCARD = 65535;
+
+ final int EQ = 0;
+ final int LE = 1;
+ final int GE = 2;
+ final int APPROX = 3;
+ final int LESS = 4;
+ final int GREATER = 5;
+ final int SUBSET = 6;
+ final int SUPERSET = 7;
+
+ private String filter;
+
+ abstract class Query {
+ static final String GARBAGE = "Trailing garbage";
+ static final String MALFORMED = "Malformed query";
+ static final String EMPTY = "Empty list";
+ static final String SUBEXPR = "No subexpression";
+ static final String OPERATOR = "Undefined operator";
+ static final String TRUNCATED = "Truncated expression";
+ static final String EQUALITY = "Only equality supported";
+
+ private String tail;
+
+ boolean match() throws IllegalArgumentException {
+ tail = filter;
+ boolean val = doQuery();
+ if (tail.length() > 0)
+ error(GARBAGE);
+ return val;
+ }
+
+ private boolean doQuery() throws IllegalArgumentException {
+ if (tail.length() < 3 || !prefix("("))
+ error(MALFORMED);
+ boolean val;
+
+ switch (tail.charAt(0)) {
+ case '&' :
+ val = doAnd();
+ break;
+ case '|' :
+ val = doOr();
+ break;
+ case '!' :
+ val = doNot();
+ break;
+ default :
+ val = doSimple();
+ break;
+ }
+
+ if (!prefix(")"))
+ error(MALFORMED);
+ return val;
+ }
+
+ private boolean doAnd() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ boolean val = true;
+ if (!tail.startsWith("("))
+ error(EMPTY);
+ do {
+ if (!doQuery())
+ val = false;
+ } while (tail.startsWith("("));
+ return val;
+ }
+
+ private boolean doOr() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ boolean val = false;
+ if (!tail.startsWith("("))
+ error(EMPTY);
+ do {
+ if (doQuery())
+ val = true;
+ } while (tail.startsWith("("));
+ return val;
+ }
+
+ private boolean doNot() throws IllegalArgumentException {
+ tail = tail.substring(1);
+ if (!tail.startsWith("("))
+ error(SUBEXPR);
+ return !doQuery();
+ }
+
+ private boolean doSimple() throws IllegalArgumentException {
+ int op = 0;
+ Object attr = getAttr();
+
+ if (prefix("="))
+ op = EQ;
+ else if (prefix("<="))
+ op = LE;
+ else if (prefix(">="))
+ op = GE;
+ else if (prefix("~="))
+ op = APPROX;
+ else if (prefix("*>"))
+ op = SUPERSET;
+ else if (prefix("<*"))
+ op = SUBSET;
+ else if (prefix("<"))
+ op = LESS;
+ else if (prefix(">"))
+ op = GREATER;
+ else
+ error(OPERATOR);
+
+ return compare(attr, op, getValue());
+ }
+
+ private boolean prefix(String pre) {
+ if (!tail.startsWith(pre))
+ return false;
+ tail = tail.substring(pre.length());
+ return true;
+ }
+
+ private Object getAttr() {
+ int len = tail.length();
+ int ix = 0;
+ label: for (; ix < len; ix++) {
+ switch (tail.charAt(ix)) {
+ case '(' :
+ case ')' :
+ case '<' :
+ case '>' :
+ case '=' :
+ case '~' :
+ case '*' :
+ case '}' :
+ case '{' :
+ case '\\' :
+ break label;
+ }
+ }
+ String attr = tail.substring(0, ix).toLowerCase();
+ tail = tail.substring(ix);
+ return getProp(attr);
+ }
+
+ abstract Object getProp(String key);
+
+ private String getValue() {
+ StringBuffer sb = new StringBuffer();
+ int len = tail.length();
+ int ix = 0;
+ label: for (; ix < len; ix++) {
+ char c = tail.charAt(ix);
+ switch (c) {
+ case '(' :
+ case ')' :
+ break label;
+ case '*' :
+ sb.append(WILDCARD);
+ break;
+ case '\\' :
+ if (ix == len - 1)
+ break label;
+ sb.append(tail.charAt(++ix));
+ break;
+ default :
+ sb.append(c);
+ break;
+ }
+ }
+ tail = tail.substring(ix);
+ return sb.toString();
+ }
+
+ private void error(String m) throws IllegalArgumentException {
+ throw new IllegalArgumentException(m + " " + tail);
+ }
+
+ private boolean compare(Object obj, int op, String s) {
+ if (obj == null) {
+ // No value is ok for a subset
+ if (op == SUBSET)
+ return true;
+
+ // No value is ok for a superset when the value is
+ // empty
+ if (op == SUPERSET) {
+ return s.trim().length() == 0;
+ }
+
+ return false;
+ }
+ try {
+ Class numClass = obj.getClass();
+ if (numClass == String.class) {
+ return compareString((String) obj, op, s);
+ }
+ else if (numClass == Character.class) {
+ return compareString(obj.toString(), op, s);
+ }
+ else if (numClass == Long.class) {
+ return compareSign(op, Long.valueOf(s)
+ .compareTo((Long) obj));
+ }
+ else if (numClass == Integer.class) {
+ return compareSign(op, Integer.valueOf(s).compareTo(
+ (Integer) obj));
+ }
+ else if (numClass == Short.class) {
+ return compareSign(op, Short.valueOf(s).compareTo(
+ (Short) obj));
+ }
+ else if (numClass == Byte.class) {
+ return compareSign(op, Byte.valueOf(s)
+ .compareTo((Byte) obj));
+ }
+ else if (numClass == Double.class) {
+ return compareSign(op, Double.valueOf(s).compareTo(
+ (Double) obj));
+ }
+ else if (numClass == Float.class) {
+ return compareSign(op, Float.valueOf(s).compareTo(
+ (Float) obj));
+ }
+ else if (numClass == Boolean.class) {
+ if (op != EQ)
+ return false;
+ int a = Boolean.valueOf(s).booleanValue() ? 1 : 0;
+ int b = ((Boolean) obj).booleanValue() ? 1 : 0;
+ return compareSign(op, a - b);
+ }
+ else if (numClass == BigInteger.class) {
+ return compareSign(op, new BigInteger(s)
+ .compareTo((BigInteger) obj));
+ }
+ else if (obj instanceof Collection) {
+ if (op == SUBSET || op == SUPERSET) {
+ StringSet set = new StringSet(s);
+ if (op == SUBSET)
+ return set.containsAll((Collection) obj);
+ else
+ return ((Collection) obj).containsAll(set);
+ }
+
+ for (Iterator i = ((Collection) obj).iterator(); i
+ .hasNext();) {
+ Object element = i.next();
+ if (compare(element, op, s))
+ return true;
+ }
+ }
+ else if (numClass.isArray()) {
+ int len = Array.getLength(obj);
+ for (int i = 0; i < len; i++)
+ if (compare(Array.get(obj, i), op, s))
+ return true;
+ }
+ else {
+ try {
+ if (op == SUPERSET || op == SUBSET) {
+ StringSet set = new StringSet(s);
+ if (op == SUPERSET)
+ return set.contains(obj);
+ else
+ return set.size() == 0
+ || (set.size() == 1 && set.iterator()
+ .next().equals(obj));
+ }
+ else {
+ Constructor constructor = numClass
+ .getConstructor(new Class[] {String.class});
+ Object instance = constructor
+ .newInstance(new Object[] {s});
+ switch (op) {
+ case EQ :
+ return obj.equals(instance);
+ case LESS :
+ return ((Comparable) obj)
+ .compareTo(instance) < 0;
+ case GREATER :
+ return ((Comparable) obj)
+ .compareTo(instance) > 0;
+ case LE :
+ return ((Comparable) obj)
+ .compareTo(instance) <= 0;
+ case GE :
+ return ((Comparable) obj)
+ .compareTo(instance) >= 0;
+ }
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ // Ignore
+ }
+ }
+ }
+ catch (Exception e) {
+ }
+ return false;
+ }
+ }
+
+ class DictQuery extends Query {
+ private Map dict;
+
+ DictQuery(Map dict) {
+ this.dict = dict;
+ }
+
+ Object getProp(String key) {
+ return dict.get(key);
+ }
+ }
+
+ public FilterImpl(String filter) throws IllegalArgumentException {
+ // NYI: Normalize the filter string?
+ this.filter = filter;
+ if (filter == null || filter.length() == 0)
+ throw new IllegalArgumentException("Null query");
+ }
+
+ public boolean match(Map dict) {
+ try {
+ return new DictQuery(dict).match();
+ }
+ catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ public String toString() {
+ return filter;
+ }
+
+ public boolean equals(Object obj) {
+ return obj != null && obj instanceof FilterImpl
+ && filter.equals(((FilterImpl) obj).filter);
+ }
+
+ public int hashCode() {
+ return filter.hashCode();
+ }
+
+ boolean compareString(String s1, int op, String s2) {
+ switch (op) {
+ case EQ :
+ return patSubstr(s1, s2);
+ case APPROX :
+ return patSubstr(fixupString(s1), fixupString(s2));
+ default :
+ return compareSign(op, s2.compareTo(s1));
+ }
+ }
+
+ boolean compareSign(int op, int cmp) {
+ switch (op) {
+ case LE :
+ return cmp >= 0;
+ case GE :
+ return cmp <= 0;
+ case EQ :
+ return cmp == 0;
+ default : /* APPROX */
+ return cmp == 0;
+ }
+ }
+
+ String fixupString(String s) {
+ StringBuffer sb = new StringBuffer();
+ int len = s.length();
+ boolean isStart = true;
+ boolean isWhite = false;
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (Character.isWhitespace(c)) {
+ isWhite = true;
+ }
+ else {
+ if (!isStart && isWhite)
+ sb.append(' ');
+ if (Character.isUpperCase(c))
+ c = Character.toLowerCase(c);
+ sb.append(c);
+ isStart = false;
+ isWhite = false;
+ }
+ }
+ return sb.toString();
+ }
+
+ boolean patSubstr(String s, String pat) {
+ if (s == null)
+ return false;
+ if (pat.length() == 0)
+ return s.length() == 0;
+ if (pat.charAt(0) == WILDCARD) {
+ pat = pat.substring(1);
+ for (;;) {
+ if (patSubstr(s, pat))
+ return true;
+ if (s.length() == 0)
+ return false;
+ s = s.substring(1);
+ }
+ }
+ else {
+ if (s.length() == 0 || s.charAt(0) != pat.charAt(0))
+ return false;
+ return patSubstr(s.substring(1), pat.substring(1));
+ }
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Manifest.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Manifest.java
new file mode 100644
index 0000000..25b0e12
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Manifest.java
@@ -0,0 +1,386 @@
+package org.osgi.impl.bundle.obr.resource;
+
+import java.io.*;
+import java.util.*;
+
+import org.osgi.impl.bundle.obr.resource.VersionImpl;
+
+
+public class Manifest extends Hashtable {
+ List imports;
+ List exports;
+ ManifestEntry name;
+ String activator;
+ String classpath[] = new String[] {"."};
+ int section;
+ String location;
+ Native _native[];
+ Vector duplicates = new Vector();
+ final static String wordparts = "~!@#$%^&*_:/?><.-+";
+ ManifestEntry bsn;
+ VersionImpl version;
+ ManifestEntry host;
+ List require;
+
+ public Manifest(InputStream in) throws IOException {
+ parse(new InputStreamReader(in, "UTF8"));
+ }
+
+ public Manifest(Reader in) throws IOException {
+ parse(in);
+ }
+
+ public Object put(Object header, Object value) {
+ if (containsKey(header)) {
+ if (!((String) header).equalsIgnoreCase("comment"))
+ duplicates.add(header + ":" + value);
+ }
+ return super.put(header, value);
+ }
+
+ void parse(Reader in) throws IOException {
+ BufferedReader rdr = new BufferedReader(in);
+ String current = " ";
+ String buffer = rdr.readLine();
+ int section = 0;
+ if (buffer != null && !buffer.startsWith("Manifest-Version")) {
+ System.err
+ .println("The first line of a manifest file must be the Manifest-Version attribute");
+ throw new IOException(
+ "The first line of a manifest file must be the Manifest-Version attribute");
+ }
+ while (buffer != null && current != null && section == 0) {
+ if (current.startsWith(" ")) {
+ buffer += current.substring(1);
+ }
+ else {
+ section += entry(buffer);
+ buffer = current;
+ }
+ current = rdr.readLine();
+ }
+ entry(buffer);
+ }
+
+ int entry(String line) throws IOException {
+ if (line.length() < 2)
+ return 1;
+ int colon = line.indexOf(':');
+ if (colon < 1) {
+ error("Invalid header '" + line + "'");
+ }
+ else {
+ String header = line.substring(0, colon).toLowerCase();
+ String alphanum = "abcdefghijklmnopqrstuvwxyz0123456789";
+ String set = alphanum;
+ if (alphanum.indexOf(header.charAt(0)) < 0)
+ error("Header does not start with alphanum: " + header);
+ for (int i = 0; i < header.length(); i++) {
+ if (set.indexOf(header.charAt(i)) < 0)
+ error("Header contains non alphanum, - _: " + header);
+ set = "_-" + alphanum;
+ }
+ String value = "";
+ if (colon + 2 < line.length())
+ value = line.substring(colon + 2);
+ else
+ error("No value for manifest header " + header);
+ if (section == 0) {
+ if (header.equals("bundle-symbolicname")) {
+ bsn = (ManifestEntry) getEntries(value).get(0);
+ }
+ if (header.equals("bundle-version")) {
+ try {
+ version = new VersionImpl(value.trim());
+ }
+ catch (Exception e) {
+ version = new VersionImpl("0");
+ System.err.println("Invalid version attr for: " + bsn
+ + " value is " + value);
+ }
+ }
+ if (header.equals("fragment-host"))
+ host = (ManifestEntry) getEntries(value).get(0);
+ if (header.equals("require-bundle"))
+ require = getEntries(value);
+ if (header.equals("import-package"))
+ imports = getEntries(value);
+ else if (header.equals("export-package"))
+ exports = getEntries(value);
+ else if (header.equals("bundle-activator"))
+ activator = value.trim();
+ else if (header.equals("bundle-updatelocation"))
+ location = value.trim();
+ else if (header.equals("bundle-classpath"))
+ classpath = getClasspath(value);
+ else if (header.equals("bundle-nativecode"))
+ _native = getNative(value);
+ put(header, value);
+ }
+ }
+ return 0;
+ }
+
+ void error(String msg) throws IOException {
+ System.err.println("Reading manifest: " + msg);
+ }
+
+ void warning(String msg) throws IOException {
+ System.err.println("Reading manifest: " + msg);
+ }
+
+ StreamTokenizer getStreamTokenizer(String line) {
+ StreamTokenizer st = new StreamTokenizer(new StringReader(line));
+ st.resetSyntax();
+ st.wordChars('a', 'z');
+ st.wordChars('A', 'Z');
+ st.wordChars('0', '9');
+ st.whitespaceChars(0, ' ');
+ st.quoteChar('"');
+ for (int i = 0; i < wordparts.length(); i++)
+ st.wordChars(wordparts.charAt(i), wordparts.charAt(i));
+ return st;
+ }
+
+ String word(StreamTokenizer st) throws IOException {
+ switch (st.nextToken()) {
+ case '"' :
+ case StreamTokenizer.TT_WORD :
+ String result = st.sval;
+ st.nextToken();
+ return result;
+ }
+ return null;
+ }
+
+ Parameter getParameter(StreamTokenizer st) throws IOException {
+
+ Parameter parameter = new Parameter();
+ parameter.key = word(st);
+ if (st.ttype == ':') {
+ st.nextToken();
+ parameter.type = Parameter.DIRECTIVE;
+ }
+ else {
+ parameter.type = Parameter.ATTRIBUTE;
+ }
+
+ if (st.ttype == '=') {
+ parameter.value = word(st);
+ while (st.ttype == StreamTokenizer.TT_WORD || st.ttype == '"') {
+ parameter.value += " " + st.sval;
+ st.nextToken();
+ }
+ }
+
+ return parameter;
+ }
+
+ public List getEntries(String line) throws IOException {
+ List v = new Vector();
+ Set aliases = new HashSet();
+
+ StreamTokenizer st = getStreamTokenizer(line);
+ do {
+ Parameter parameter = getParameter(st);
+ ManifestEntry p = new ManifestEntry(parameter.key);
+ while (st.ttype == ';') {
+ parameter = getParameter(st);
+ if (parameter.value == null) {
+ aliases.add(parameter.key);
+ }
+ else {
+ if (parameter.type == Parameter.ATTRIBUTE)
+ p.addParameter(parameter);
+ else
+ p.addParameter(parameter);
+ }
+ }
+ v.add(p);
+ for (Iterator a = aliases.iterator(); a.hasNext();) {
+ v.add(p.getAlias((String) a.next()));
+ }
+ } while (st.ttype == ',');
+ return v;
+ }
+
+ Native[] getNative(String line) throws IOException {
+ Vector v = new Vector();
+ StreamTokenizer st = getStreamTokenizer(line);
+ do {
+ Native spec = new Native();
+ Vector names = new Vector();
+ do {
+ Parameter parameter = getParameter(st);
+ if (parameter.value == null)
+ names.add(parameter.key);
+ else if (parameter.is("processor", Parameter.ATTRIBUTE))
+ spec.processor = parameter.value;
+ else if (parameter.is("osname", Parameter.ATTRIBUTE))
+ spec.osname = parameter.value;
+ else if (parameter.is("osversion", Parameter.ATTRIBUTE))
+ spec.osversion = parameter.value;
+ else if (parameter.is("language", Parameter.ATTRIBUTE))
+ spec.language = parameter.value;
+ else if (parameter.is("selection-filter", Parameter.DIRECTIVE))
+ spec.filter = parameter.value;
+ else
+ warning("Unknown parameter for native code : " + parameter);
+ } while (st.ttype == ';');
+ spec.paths = new String[names.size()];
+ names.copyInto(spec.paths);
+ v.add(spec);
+ } while (st.ttype == ',');
+ Native[] result = new Native[v.size()];
+ v.copyInto(result);
+ return result;
+ }
+
+ String[] getClasspath(String line) throws IOException {
+ StringTokenizer st = new StringTokenizer(line, " \t,");
+ String result[] = new String[st.countTokens()];
+ for (int i = 0; i < result.length; i++)
+ result[i] = st.nextToken();
+ return result;
+ }
+
+ public List getImports() {
+ return imports;
+ }
+
+ public List getExports() {
+ return exports;
+ }
+
+ public String getActivator() {
+ return activator;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public String[] getClasspath() {
+ return classpath;
+ }
+
+ public Native[] getNative() {
+ return _native;
+ }
+
+ public Object get(Object key) {
+ if (key instanceof String)
+ return super.get(((String) key).toLowerCase());
+ else
+ return null;
+ }
+
+ public String getValue(String key) {
+ return (String) super.get(key.toLowerCase());
+ }
+
+ public String getValue(String key, String deflt) {
+ String s = getValue(key);
+ if (s == null)
+ return deflt;
+ else
+ return s;
+ }
+
+ public String[] getRequiredExecutionEnvironments() {
+ String ees = getValue("Bundle-RequiredExecutionEnvironment");
+ if (ees != null)
+ return ees.trim().split("\\s*,\\s*");
+ else
+ return null;
+ }
+
+ public VersionImpl getVersion() {
+ if (version == null)
+ return new VersionImpl("0");
+ return version;
+ }
+
+ public String getSymbolicName() {
+ ManifestEntry bsn = getBsn();
+
+ if (bsn == null) {
+ //nox if the symbolic name is not define in manifest fils, we take the
+ //artefactId from the pom.xml file
+ /*String name = getValue("Bundle-Name");
+ if (name == null)
+ name = "Untitled-" + hashCode();*/
+ return null;
+ }
+ else
+ return bsn.getName();
+ }
+
+ public String getManifestVersion() {
+ return getValue("Bundle-ManifestVersion", "1");
+ }
+
+ public String getCopyright() {
+ return getValue("Bundle-Copyright");
+ }
+
+ public String getDocumentation() {
+ return getValue("Bundle-DocURL");
+ }
+
+ public String[] getCategories() {
+ String cats = getValue("Bundle-Category");
+ if (cats == null)
+ return new String[0];
+ else
+ return cats.split("\\s*,\\s*");
+ }
+
+ public Native[] get_native() {
+ return _native;
+ }
+
+ public void set_native(Native[] _native) {
+ this._native = _native;
+ }
+
+ public ManifestEntry getBsn() {
+ return bsn;
+ }
+
+ public void setBsn(ManifestEntry bsn) {
+ this.bsn = bsn;
+ }
+
+ public Vector getDuplicates() {
+ return duplicates;
+ }
+
+ public void setDuplicates(Vector duplicates) {
+ this.duplicates = duplicates;
+ }
+
+ public ManifestEntry getHost() {
+ return host;
+ }
+
+ public void setHost(ManifestEntry host) {
+ this.host = host;
+ }
+
+ public List getRequire() {
+ return require;
+ }
+
+}
+
+class Native {
+ String filter;
+ int index = -1;
+ String paths[];
+ String osname;
+ String osversion;
+ String language;
+ String processor;
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/ManifestEntry.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/ManifestEntry.java
new file mode 100644
index 0000000..f26f22f
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/ManifestEntry.java
@@ -0,0 +1,96 @@
+package org.osgi.impl.bundle.obr.resource;
+
+import java.util.*;
+
+import org.osgi.impl.bundle.obr.resource.VersionImpl;
+
+
+public class ManifestEntry implements Comparable {
+ String name;
+ VersionImpl version;
+ Map attributes;
+ public Map directives;
+ public Set uses;
+
+ public ManifestEntry(String name) {
+ this.name = name;
+ }
+
+ public ManifestEntry(String name, VersionImpl version) {
+ this.name = name;
+ this.version = version;
+ }
+
+ public String toString() {
+ if (version == null)
+ return name;
+ return name + " ;version=" + version;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public VersionImpl getVersion() {
+ if (version != null)
+ return version;
+ return new VersionImpl("0");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object o) {
+ ManifestEntry p = (ManifestEntry) o;
+ return name.compareTo(p.name);
+ }
+
+ /**
+ * @return
+ */
+ public Object getPath() {
+ return getName().replace('.', '/');
+ }
+
+ public Map getDirectives() {
+ return directives;
+ }
+
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * @param parameter
+ */
+ public void addParameter(Parameter parameter) {
+ switch (parameter.type) {
+ case Parameter.ATTRIBUTE :
+ if (attributes == null)
+ attributes = new HashMap();
+ attributes.put(parameter.key, parameter.value);
+ if (parameter.key.equalsIgnoreCase("version")
+ || parameter.key
+ .equalsIgnoreCase("specification-version"))
+ this.version = new VersionImpl(parameter.value);
+ break;
+
+ case Parameter.DIRECTIVE :
+ if (directives == null)
+ directives = new HashMap();
+ directives.put(parameter.key, parameter.value);
+ break;
+ }
+ }
+
+ public ManifestEntry getAlias(String key) {
+ ManifestEntry me = new ManifestEntry(key);
+ me.attributes = attributes;
+ me.directives = directives;
+ me.version = version;
+ return me;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Parameter.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Parameter.java
new file mode 100644
index 0000000..1edfb7e
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Parameter.java
@@ -0,0 +1,59 @@
+/*
+ * $Header: /cvshome/bundles/bundles.obr/src/bundles/obr/resource/Parameter.java,v 1.1 2006/07/27 10:31:02 pkriens Exp $
+ *
+ * Copyright (c) The OSGi Alliance (2005). All Rights Reserved.
+ *
+ * Implementation of certain elements of the OSGi Specification may be subject
+ * to third party intellectual property rights, including without limitation,
+ * patent rights (such a third party may or may not be a member of the OSGi
+ * Alliance). The OSGi Alliance is not responsible and shall not be held
+ * responsible in any manner for identifying or failing to identify any or all
+ * such third party intellectual property rights.
+ *
+ * This document and the information contained herein are provided on an "AS IS"
+ * basis and THE OSGI ALLIANCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ * HEREIN WILL NOT INFRINGE ANY RIGHTS AND ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL THE
+ * OSGI ALLIANCE BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF BUSINESS, LOSS OF
+ * USE OF DATA, INTERRUPTION OF BUSINESS, OR FOR DIRECT, INDIRECT, SPECIAL OR
+ * EXEMPLARY, INCIDENTIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES OF ANY KIND IN
+ * CONNECTION WITH THIS DOCUMENT OR THE INFORMATION CONTAINED HEREIN, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE.
+ *
+ * All Company, brand and product names may be trademarks that are the sole
+ * property of their respective owners. All rights reserved.
+ */
+
+package org.osgi.impl.bundle.obr.resource;
+
+class Parameter {
+ final static int ATTRIBUTE = 1;
+ final static int DIRECTIVE = 2;
+ final static int SINGLE = 0;
+
+ int type;
+ String key;
+ String value;
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(key);
+ switch (type) {
+ case ATTRIBUTE :
+ sb.append("=");
+ break;
+ case DIRECTIVE :
+ sb.append(":=");
+ break;
+ case SINGLE :
+ return sb.toString();
+ }
+ sb.append(value);
+ return sb.toString();
+ }
+
+ boolean is(String s, int type) {
+ return this.type == type && key.equalsIgnoreCase(s);
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java
new file mode 100644
index 0000000..0c27962
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/RepositoryImpl.java
@@ -0,0 +1,386 @@
+/*
+ * $Header: /cvshome/bundles/bundles.obr/src/bundles/obr/resource/RepositoryImpl.java,v 1.11 2006/04/27 09:00:16 pkriens Exp $
+ *
+ * Copyright (c) The OSGi Alliance (2005). All Rights Reserved.
+ *
+ * Implementation of certain elements of the OSGi Specification may be subject
+ * to third party intellectual property rights, including without limitation,
+ * patent rights (such a third party may or may not be a member of the OSGi
+ * Alliance). The OSGi Alliance is not responsible and shall not be held
+ * responsible in any manner for identifying or failing to identify any or all
+ * such third party intellectual property rights.
+ *
+ * This document and the information contained herein are provided on an "AS IS"
+ * basis and THE OSGI ALLIANCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ * HEREIN WILL NOT INFRINGE ANY RIGHTS AND ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL THE
+ * OSGI ALLIANCE BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF BUSINESS, LOSS OF
+ * USE OF DATA, INTERRUPTION OF BUSINESS, OR FOR DIRECT, INDIRECT, SPECIAL OR
+ * EXEMPLARY, INCIDENTIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES OF ANY KIND IN
+ * CONNECTION WITH THIS DOCUMENT OR THE INFORMATION CONTAINED HEREIN, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE.
+ *
+ * All Company, brand and product names may be trademarks that are the sole
+ * property of their respective owners. All rights reserved.
+ */
+
+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.Repository;
+import org.osgi.service.obr.Resource;
+
+import org.xmlpull.v1.*;
+
+/**
+ * Implements the basic repository. A repository holds a set of resources.
+ *
+ *
+ * @version $Revision: 1.11 $
+ */
+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");
+ VersionImpl v = new VersionImpl("0");
+ if (version != null) {
+ sb.append("(version=");
+ sb.append(v= new VersionImpl(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 VersionImpl(
+ 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 VersionImpl(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;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/RequirementImpl.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/RequirementImpl.java
new file mode 100644
index 0000000..97032a7
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/RequirementImpl.java
@@ -0,0 +1,160 @@
+package org.osgi.impl.bundle.obr.resource;
+
+import org.osgi.service.obr.*;
+import org.xmlpull.v1.XmlPullParser;
+
+
+
+/**
+ * Implements the Requirement interface.
+ *
+ *
+ * @version $Revision: 1.8 $
+ */
+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;
+ }
+
+ 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;
+ }
+
+
+ public boolean equals(Object o) {
+ if ( ! (o instanceof Requirement) )
+ return false;
+
+ Requirement r2 = (Requirement)o;
+ return filter.equals(r2.getFilter()) && name.equals(r2.getName());
+ }
+
+ public int hashCode() {
+ return filter.hashCode() ^ name.hashCode();
+ }
+
+ public boolean isExtend() {
+ return extend;
+ }
+
+ public void setExtend(boolean extend) {
+ this.extend = extend;
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/ResourceImpl.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/ResourceImpl.java
new file mode 100644
index 0000000..beedc0d
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/ResourceImpl.java
@@ -0,0 +1,351 @@
+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;
+ VersionImpl version;
+ List categories = new ArrayList();
+ long size = -1;
+ String id;
+ static int ID = 1;
+ Map map = new HashMap();
+ RepositoryImpl repository;
+ String presentationName;
+ File file;
+
+ {
+ id = Integer.toString(ID++);
+ }
+
+ public ResourceImpl(RepositoryImpl repository, String name,
+ VersionImpl version) {
+ this.version = version;
+ 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 VersionImpl("0"));
+ else
+ setVersion(new VersionImpl(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;
+ }
+
+ 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 );
+ 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 VersionImpl("0");
+ return version;
+ }
+
+ void setVersion(VersionImpl version) {
+ if (version == null)
+ this.version = new VersionImpl("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;
+ }
+
+ 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;
+ }
+
+ public int hashCode() {
+ return symbolicName.hashCode() ^ version.hashCode();
+ }
+
+ 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 String getId() {
+ 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;
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/StringSet.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/StringSet.java
new file mode 100644
index 0000000..d69958d
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/StringSet.java
@@ -0,0 +1,39 @@
+/*
+ * $Header: /cvshome/bundles/bundles.obr/src/bundles/obr/resource/StringSet.java,v 1.1 2006/01/03 16:22:46 pkriens Exp $
+ *
+ * Copyright (c) The OSGi Alliance (2006). All Rights Reserved.
+ *
+ * Implementation of certain elements of the OSGi Specification may be subject
+ * to third party intellectual property rights, including without limitation,
+ * patent rights (such a third party may or may not be a member of the OSGi
+ * Alliance). The OSGi Alliance is not responsible and shall not be held
+ * responsible in any manner for identifying or failing to identify any or all
+ * such third party intellectual property rights.
+ *
+ * This document and the information contained herein are provided on an "AS IS"
+ * basis and THE OSGI ALLIANCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ * HEREIN WILL NOT INFRINGE ANY RIGHTS AND ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL THE
+ * OSGI ALLIANCE BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF BUSINESS, LOSS OF
+ * USE OF DATA, INTERRUPTION OF BUSINESS, OR FOR DIRECT, INDIRECT, SPECIAL OR
+ * EXEMPLARY, INCIDENTIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES OF ANY KIND IN
+ * CONNECTION WITH THIS DOCUMENT OR THE INFORMATION CONTAINED HEREIN, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE.
+ *
+ * All Company, brand and product names may be trademarks that are the sole
+ * property of their respective owners. All rights reserved.
+ */
+
+package org.osgi.impl.bundle.obr.resource;
+
+import java.util.*;
+
+public class StringSet extends HashSet {
+
+ public StringSet(String set) {
+ StringTokenizer st = new StringTokenizer(set, ",");
+ while (st.hasMoreTokens())
+ add(st.nextToken().trim());
+ }
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Tag.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Tag.java
new file mode 100644
index 0000000..e077969
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/Tag.java
@@ -0,0 +1,471 @@
+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.
+ */
+ 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("<");
+ pos += 4;
+ break;
+ case '>' :
+ pw.print(">");
+ pos += 4;
+ break;
+ case '&' :
+ pw.print("&");
+ pos += 5;
+ break;
+ default :
+ pw.print(c);
+ pos++;
+ break;
+ }
+
+ }
+ }
+
+ /**
+ * Escape a string, do entity conversion.
+ */
+ String escape(String s) {
+ if ( s == null )
+ System.out.println("??");
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '<' :
+ sb.append("<");
+ break;
+ case '>' :
+ sb.append(">");
+ break;
+ case '&' :
+ sb.append("&");
+ 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) );
+ }
+ }
+
+}
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/VersionImpl.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/VersionImpl.java
new file mode 100644
index 0000000..8071166
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/VersionImpl.java
@@ -0,0 +1,121 @@
+/*
+ * $Header: /cvshome/bundles/bundles.obr/src/bundles/obr/resource/VersionImpl.java,v 1.3 2006/02/15 16:36:57 pkriens Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.osgi.impl.bundle.obr.resource;
+
+import org.osgi.framework.Version;
+
+/**
+ * Version identifier for bundles and packages.
+ *
+ * <p>
+ * Version identifiers have four components.
+ * <ol>
+ * <li>Major version. A non-negative integer.</li>
+ * <li>Minor version. A non-negative integer.</li>
+ * <li>Micro version. A non-negative integer.</li>
+ * <li>Qualifier. A text string. See <code>Version(String)</code> for the
+ * format of the qualifier string.</li>
+ * </ol>
+ *
+ * <p>
+ * <code>Version</code> objects are immutable.
+ *
+ * @version $Revision: 1.3 $
+ * @since 1.3
+ */
+
+public class VersionImpl extends Version {
+ VersionRange range;
+
+ /**
+ * Creates a version identifier from the specified numerical components.
+ *
+ * <p>
+ * The qualifier is set to the empty string.
+ *
+ * @param major Major component of the version identifier.
+ * @param minor Minor component of the version identifier.
+ * @param micro Micro component of the version identifier.
+ * @throws IllegalArgumentException If the numerical components are
+ * negative.
+ */
+ public VersionImpl(int major, int minor, int micro) {
+ this(major, minor, micro, null);
+ }
+
+ /**
+ * Creates a version identifier from the specifed components.
+ *
+ * @param major Major component of the version identifier.
+ * @param minor Minor component of the version identifier.
+ * @param micro Micro component of the version identifier.
+ * @param qualifier Qualifier component of the version identifier. If
+ * <code>null</code> is specified, then the qualifier will be set
+ * to the empty string.
+ * @throws IllegalArgumentException If the numerical components are negative
+ * or the qualifier string is invalid.
+ */
+ public VersionImpl(int major, int minor, int micro, String qualifier) {
+ super(major, minor, micro, qualifier);
+ }
+
+ // TODO Ugly!
+ public VersionImpl(String string) {
+ super(
+ string.indexOf("[") >= 0 || string.indexOf("(") >= 0 ? new VersionRange(
+ string).getMinimum().toString()
+ : string);
+ if ( string.indexOf("[") >= 0 || string.indexOf("(") >= 0 )
+ range = new VersionRange(string);
+ }
+
+ VersionRange getRange() {
+ return range;
+ }
+ /**
+ * this other 0 1 -1
+ *
+ * @param o
+ * @return
+ * @see org.osgi.framework.Version#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object o) {
+ if ( o instanceof VersionImpl ) {
+ VersionImpl other = (VersionImpl) o;
+ int cs = 0;
+ if ( range != null )
+ cs++;
+ if ( other.range!=null)
+ cs+=2;
+ switch (cs ) {
+ case 0: // V1 V2
+ return super.compareTo(other);
+
+ case 1: // R1 V2
+ return range.isIncluded(other) ? 0 : 1;
+
+ case 2: // V1 R2
+ return other.range.isIncluded(this) ? 0 : 1;
+
+ // TODO experimental
+ case 3: // R1 R2
+ return range.isIncluded(other.range.getMinimum()) && range.isIncluded(other.range.getMaximum()) ? 0 : 1;
+ }
+ return -1;
+ } else {
+ return super.compareTo(o);
+ }
+ }
+
+ public boolean equals(Object other) {
+ return compareTo(other) == 0;
+ }
+}
\ No newline at end of file
diff --git a/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/VersionRange.java b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/VersionRange.java
new file mode 100644
index 0000000..820e5ce
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/osgi/impl/bundle/obr/resource/VersionRange.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.osgi.impl.bundle.obr.resource;
+
+import org.osgi.framework.Version;
+
+/**
+ * This class represents a version range.
+ * @since 3.1
+ */
+public class VersionRange {
+ private static final Version versionMax = new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
+ /**
+ * An empty version
+ */
+ public static final VersionRange emptyRange = new VersionRange(null);
+
+ private Version minVersion;
+ private boolean includeMin;
+ private Version maxVersion;
+ private boolean includeMax;
+
+ /**
+ * Constructs a VersionRange with the specified minVersion and maxVersion.
+ * @param minVersion the minimum version of the range
+ * @param maxVersion the maximum version of the range
+ */
+ public VersionRange(Version minVersion, boolean includeMin, Version maxVersion, boolean includeMax) {
+ this.minVersion = minVersion;
+ this.includeMin = includeMin;
+ this.maxVersion = maxVersion;
+ this.includeMax = includeMax;
+ }
+
+ /**
+ * Constructs a VersionRange from the given versionRange String.
+ * @param versionRange a version range String that specifies a range of
+ * versions.
+ */
+ public VersionRange(String versionRange) {
+ if (versionRange == null || versionRange.length() == 0) {
+ minVersion = Version.emptyVersion;
+ includeMin = true;
+ maxVersion = VersionRange.versionMax;
+ includeMax = true;
+ return;
+ }
+ versionRange = versionRange.trim();
+ if (versionRange.charAt(0) == '[' || versionRange.charAt(0) == '(') {
+ int comma = versionRange.indexOf(',');
+ if (comma < 0)
+ throw new IllegalArgumentException();
+ char last = versionRange.charAt(versionRange.length() - 1);
+ if (last != ']' && last != ')')
+ throw new IllegalArgumentException();
+
+ minVersion = Version.parseVersion(versionRange.substring(1, comma).trim());
+ includeMin = versionRange.charAt(0) == '[';
+ maxVersion = Version.parseVersion(versionRange.substring(comma + 1, versionRange.length() - 1).trim());
+ includeMax = last == ']';
+ } else {
+ minVersion = Version.parseVersion(versionRange.trim());
+ includeMin = true;
+ maxVersion = VersionRange.versionMax;
+ includeMax = true;
+ }
+ }
+
+ /**
+ * Returns the minimum Version of this VersionRange
+ * @return the minimum Version of this VersionRange
+ */
+ public Version getMinimum() {
+ return minVersion;
+ }
+
+ /**
+ * Indicates if the minimum version is included in the version range.
+ * @return true if the minimum version is included in the version range;
+ * otherwise false is returned
+ */
+ public boolean getIncludeMinimum() {
+ return includeMin;
+ }
+
+ /**
+ * Returns the maximum Version of this VersionRange
+ * @return the maximum Version of this VersionRange
+ */
+ public Version getMaximum() {
+ return maxVersion;
+ }
+
+ /**
+ * Indicates if the maximum version is included in the version range.
+ * @return true if the maximum version is included in the version range;
+ * otherwise false is returned
+ */
+ public boolean getIncludeMaximum() {
+ return includeMax;
+ }
+
+ /**
+ * Returns whether the given version is included in this VersionRange.
+ * This will depend on the minimum and maximum versions of this VersionRange
+ * and the given version.
+ *
+ * @param version a version to be tested for inclusion in this VersionRange.
+ * (may be <code>null</code>)
+ * @return <code>true</code> if the version is include,
+ * <code>false</code> otherwise
+ */
+ public boolean isIncluded(Version version) {
+ Version minRequired = getMinimum();
+ if (minRequired == null)
+ return true;
+ if (version == null)
+ return false;
+ Version maxRequired = getMaximum() == null ? VersionRange.versionMax : getMaximum();
+ int minCheck = includeMin ? 0 : 1;
+ int maxCheck = includeMax ? 0 : -1;
+ return version.compareTo(minRequired) >= minCheck && version.compareTo(maxRequired) <= maxCheck;
+
+ }
+
+ public boolean equals(Object object) {
+ if (!(object instanceof VersionRange))
+ return false;
+ VersionRange vr = (VersionRange) object;
+ if (minVersion != null && vr.getMinimum() != null) {
+ if (minVersion.equals(vr.getMinimum()) && includeMin == vr.includeMin)
+ if (maxVersion != null && vr.getMaximum() != null) {
+ if (maxVersion.equals(vr.getMaximum()) && includeMax == vr.includeMax)
+ return true;
+ }
+ else
+ return maxVersion == vr.getMaximum();
+ }
+ else {
+ return minVersion == vr.getMinimum();
+ }
+ return false;
+ }
+
+ public String toString() {
+ if (minVersion == null)
+ return Version.emptyVersion.toString();
+ if (VersionRange.versionMax.equals(maxVersion))
+ return minVersion.toString();
+ StringBuffer result = new StringBuffer();
+ result.append(includeMin ? '[' : '(');
+ result.append(minVersion);
+ result.append(',');
+ result.append(maxVersion);
+ result.append(includeMax ? ']' : ')');
+ return result.toString();
+ }
+}
diff --git a/maven-obr-plugin/src/main/resources/SchemaObr.xsd b/maven-obr-plugin/src/main/resources/SchemaObr.xsd
new file mode 100644
index 0000000..2a99c1b
--- /dev/null
+++ b/maven-obr-plugin/src/main/resources/SchemaObr.xsd
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+<!-- definition of simple elements -->
+
+<!-- definition of attribute -->
+<xs:attribute name="name" type="xs:string"/>
+<xs:attribute name="filter" type="xs:string"/>
+<xs:attribute name="extend" type="xs:boolean"/>
+<xs:attribute name="multiple" type="xs:boolean"/>
+<xs:attribute name="optional" type="xs:boolean"/>
+<xs:attribute name="id" type="xs:string"/>
+<xs:attribute name="n" type="xs:string"/>
+<xs:attribute name="v" type="xs:string"/>
+<xs:attribute name="t" type="xs:string"/>
+
+<xs:element name="require">
+ <xs:complexType mixed="true">
+ <xs:attribute ref="name" use="required"/>
+ <xs:attribute ref="filter" use="required"/>
+ <xs:attribute ref="extend" use="required"/>
+ <xs:attribute ref="multiple" use="required"/>
+ <xs:attribute ref="optional" use="required"/>
+ </xs:complexType>
+</xs:element>
+
+<xs:element name="category">
+ <xs:complexType>
+ <xs:attribute ref="id" use="required"/>
+ </xs:complexType>
+</xs:element>
+
+<xs:element name="p">
+ <xs:complexType>
+ <xs:attribute ref="n" use="required"/>
+ <xs:attribute ref="v" use="required"/>
+ <xs:attribute ref="t" />
+ </xs:complexType>
+</xs:element>
+
+
+<xs:element name="capability">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="p" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:element>
+
+<xs:element name="resource">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="capability" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="require" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="category" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:element>
+</xs:schema>
\ No newline at end of file
diff --git a/pom/pom.xml b/pom/pom.xml
index 41d5bd1..2f9c116 100644
--- a/pom/pom.xml
+++ b/pom/pom.xml
@@ -97,10 +97,9 @@
</activation>
<modules>
<module>../bundleplugin</module>
+ <module>../maven-obr-plugin</module>
<module>../scrplugin</module>
<module>../tools/maven2/maven-osgi-plugin</module>
- <module>../ipojo/metadata</module>
- <module>../ipojo/manipulator</module>
<module>../ipojo/plugin</module>
</modules>
</profile>
@@ -133,6 +132,7 @@
<module>../upnp/samples/tv</module>
<module>../upnp/samples/clock</module>
<module>../upnp/samples/binarylight</module>
+
<module>../org.osgi.foundation</module>
<module>../javax.servlet</module>
<module>../org.osgi.core</module>
@@ -157,6 +157,8 @@
<module>../ipojo/core</module>
<module>../ipojo/arch</module>
+ <module>../ipojo/metadata</module>
+ <module>../ipojo/manipulator</module>
<module>../mosgi</module>
<module>../jmood</module>
diff --git a/upnp/basedriver/pom.xml b/upnp/basedriver/pom.xml
index 96d226f..2358800 100644
--- a/upnp/basedriver/pom.xml
+++ b/upnp/basedriver/pom.xml
@@ -4,7 +4,7 @@
<groupId>org.apache.felix</groupId>
<artifactId>felix</artifactId>
<version>1.1.0-SNAPSHOT</version>
- <relativePath>../pom/pom.xml</relativePath>
+ <relativePath>../../pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>bundle</packaging>
diff --git a/upnp/extra/pom.xml b/upnp/extra/pom.xml
index 97af362..da6de3a 100644
--- a/upnp/extra/pom.xml
+++ b/upnp/extra/pom.xml
@@ -4,7 +4,7 @@
<groupId>org.apache.felix</groupId>
<artifactId>felix</artifactId>
<version>1.1.0-SNAPSHOT</version>
- <relativePath>../pom/pom.xml</relativePath>
+ <relativePath>../../pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>bundle</packaging>