You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2007/09/04 16:52:51 UTC

svn commit: r572697 [3/4] - in /felix/sandbox/clement/maven-obr-plugin: ./ src/ src/main/ src/main/java/ src/main/java/bundles/ src/main/java/bundles/obr/ src/main/java/bundles/obr/resource/ src/main/java/org/ src/main/java/org/apache/ src/main/java/or...

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ObrUpdate.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ObrUpdate.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ObrUpdate.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ObrUpdate.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,611 @@
+/*
+ * 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.maven.obr.plugin;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+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 Maxime
+ * 
+ */
+
+public class ObrUpdate
+{
+
+    /**
+     * 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; 
+
+   
+    /**
+     * generate the date format to insert it in repository descriptor file
+     */
+    static SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
+
+    /**
+     * 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_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;
+
+    }
+
+    /**
+     * pase 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.getPath());
+        if (!fout.exists())
+        {
+            // create the repository.xml
+            try
+            {
+                fout.createNewFile();
+                m_logger.info("create new repository.xml file");
+            }
+            catch (IOException e)
+            {
+                m_logger.error("cannot create " + m_repoFilename.getPath());
+                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", 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(m_repoFilename.getPath()/* +m_ext */, 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)
+        {
+            if (resource(node))
+                return true;
+            else
+                return false;
+        }
+        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(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
+     * @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;
+    }
+}

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PElement.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PElement.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PElement.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PElement.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,118 @@
+/*
+ * 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.maven.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 Maxime
+ * 
+ */
+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 m_n new value
+     */
+    public void setN(String m_n)
+    {
+        this.m_n = m_n;
+    }
+
+    /**
+     * get the t tag.
+     * @return attribute t
+     */
+    public String getT()
+    {
+        return m_t;
+    }
+
+    /**
+     * set the t tag.
+     * @param m_t new value
+     */
+    public void setT(String m_t)
+    {
+        this.m_t = m_t;
+    }
+
+    /**
+     * get the v tag.
+     * @return attribute v
+     */
+    public String getV()
+    {
+        return m_v;
+    }
+
+    /**
+     * set the v tag.
+     * @param m_v new value
+     */
+    public void setV(String m_v)
+    {
+        this.m_v = m_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;
+    }
+}

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PathFile.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PathFile.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PathFile.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/PathFile.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,639 @@
+/*
+ * 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.maven.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 Maxime
+ * 
+ */
+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("\\", "/");
+
+        URI uri = null;
+        try
+        {
+            uri = new URI(path);
+        }
+        catch (URISyntaxException e)
+        {
+            System.err.println("malformed uri: " + path);
+            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;
+    }
+
+}

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/RemoteFileManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/RemoteFileManager.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/RemoteFileManager.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/RemoteFileManager.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,268 @@
+/*
+ * 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.maven.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.
+ * 
+ */
+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;
+    }
+
+}

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/Require.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/Require.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/Require.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/Require.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,189 @@
+/*
+ * 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.maven.obr.plugin;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+/**
+ * this class store a Require tag.
+ * @author Maxime
+ *
+ */
+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 m_extend new value for the extend attribute
+     */
+    public void setExtend(String m_extend)
+    {
+        this.m_extend = m_extend;
+    }
+
+    /**
+     * get the filter attribute.
+     * @return m_filter value
+     */
+    public String getFilter()
+    {
+        return m_filter;
+    }
+
+    /**
+     * set the filter attribute.
+     * @param m_filter new value for filter
+     */
+    public void setFilter(String m_filter)
+    {
+        this.m_filter = m_filter;
+    }
+
+    /**
+     * get multiple attribute.
+     * @return m_multiple value
+     */
+    public String getMultiple()
+    {
+        return m_multiple;
+    }
+
+    /**
+     * set multiple attribute.
+     * @param m_multiple new value for m_multiple
+     */
+    public void setMultiple(String m_multiple)
+    {
+        this.m_multiple = m_multiple;
+    }
+
+    /**
+     * get name attribute.
+     * @return m_name value
+     */
+    public String getName()
+    {
+        return m_name;
+    }
+
+    /**
+     * set name attribute.
+     * @param m_name new value for m_name
+     */
+    public void setName(String m_name)
+    {
+        this.m_name = m_name;
+    }
+
+    /**
+     * get the optional attribute.
+     * @return m_optional value
+     */
+    public String getOptional()
+    {
+        return m_optional;
+    }
+
+    /**
+     * set the optional attribute.
+     * @param m_optionnal new value for m_optional
+     */
+    public void setOptional(String m_optionnal)
+    {
+        this.m_optional = m_optionnal;
+    }
+
+    /**
+     * get value of the tag.
+     * @return value of this tag requiere
+     */
+    public String getValue()
+    {
+        return m_value;
+    }
+
+    /**
+     * set the value of the tag.
+     * @param m_value new value for this tag
+     */
+    public void setValue(String m_value)
+    {
+        this.m_value = m_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;
+    }
+
+}

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ResourcesBundle.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ResourcesBundle.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ResourcesBundle.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/apache/felix/maven/obr/plugin/ResourcesBundle.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,586 @@
+/*
+ * 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.maven.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.
+ */
+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 m_description)
+    {
+        this.m_description = m_description;
+    }
+
+    public String getDocumentation()
+    {
+        return m_documentation;
+    }
+
+    public void setDocumentation(String m_documentation)
+    {
+        this.m_documentation = m_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 m_size)
+    {
+        this.m_size = m_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 m_url)
+    {
+        this.m_uri = m_url;
+    }
+
+    public String getVersion()
+    {
+        return m_version;
+    }
+
+    public void setVersion(String m_version)
+    {
+        this.m_version = m_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 m_id)
+    {
+        this.m_id = m_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);
+
+        documentation.setTextContent(this.getDocumentation());
+        resource.appendChild(documentation);
+
+        source.setTextContent(this.getSource());
+        resource.appendChild(source);
+
+        license.setTextContent(this.getLicense());
+        resource.appendChild(license);
+
+        ArrayList 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);
+
+        ArrayList capabilities = (ArrayList) ebi.getCapabilities();
+        for (int i = 0; i < capabilities.size(); i++)
+        {
+            this.addCapability((Capability) capabilities.get(i));
+        }
+
+        ArrayList 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
+        boolean result = this.getPresentationName() != null && this.getSymbolicName() != null && this.getVersion() != null && this.getUri() != null && this.getSize() != null;
+        return result;
+    }
+
+    /**
+     * 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;
+    }
+
+}

Added: felix/sandbox/clement/maven-obr-plugin/src/main/java/org/osgi/framework/Version.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/maven-obr-plugin/src/main/java/org/osgi/framework/Version.java?rev=572697&view=auto
==============================================================================
--- felix/sandbox/clement/maven-obr-plugin/src/main/java/org/osgi/framework/Version.java (added)
+++ felix/sandbox/clement/maven-obr-plugin/src/main/java/org/osgi/framework/Version.java Tue Sep  4 07:52:47 2007
@@ -0,0 +1,353 @@
+/*
+ * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/Version.java,v 1.16 2006/06/16 16:31:18 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.framework;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+/**
+ * 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.16 $
+ * @since 1.3
+ */
+
+public class Version implements Comparable {
+	private final int			major;
+	private final int			minor;
+	private final int			micro;
+	private final String		qualifier;
+	private static final String	SEPARATOR		= ".";					//$NON-NLS-1$
+
+	/**
+	 * The empty version "0.0.0". Equivalent to calling
+	 * <code>new Version(0,0,0)</code>.
+	 */
+	public static final Version	emptyVersion	= new Version(0, 0, 0);
+
+	/**
+	 * 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 Version(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 Version(int major, int minor, int micro, String qualifier) {
+		if (qualifier == null) {
+			qualifier = ""; //$NON-NLS-1$
+		}
+
+		this.major = major;
+		this.minor = minor;
+		this.micro = micro;
+		this.qualifier = qualifier;
+		validate();
+	}
+
+	/**
+	 * Created a version identifier from the specified string.
+	 * 
+	 * <p>
+	 * Here is the grammar for version strings.
+	 * 
+	 * <pre>
+	 * version ::= major('.'minor('.'micro('.'qualifier)?)?)?
+	 * major ::= digit+
+	 * minor ::= digit+
+	 * micro ::= digit+
+	 * qualifier ::= (alpha|digit|'_'|'-')+
+	 * digit ::= [0..9]
+	 * alpha ::= [a..zA..Z]
+	 * </pre>
+	 * 
+	 * There must be no whitespace in version.
+	 * 
+	 * @param version String representation of the version identifier.
+	 * @throws IllegalArgumentException If <code>version</code> is improperly
+	 *         formatted.
+	 */
+	public Version(String version) {
+		int major = 0;
+		int minor = 0;
+		int micro = 0;
+		String qualifier = ""; //$NON-NLS-1$
+
+		try {
+			StringTokenizer st = new StringTokenizer(version, SEPARATOR, true);
+			major = Integer.parseInt(st.nextToken());
+
+			if (st.hasMoreTokens()) {
+				st.nextToken(); // consume delimiter
+				minor = Integer.parseInt(st.nextToken());
+
+				if (st.hasMoreTokens()) {
+					st.nextToken(); // consume delimiter
+					micro = Integer.parseInt(st.nextToken());
+
+					if (st.hasMoreTokens()) {
+						st.nextToken(); // consume delimiter
+						qualifier = st.nextToken();
+
+						if (st.hasMoreTokens()) {
+							throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
+						}
+					}
+				}
+			}
+		}
+		catch (NoSuchElementException e) {
+			throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
+		}
+
+		this.major = major;
+		this.minor = minor;
+		this.micro = micro;
+		this.qualifier = qualifier;
+		validate();
+	}
+
+	/**
+	 * Called by the Version constructors to validate the version components.
+	 * 
+	 * @throws IllegalArgumentException If the numerical components are negative
+	 *         or the qualifier string is invalid.
+	 */
+	private void validate() {
+		if (major < 0) {
+			throw new IllegalArgumentException("negative major"); //$NON-NLS-1$
+		}
+		if (minor < 0) {
+			throw new IllegalArgumentException("negative minor"); //$NON-NLS-1$
+		}
+		if (micro < 0) {
+			throw new IllegalArgumentException("negative micro"); //$NON-NLS-1$
+		}
+		int length = qualifier.length();
+		for (int i = 0; i < length; i++) {
+			if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".indexOf(qualifier.charAt(i)) == -1) { //$NON-NLS-1$
+				throw new IllegalArgumentException("invalid qualifier"); //$NON-NLS-1$
+			}
+		}
+	}
+
+	/**
+	 * Parses a version identifier from the specified string.
+	 * 
+	 * <p>
+	 * See <code>Version(String)</code> for the format of the version string.
+	 * 
+	 * @param version String representation of the version identifier. Leading
+	 *        and trailing whitespace will be ignored.
+	 * @return A <code>Version</code> object representing the version
+	 *         identifier. If <code>version</code> is <code>null</code> or
+	 *         the empty string then <code>emptyVersion</code> will be
+	 *         returned.
+	 * @throws IllegalArgumentException If <code>version</code> is improperly
+	 *         formatted.
+	 */
+	public static Version parseVersion(String version) {
+		if (version == null) {
+			return emptyVersion;
+		}
+
+		version = version.trim();
+		if (version.length() == 0) {
+			return emptyVersion;
+		}
+
+		return new Version(version);
+	}
+
+	/**
+	 * Returns the major component of this version identifier.
+	 * 
+	 * @return The major component.
+	 */
+	public int getMajor() {
+		return major;
+	}
+
+	/**
+	 * Returns the minor component of this version identifier.
+	 * 
+	 * @return The minor component.
+	 */
+	public int getMinor() {
+		return minor;
+	}
+
+	/**
+	 * Returns the micro component of this version identifier.
+	 * 
+	 * @return The micro component.
+	 */
+	public int getMicro() {
+		return micro;
+	}
+
+	/**
+	 * Returns the qualifier component of this version identifier.
+	 * 
+	 * @return The qualifier component.
+	 */
+	public String getQualifier() {
+		return qualifier;
+	}
+
+	/**
+	 * Returns the string representation of this version identifier.
+	 * 
+	 * <p>
+	 * The format of the version string will be <code>major.minor.micro</code>
+	 * if qualifier is the empty string or
+	 * <code>major.minor.micro.qualifier</code> otherwise.
+	 * 
+	 * @return The string representation of this version identifier.
+	 */
+	public String toString() {
+		String base = major + SEPARATOR + minor + SEPARATOR + micro;
+		if (qualifier.length() == 0) { //$NON-NLS-1$
+			return base;
+		}
+		else {
+			return base + SEPARATOR + qualifier;
+		}
+	}
+
+	/**
+	 * Returns a hash code value for the object.
+	 * 
+	 * @return An integer which is a hash code value for this object.
+	 */
+	public int hashCode() {
+		return (major << 24) + (minor << 16) + (micro << 8)
+				+ qualifier.hashCode();
+	}
+
+	/**
+	 * Compares this <code>Version</code> object to another object.
+	 * 
+	 * <p>
+	 * A version is considered to be <b>equal to </b> another version if the
+	 * major, minor and micro components are equal and the qualifier component
+	 * is equal (using <code>String.equals</code>).
+	 * 
+	 * @param object The <code>Version</code> object to be compared.
+	 * @return <code>true</code> if <code>object</code> is a
+	 *         <code>Version</code> and is equal to this object;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean equals(Object object) {
+		if (object == this) { // quicktest
+			return true;
+		}
+
+		if (!(object instanceof Version)) {
+			return false;
+		}
+
+		Version other = (Version) object;
+		return (major == other.major) && (minor == other.minor)
+				&& (micro == other.micro) && qualifier.equals(other.qualifier);
+	}
+
+	/**
+	 * Compares this <code>Version</code> object to another object.
+	 * 
+	 * <p>
+	 * A version is considered to be <b>less than </b> another version if its
+	 * major component is less than the other version's major component, or the
+	 * major components are equal and its minor component is less than the other
+	 * version's minor component, or the major and minor components are equal
+	 * and its micro component is less than the other version's micro component,
+	 * or the major, minor and micro components are equal and it's qualifier
+	 * component is less than the other version's qualifier component (using
+	 * <code>String.compareTo</code>).
+	 * 
+	 * <p>
+	 * A version is considered to be <b>equal to</b> another version if the
+	 * major, minor and micro components are equal and the qualifier component
+	 * is equal (using <code>String.compareTo</code>).
+	 * 
+	 * @param object The <code>Version</code> object to be compared.
+	 * @return A negative integer, zero, or a positive integer if this object is
+	 *         less than, equal to, or greater than the specified
+	 *         <code>Version</code> object.
+	 * @throws ClassCastException If the specified object is not a
+	 *         <code>Version</code>.
+	 */
+	public int compareTo(Object object) {
+		if (object == this) { // quicktest
+			return 0;
+		}
+
+		Version other = (Version) object;
+
+		int result = major - other.major;
+		if (result != 0) {
+			return result;
+		}
+
+		result = minor - other.minor;
+		if (result != 0) {
+			return result;
+		}
+
+		result = micro - other.micro;
+		if (result != 0) {
+			return result;
+		}
+
+		return qualifier.compareTo(other.qualifier);
+	}
+}

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