felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickh...@apache.org
Subject svn commit: r391296 [2/3] - in /incubator/felix/trunk/org.apache.felix.bundlerepository: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/bundlerepository/ src/...
Date Tue, 04 Apr 2006 13:17:26 GMT
Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Directive.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Directive.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Directive.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Directive.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,39 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+public class R4Directive
+{
+    private String m_name = "";
+    private String m_value = "";
+    
+    public R4Directive(String name, String value)
+    {
+        m_name = name;
+        m_value = value;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public String getValue()
+    {
+        return m_value;
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Directive.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Export.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Export.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Export.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Export.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,280 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+import java.util.*;
+
+import org.osgi.framework.Constants;
+
+public class R4Export extends R4Package
+{
+    private String[] m_uses = null;
+    private String[][] m_includeFilter = null;
+    private String[][] m_excludeFilter = null;
+
+    public R4Export(R4Package pkg)
+    {
+        this(pkg.getName(), pkg.getDirectives(), pkg.getAttributes());
+    }
+
+    public R4Export(String name, R4Directive[] directives, R4Attribute[] attrs)
+    {
+        super(name, directives, attrs);
+
+        // Find all export directives: uses, mandatory, include, and exclude.
+        String mandatory = "", uses = "";
+        for (int i = 0; i < m_directives.length; i++)
+        {
+            if (m_directives[i].getName().equals(Constants.USES_DIRECTIVE))
+            {
+                uses = m_directives[i].getValue();
+            }
+            else if (m_directives[i].getName().equals(Constants.MANDATORY_DIRECTIVE))
+            {
+                mandatory = m_directives[i].getValue();
+            }
+            else if (m_directives[i].getName().equals(Constants.INCLUDE_DIRECTIVE))
+            {
+                String[] ss = Util.parseDelimitedString(m_directives[i].getValue(), ",");
+                m_includeFilter = new String[ss.length][];
+                for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
+                {
+                    m_includeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+                }
+            }
+            else if (m_directives[i].getName().equals(Constants.EXCLUDE_DIRECTIVE))
+            {
+                String[] ss = Util.parseDelimitedString(m_directives[i].getValue(), ",");
+                m_excludeFilter = new String[ss.length][];
+                for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
+                {
+                    m_excludeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+                }
+            }
+        }
+
+        // Parse these uses directive.
+        StringTokenizer tok = new StringTokenizer(uses, ",");
+        m_uses = new String[tok.countTokens()];
+        for (int i = 0; i < m_uses.length; i++)
+        {
+            m_uses[i] = tok.nextToken().trim();
+        }
+
+        // Parse mandatory directive and mark specified
+        // attributes as mandatory.
+        tok = new StringTokenizer(mandatory, ",");
+        while (tok.hasMoreTokens())
+        {
+            // Get attribute name.
+            String attrName = tok.nextToken().trim();
+            // Find attribute and mark it as mandatory.
+            boolean found = false;
+            for (int i = 0; (!found) && (i < m_attrs.length); i++)
+            {
+                if (m_attrs[i].getName().equals(attrName))
+                {
+                    m_attrs[i] = new R4Attribute(
+                        m_attrs[i].getName(),
+                        m_attrs[i].getValue(), true);
+                    found = true;
+                }
+            }
+            // If a specified mandatory attribute was not found,
+            // then error.
+            if (!found)
+            {
+                throw new IllegalArgumentException(
+                    "Mandatory attribute '" + attrName + "' does not exist.");
+            }
+        }
+    }
+
+    public String[] getUses()
+    {
+        return m_uses;
+    }
+
+    public boolean isIncluded(String name)
+    {
+        if ((m_includeFilter == null) && (m_excludeFilter == null))
+        {
+            return true;
+        }
+
+        // Get the class name portion of the target class.
+        String className = Util.getClassName(name);
+
+        // If there are no include filters then all classes are included
+        // by default, otherwise try to find one match.
+        boolean included = (m_includeFilter == null);
+        for (int i = 0;
+            (!included) && (m_includeFilter != null) && (i < m_includeFilter.length);
+            i++)
+        {
+            included = checkSubstring(m_includeFilter[i], className);
+        }
+
+        // If there are no exclude filters then no classes are excluded
+        // by default, otherwise try to find one match.
+        boolean excluded = false;
+        for (int i = 0;
+            (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.length);
+            i++)
+        {
+            excluded = checkSubstring(m_excludeFilter[i], className);
+        }
+        return included && !excluded;
+    }
+
+    //
+    // The following substring-related code was lifted and modified
+    // from the LDAP parser code.
+    //
+
+    private static String[] parseSubstring(String target)
+    {
+        List pieces = new ArrayList();
+        StringBuffer ss = new StringBuffer();
+        // int kind = SIMPLE; // assume until proven otherwise
+        boolean wasStar = false; // indicates last piece was a star
+        boolean leftstar = false; // track if the initial piece is a star
+        boolean rightstar = false; // track if the final piece is a star
+
+        int idx = 0;
+
+        // We assume (sub)strings can contain leading and trailing blanks
+loop:   for (;;)
+        {
+            if (idx >= target.length())
+            {
+                if (wasStar)
+                {
+                    // insert last piece as "" to handle trailing star
+                    rightstar = true;
+                }
+                else
+                {
+                    pieces.add(ss.toString());
+                    // accumulate the last piece
+                    // note that in the case of
+                    // (cn=); this might be
+                    // the string "" (!=null)
+                }
+                ss.setLength(0);
+                break loop;
+            }
+
+            char c = target.charAt(idx++);
+            if (c == '*')
+            {
+                if (wasStar)
+                {
+                    // encountered two successive stars;
+                    // I assume this is illegal
+                    throw new IllegalArgumentException("Invalid filter string: " + target);
+                }
+                if (ss.length() > 0)
+                {
+                    pieces.add(ss.toString()); // accumulate the pieces
+                    // between '*' occurrences
+                }
+                ss.setLength(0);
+                // if this is a leading star, then track it
+                if (pieces.size() == 0)
+                {
+                    leftstar = true;
+                }
+                ss.setLength(0);
+                wasStar = true;
+            }
+            else
+            {
+                wasStar = false;
+                ss.append(c);
+            }
+        }
+        if (leftstar || rightstar || pieces.size() > 1)
+        {
+            // insert leading and/or trailing "" to anchor ends
+            if (rightstar)
+            {
+                pieces.add("");
+            }
+            if (leftstar)
+            {
+                pieces.add(0, "");
+            }
+        }
+        return (String[]) pieces.toArray(new String[pieces.size()]);
+    }
+
+    private static boolean checkSubstring(String[] pieces, String s)
+    {
+        // Walk the pieces to match the string
+        // There are implicit stars between each piece,
+        // and the first and last pieces might be "" to anchor the match.
+        // assert (pieces.length > 1)
+        // minimal case is <string>*<string>
+
+        boolean result = false;
+        int len = pieces.length;
+
+loop:   for (int i = 0; i < len; i++)
+        {
+            String piece = (String) pieces[i];
+            int index = 0;
+            if (i == len - 1)
+            {
+                // this is the last piece
+                if (s.endsWith(piece))
+                {
+                    result = true;
+                }
+                else
+                {
+                    result = false;
+                }
+                break loop;
+            }
+            // initial non-star; assert index == 0
+            else if (i == 0)
+            {
+                if (!s.startsWith(piece))
+                {
+                    result = false;
+                    break loop;
+                }
+            }
+            // assert i > 0 && i < len-1
+            else
+            {
+                // Sure wish stringbuffer supported e.g. indexOf
+                index = s.indexOf(piece, index);
+                if (index < 0)
+                {
+                    result = false;
+                    break loop;
+                }
+            }
+            // start beyond the matching piece
+            index += piece.length();
+        }
+
+        return result;
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Export.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Import.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Import.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Import.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Import.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,183 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+public class R4Import extends R4Package
+{
+    private VersionRange m_versionRange = null;
+    private boolean m_isOptional = false;
+
+    public R4Import(R4Package pkg)
+    {
+        this(pkg.getName(), pkg.getDirectives(), pkg.getAttributes());
+    }
+
+    public R4Import(String name, R4Directive[] directives, R4Attribute[] attrs)
+    {
+        super(name, directives, attrs);
+
+        // Find all import directives: resolution.
+        for (int i = 0; i < m_directives.length; i++)
+        {
+            if (m_directives[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
+            {
+                m_isOptional = m_directives[i].getValue().equals(Constants.RESOLUTION_OPTIONAL);
+            }
+        }
+
+        // Find and parse version attribute, if present.
+        String rangeStr = "0.0.0";
+        for (int i = 0; i < m_attrs.length; i++)
+        {
+            if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE) ||
+                m_attrs[i].getName().equals(Constants.PACKAGE_SPECIFICATION_VERSION))
+            {
+                // Normalize version attribute name.
+                m_attrs[i] = new R4Attribute(
+                    Constants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
+                    m_attrs[i].isMandatory());
+                rangeStr = m_attrs[i].getValue();
+                break;
+            }
+        }
+        
+        m_versionRange = VersionRange.parse(rangeStr);
+        m_version = m_versionRange.getLow();
+    }
+
+    public Version getVersionHigh()
+    {
+        return m_versionRange.getHigh();
+    }
+
+    public boolean isLowInclusive()
+    {
+        return m_versionRange.isLowInclusive();
+    }
+
+    public boolean isHighInclusive()
+    {
+        return m_versionRange.isHighInclusive();
+    }
+
+    public boolean isOptional()
+    {
+        return m_isOptional;
+    }
+
+    public boolean isSatisfied(R4Export export)
+    {
+        // For packages to be compatible, they must have the
+        // same name.
+        if (!getName().equals(export.getName()))
+        {
+            return false;
+        }
+        
+        return m_versionRange.isInRange(export.getVersion())
+            && doAttributesMatch(export);
+    }
+
+    private boolean doAttributesMatch(R4Export export)
+    {
+        // Cycle through all attributes of this import package
+        // and make sure its values match the attribute values
+        // of the specified export package.
+        for (int impAttrIdx = 0; impAttrIdx < getAttributes().length; impAttrIdx++)
+        {
+            // Get current attribute from this import package.
+            R4Attribute impAttr = getAttributes()[impAttrIdx];
+
+            // Ignore version attribute, since it is a special case that
+            // has already been compared using isVersionInRange() before
+            // the call to this method was made.
+            if (impAttr.getName().equals(Constants.VERSION_ATTRIBUTE))
+            {
+                continue;
+            }
+
+            // Check if the export package has the same attribute.
+            boolean found = false;
+            for (int expAttrIdx = 0;
+                (!found) && (expAttrIdx < export.getAttributes().length);
+                expAttrIdx++)
+            {
+                // Get current attribute for the export package.
+                R4Attribute expAttr = export.getAttributes()[expAttrIdx];
+                // Check if the attribute names are equal.
+                if (impAttr.getName().equals(expAttr.getName()))
+                {
+                    // If the values are not equal, then return false immediately.
+                    // We should not compare version values here, since they are
+                    // a special case and have already been compared by a call to
+                    // isVersionInRange() before getting here; however, it is
+                    // possible for version to be mandatory, so make sure it is
+                    // present below.
+                    if (!impAttr.getValue().equals(expAttr.getValue()))
+                    {
+                        return false;
+                    }
+                    found = true;
+                }
+            }
+            // If the attribute was not found, then return false.
+            if (!found)
+            {
+                return false;
+            }
+        }
+
+        // Now, cycle through all attributes of the export package and verify that
+        // all mandatory attributes are present in this import package.
+        for (int expAttrIdx = 0; expAttrIdx < export.getAttributes().length; expAttrIdx++)
+        {
+            // Get current attribute for this package.
+            R4Attribute expAttr = export.getAttributes()[expAttrIdx];
+            
+            // If the export attribute is mandatory, then make sure
+            // this import package has the attribute.
+            if (expAttr.isMandatory())
+            {
+                boolean found = false;
+                for (int impAttrIdx = 0;
+                    (!found) && (impAttrIdx < getAttributes().length);
+                    impAttrIdx++)
+                {
+                    // Get current attribute from specified package.
+                    R4Attribute impAttr = getAttributes()[impAttrIdx];
+        
+                    // Check if the attribute names are equal
+                    // and set found flag.
+                    if (expAttr.getName().equals(impAttr.getName()))
+                    {
+                        found = true;
+                    }
+                }
+                // If not found, then return false.
+                if (!found)
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Import.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Package.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Package.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Package.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Package.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,214 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+public class R4Package
+{
+    private String m_name = "";
+    protected R4Directive[] m_directives = null;
+    protected R4Attribute[] m_attrs = null;
+    protected Version m_version = null;
+
+    public R4Package(String name, R4Directive[] directives, R4Attribute[] attrs)
+    {
+        m_name = name;
+        m_directives = (directives == null) ? new R4Directive[0] : directives;
+        m_attrs = (attrs == null) ? new R4Attribute[0] : attrs;
+
+        // Find and parse version attribute, if present.
+        String rangeStr = "0.0.0";
+        for (int i = 0; i < m_attrs.length; i++)
+        {
+            if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE) ||
+                m_attrs[i].getName().equals(Constants.PACKAGE_SPECIFICATION_VERSION))
+            {
+                // Normalize version attribute name.
+                m_attrs[i] = new R4Attribute(
+                    Constants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
+                    m_attrs[i].isMandatory());
+                rangeStr = m_attrs[i].getValue();
+                break;
+            }
+        }
+        
+        VersionRange range = VersionRange.parse(rangeStr);
+        // For now, ignore if we have a version range.
+        m_version = range.getLow();
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public R4Directive[] getDirectives()
+    {
+        return m_directives;
+    }
+
+    public R4Attribute[] getAttributes()
+    {
+        return m_attrs;
+    }
+
+    public Version getVersion()
+    {
+        return m_version;
+    }
+
+    public String toString()
+    {
+        String msg = getName();
+        for (int i = 0; (m_directives != null) && (i < m_directives.length); i++)
+        {
+            msg = msg + " [" + m_directives[i].getName() + ":="+ m_directives[i].getValue() + "]";
+        }
+        for (int i = 0; (m_attrs != null) && (i < m_attrs.length); i++)
+        {
+            msg = msg + " [" + m_attrs[i].getName() + "="+ m_attrs[i].getValue() + "]";
+        }
+        return msg;
+    }
+
+    // Like this: pkg1; pkg2; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2,
+    //            pkg1; pkg2; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2
+    public static R4Package[] parseImportOrExportHeader(String s)
+    {
+        R4Package[] pkgs = null;
+        if (s != null)
+        {
+            if (s.length() == 0)
+            {
+                throw new IllegalArgumentException(
+                    "The import and export headers cannot be an empty string.");
+            }
+            String[] ss = Util.parseDelimitedString(s, ",");
+            pkgs = parsePackageStrings(ss);
+        }
+        return (pkgs == null) ? new R4Package[0] : pkgs;
+    }
+
+    // Like this: pkg1; pkg2; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2
+    public static R4Package[] parsePackageStrings(String[] ss)
+        throws IllegalArgumentException
+    {
+        if (ss == null)
+        {
+            return null;
+        }
+
+        List completeList = new ArrayList();
+        for (int ssIdx = 0; ssIdx < ss.length; ssIdx++)
+        {
+            // Break string into semi-colon delimited pieces.
+            String[] pieces = Util.parseDelimitedString(ss[ssIdx], ";");
+
+            // Count the number of different packages; packages
+            // will not have an '=' in their string. This assumes
+            // that packages come first, before directives and
+            // attributes.
+            int pkgCount = 0;
+            for (int pieceIdx = 0; pieceIdx < pieces.length; pieceIdx++)
+            {
+                if (pieces[pieceIdx].indexOf('=') >= 0)
+                {
+                    break;
+                }
+                pkgCount++;
+            }
+
+            // Error if no packages were specified.
+            if (pkgCount == 0)
+            {
+                throw new IllegalArgumentException(
+                    "No packages specified on import: " + ss[ssIdx]);
+            }
+
+            // Parse the directives/attributes.
+            R4Directive[] dirs = new R4Directive[pieces.length - pkgCount];
+            R4Attribute[] attrs = new R4Attribute[pieces.length - pkgCount];
+            int dirCount = 0, attrCount = 0;
+            int idx = -1;
+            String sep = null;
+            for (int pieceIdx = pkgCount; pieceIdx < pieces.length; pieceIdx++)
+            {
+                // Check if it is a directive.
+                if ((idx = pieces[pieceIdx].indexOf(":=")) >= 0)
+                {
+                    sep = ":=";
+                }
+                // Check if it is an attribute.
+                else if ((idx = pieces[pieceIdx].indexOf("=")) >= 0)
+                {
+                    sep = "=";
+                }
+                // It is an error.
+                else
+                {
+                    throw new IllegalArgumentException(
+                        "Not a directive/attribute: " + ss[ssIdx]);
+                }
+
+                String key = pieces[pieceIdx].substring(0, idx).trim();
+                String value = pieces[pieceIdx].substring(idx + sep.length()).trim();
+
+                // Remove quotes, if value is quoted.
+                if (value.startsWith("\"") && value.endsWith("\""))
+                {
+                    value = value.substring(1, value.length() - 1);
+                }
+
+                // Save the directive/attribute in the appropriate array.
+                if (sep.equals(":="))
+                {
+                    dirs[dirCount++] = new R4Directive(key, value);
+                }
+                else
+                {
+                    attrs[attrCount++] = new R4Attribute(key, value, false);
+                }
+            }
+
+            // Shrink directive array.
+            R4Directive[] dirsFinal = new R4Directive[dirCount];
+            System.arraycopy(dirs, 0, dirsFinal, 0, dirCount);
+            // Shrink attribute array.
+            R4Attribute[] attrsFinal = new R4Attribute[attrCount];
+            System.arraycopy(attrs, 0, attrsFinal, 0, attrCount);
+
+            // Create package attributes for each package and
+            // set directives/attributes. Add each package to
+            // completel list of packages.
+            R4Package[] pkgs = new R4Package[pkgCount];
+            for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++)
+            {
+                pkgs[pkgIdx] = new R4Package(pieces[pkgIdx], dirsFinal, attrsFinal);
+                completeList.add(pkgs[pkgIdx]);
+            }
+        }
+    
+        R4Package[] pkgs = (R4Package[])
+            completeList.toArray(new R4Package[completeList.size()]);
+        return pkgs;
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/R4Package.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,182 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.felix.bundlerepository.metadataparser.XmlCommonHandler;
+import org.apache.felix.bundlerepository.metadataparser.kxmlsax.KXml2SAXParser;
+import org.osgi.framework.*;
+import org.osgi.service.obr.*;
+
+public class RepositoryAdminImpl implements RepositoryAdmin
+{
+    static BundleContext m_context = null;
+    private List m_urlList = new ArrayList();
+    private Map m_repoMap = new HashMap();
+    private boolean m_initialized = false;
+
+    // Reusable comparator for sorting resources by name.
+    private Comparator m_nameComparator = new ResourceComparator();
+
+    private static final String DEFAULT_REPOSITORY_URL =
+        "http://oscar-osgi.sf.net/obr2/repository.xml";
+    public static final String REPOSITORY_URL_PROP = "obr.repository.url";
+    public static final String EXTERN_REPOSITORY_TAG = "extern-repositories";
+
+    public RepositoryAdminImpl(BundleContext context)
+    {
+        m_context = context;
+
+        // Get repository URLs.
+        String urlStr = m_context.getProperty(REPOSITORY_URL_PROP);
+        if (urlStr != null)
+        {
+            StringTokenizer st = new StringTokenizer(urlStr);
+            if (st.countTokens() > 0)
+            {
+                while (st.hasMoreTokens())
+                {
+                    try
+                    {
+                        m_urlList.add(new URL(st.nextToken()));
+                    }
+                    catch (MalformedURLException ex)
+                    {
+                        System.err.println("RepositoryAdminImpl: " + ex);
+                    }
+                }
+            }
+        }
+
+        // Use the default URL if none were specified.
+        if (m_urlList.size() == 0)
+        {
+            try
+            {
+                m_urlList.add(new URL(DEFAULT_REPOSITORY_URL));
+            }
+            catch (MalformedURLException ex)
+            {
+                System.err.println("RepositoryAdminImpl: " + ex);
+            }
+        }
+    }
+
+    public synchronized Repository addRepository(URL url) throws Exception
+    {
+        if (!m_urlList.contains(url))
+        {
+            m_urlList.add(url);
+        }
+
+        // If the repository URL is a duplicate, then we will just
+        // replace the existing repository object with a new one,
+        // which is effectively the same as refreshing the repository.
+        Repository repo = new RepositoryImpl(url);
+        m_repoMap.put(url, repo);
+        return repo;
+    }
+
+    public synchronized boolean removeRepository(URL url)
+    {
+        m_repoMap.remove(url);
+        return (m_urlList.remove(url)) ? true : false;
+    }
+
+    public synchronized Repository[] listRepositories()
+    {
+        if (!m_initialized)
+        {
+            initialize();
+        }
+        return (Repository[]) m_repoMap.values().toArray(new Repository[m_repoMap.size()]);
+    }
+
+    public synchronized Resource getResource(String respositoryId)
+    {
+        // TODO: OBR - Auto-generated method stub
+        return null;
+    }
+
+    public synchronized Resolver resolver()
+    {
+        if (!m_initialized)
+        {
+            initialize();
+        }
+
+        return new ResolverImpl(m_context, this);
+    }
+
+    public synchronized Resource[] discoverResources(String filterExpr)
+    {
+        if (!m_initialized)
+        {
+            initialize();
+        }
+
+        Filter filter =  null;
+        try
+        {
+            filter = m_context.createFilter(filterExpr);
+        }
+        catch (InvalidSyntaxException ex)
+        {
+            System.err.println(ex);
+        }
+
+        Resource[] resources = null;
+        MapToDictionary dict = new MapToDictionary(null);
+        Repository[] repos = listRepositories();
+        List matchList = new ArrayList();
+        for (int repoIdx = 0; (repos != null) && (repoIdx < repos.length); repoIdx++)
+        {
+            resources = repos[repoIdx].getResources();
+            for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+            {
+                dict.setSourceMap(resources[resIdx].getProperties());
+                if (filter.match(dict))
+                {
+                    matchList.add(resources[resIdx]);
+                }
+            }
+        }
+
+        // Convert matching resources to an array an sort them by name.
+        resources = (Resource[]) matchList.toArray(new Resource[matchList.size()]);
+        Arrays.sort(resources, m_nameComparator);
+        return resources;
+    }
+
+    private void initialize()
+    {
+        m_initialized = true;
+        m_repoMap.clear();
+
+        for (int i = 0; i < m_urlList.size(); i++)
+        {
+            URL url = (URL) m_urlList.get(i);
+            Repository repo = new RepositoryImpl(url);
+            if (repo != null)
+            {
+                m_repoMap.put(url, repo);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,178 @@
+package org.apache.felix.bundlerepository;
+
+import java.io.*;
+import java.net.*;
+import java.net.URL;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+
+import org.apache.felix.bundlerepository.metadataparser.XmlCommonHandler;
+import org.apache.felix.bundlerepository.metadataparser.kxmlsax.KXml2SAXParser;
+import org.osgi.service.obr.*;
+import org.osgi.service.obr.Repository;
+import org.osgi.service.obr.Resource;
+
+public class RepositoryImpl implements Repository
+{
+    private String m_name = null;
+    private long m_lastmodified = 0;
+    private URL m_url = null;
+    private Resource[] m_resources = null;
+    private int m_hopCount = 1;
+
+    // Reusable comparator for sorting resources by name.
+    private ResourceComparator m_nameComparator = new ResourceComparator();
+
+    public RepositoryImpl(URL url)
+    {
+        m_url = url;
+        parseRepositoryFile(m_hopCount);
+    }
+
+    public URL getURL()
+    {
+        return m_url;
+    }
+
+    protected void setURL(URL url)
+    {
+        m_url = url;
+    }
+
+    public Resource[] getResources()
+    {
+        return m_resources;
+    }
+
+    // TODO: OBR - Wrong parameter type from metadata parser.
+    public void addResource(ResourceImpl resource)
+    {
+        // Set resource's repository.
+        ((ResourceImpl) resource).setRepository(this);
+
+        // Add to resource array.
+        if (m_resources == null)
+        {
+            m_resources = new Resource[] { resource };
+        }
+        else
+        {
+            Resource[] newResources = new Resource[m_resources.length + 1];
+            System.arraycopy(m_resources, 0, newResources, 0, m_resources.length);
+            newResources[m_resources.length] = resource;
+            m_resources = newResources;
+        }
+
+        Arrays.sort(m_resources, m_nameComparator);
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public void setName(String name)
+    {
+        m_name = name;
+    }
+
+    public long getLastModified()
+    {
+        return m_lastmodified;
+    }
+
+    public void setLastmodified(String s)
+    {
+        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmss.SSS");
+        try
+        {
+            m_lastmodified = format.parse(s).getTime();
+        }
+        catch (ParseException ex)
+        {
+        }
+    }
+
+    private void parseRepositoryFile(int hopCount)
+    {
+// TODO: OBR - Implement hop count.
+        InputStream is = null;
+        BufferedReader br = null;
+
+        try
+        {
+            // Do it the manual way to have a chance to 
+            // set request properties as proxy auth (EW).
+            URLConnection conn = m_url.openConnection(); 
+
+            // Support for http proxy authentication
+            String auth = System.getProperty("http.proxyAuth");
+            if ((auth != null) && (auth.length() > 0))
+            {
+                if ("http".equals(m_url.getProtocol()) ||
+                    "https".equals(m_url.getProtocol()))
+                {
+                    String base64 = Util.base64Encode(auth);
+                    conn.setRequestProperty(
+                        "Proxy-Authorization", "Basic " + base64);
+                }
+            }
+            is = conn.getInputStream();
+
+            // Create the parser Kxml
+            XmlCommonHandler handler = new XmlCommonHandler();
+            try
+            {
+                Object factory = new Object() {
+                    public RepositoryImpl newInstance()
+                    {
+                        return RepositoryImpl.this;
+                    }
+                };
+                handler.addType("repository", factory, Repository.class);
+                handler.addType("resource", ResourceImpl.class, Resource.class);
+                handler.addType("category", CategoryImpl.class, null);
+                handler.addType("require", RequirementImpl.class, Requirement.class);
+                handler.addType("capability", CapabilityImpl.class, Capability.class);
+                handler.addType("p", PropertyImpl.class, null);
+                handler.setDefaultType(String.class, null);
+            }
+            catch (Exception ex)
+            {
+                System.err.println("RepositoryAdminImpl: " + ex);
+            }
+
+            br = new BufferedReader(new InputStreamReader(is));
+            KXml2SAXParser parser;
+            try
+            {
+                parser = new KXml2SAXParser(br);
+                parser.parseXML(handler);
+            }
+            catch (Exception ex)
+            {
+                ex.printStackTrace();
+            }
+        }
+        catch (MalformedURLException ex)
+        {
+            System.err.println("RepositoryAdminImpl: " + ex);
+        }
+        catch (IOException ex)
+        {
+            System.err.println("RepositoryAdminImpl: " + ex);
+        }
+        finally
+        {
+            try
+            {
+                if (is != null) is.close();
+            }
+            catch (IOException ex)
+            {
+                // Not much we can do.
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,114 @@
+package org.apache.felix.bundlerepository;
+
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.obr.Capability;
+import org.osgi.service.obr.Requirement;
+
+public class RequirementImpl implements Requirement
+{
+    private String m_name = null;
+    private boolean m_extend = false;
+    private boolean m_multiple = false;
+    private boolean m_optional = false;
+    private Filter m_filter = null;
+    private String m_comment = null;
+    private MapToDictionary m_dict = new MapToDictionary(null);
+
+    public RequirementImpl()
+    {
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public synchronized void setName(String name)
+    {
+        m_name = name;
+    }
+
+    public String getFilter()
+    {
+        return m_filter.toString();
+    }
+
+    public synchronized void setFilter(String filter)
+    {
+        try
+        {
+            m_filter = RepositoryAdminImpl.m_context.createFilter(filter);
+        }
+        catch (InvalidSyntaxException ex)
+        {
+            m_filter = null;
+            System.err.println(ex);
+        }
+    }
+
+    public synchronized boolean isSatisfied(Capability capability)
+    {
+        m_dict.setSourceMap(capability.getProperties());
+        return m_filter.match(m_dict);
+    }
+
+    public boolean isExtend()
+    {
+        return m_extend;
+    }
+
+    public synchronized void setExtend(String s)
+    {
+        m_extend = Boolean.valueOf(s).booleanValue();
+    }
+
+    public boolean isMultiple()
+    {
+        return m_multiple;
+    }
+
+    public synchronized void setMultiple(String s)
+    {
+        m_multiple = Boolean.valueOf(s).booleanValue();
+    }
+
+    public boolean isOptional()
+    {
+        return m_optional;
+    }
+
+    public synchronized void setOptional(String s)
+    {
+        m_optional = Boolean.valueOf(s).booleanValue();
+    }
+
+    public String getComment()
+    {
+        return m_comment;
+    }
+
+    public synchronized void addText(String s)
+    {
+        m_comment = s;
+    }
+
+    public synchronized boolean equals(Object o)
+    {
+        if (o instanceof Requirement)
+        {
+            Requirement r = (Requirement) o;
+            return m_name.equals(r.getName()) &&
+                (m_optional == r.isOptional()) &&
+                (m_multiple == r.isMultiple()) &&
+                m_filter.toString().equals(r.getFilter()) &&
+                m_comment.equals(r.getComment());
+        }
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return m_filter.toString().hashCode();
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,608 @@
+package org.apache.felix.bundlerepository;
+
+import java.net.URL;
+import java.util.*;
+
+import org.apache.felix.bundlerepository.LocalRepositoryImpl.LocalResourceImpl;
+import org.osgi.framework.*;
+import org.osgi.service.obr.*;
+
+public class ResolverImpl implements Resolver
+{
+    private BundleContext m_context = null;
+    private RepositoryAdmin m_admin = null;
+    private LocalRepositoryImpl m_local = null;
+    private Set m_addedSet = new HashSet();
+    private Set m_resolveSet = new HashSet();
+    private Set m_requiredSet = new HashSet();
+    private Set m_optionalSet = new HashSet();
+    private Map m_reasonMap = new HashMap();
+    private Map m_unsatisfiedMap = new HashMap();
+    private boolean m_resolved = false;
+
+    public ResolverImpl(BundleContext context, RepositoryAdmin admin)
+    {
+        m_context = context;
+        m_admin = admin;
+    }
+
+    public synchronized void add(Resource resource)
+    {
+        m_resolved = false;
+        m_addedSet.add(resource);
+    }
+
+    public synchronized Requirement[] getUnsatisfiedRequirements()
+    {
+        if (m_resolved)
+        {
+            return (Requirement[])
+                m_unsatisfiedMap.keySet().toArray(
+                    new Requirement[m_unsatisfiedMap.size()]);
+        }
+        throw new IllegalStateException("The resources have not been resolved.");
+    }
+
+    public synchronized Resource[] getOptionalResources()
+    {
+        if (m_resolved)
+        {
+            return (Resource[])
+                m_optionalSet.toArray(
+                    new Resource[m_optionalSet.size()]);
+        }
+        throw new IllegalStateException("The resources have not been resolved.");
+    }
+
+    public synchronized Requirement[] getReason(Resource resource)
+    {
+        if (m_resolved)
+        {
+            return (Requirement[]) m_reasonMap.get(resource);
+        }
+        throw new IllegalStateException("The resources have not been resolved.");
+    }
+
+    public synchronized Resource[] getResources(Requirement requirement)
+    {
+        if (m_resolved)
+        {
+            return (Resource[]) m_unsatisfiedMap.get(requirement);
+        }
+        throw new IllegalStateException("The resources have not been resolved.");
+    }
+
+    public synchronized Resource[] getRequiredResources()
+    {
+        if (m_resolved)
+        {
+            return (Resource[])
+                m_requiredSet.toArray(
+                    new Resource[m_requiredSet.size()]);
+        }
+        throw new IllegalStateException("The resources have not been resolved.");
+    }
+
+    public synchronized Resource[] getAddedResources()
+    {
+        return (Resource[]) m_addedSet.toArray(new Resource[m_addedSet.size()]);
+    }
+
+    public synchronized boolean resolve()
+    {
+        // Get a current local repository.
+        // TODO: OBR - We might want to make a smarter local repository
+        // that caches installed bundles rather than re-parsing them
+        // each time, since this could be costly.
+        if (m_local != null)
+        {
+            m_local.dispose();
+        }
+        m_local = new LocalRepositoryImpl(m_context);
+
+        // Reset instance values.
+        m_resolveSet.clear();
+        m_requiredSet.clear();
+        m_optionalSet.clear();
+        m_reasonMap.clear();
+        m_unsatisfiedMap.clear();
+        m_resolved = true;
+
+        boolean result = true;
+
+        // Loop through each resource in added list and resolve.
+        for (Iterator iter = m_addedSet.iterator(); iter.hasNext(); )
+        {
+            if (!resolve((Resource) iter.next()))
+            {
+                // If any resource does not resolve, then the
+                // entire result will be false.
+                result = false;
+            }
+        }
+
+        // Clean up the resulting data structures.
+        List locals = Arrays.asList(m_local.getResources());
+        m_requiredSet.removeAll(m_addedSet);
+        m_requiredSet.removeAll(locals);
+        m_optionalSet.removeAll(m_addedSet);
+        m_optionalSet.removeAll(m_requiredSet);
+        m_optionalSet.removeAll(locals);
+
+        // Return final result.
+        return result;
+    }
+
+    private boolean resolve(Resource resource)
+    {
+        boolean result = true;
+
+        // Check for a cycle.
+        if (m_resolveSet.contains(resource))
+        {
+            return result;
+        }
+
+        // Add to resolve map to avoid cycles.
+        m_resolveSet.add(resource);
+
+        // Resolve the requirements for the resource according to the
+        // search order of: added, local, resolving, and remote resources.
+        Requirement[] reqs = resource.getRequirements();
+        if (reqs != null)
+        {
+            Resource candidate = null;
+            for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+            {
+                candidate = searchAddedResources(reqs[reqIdx]);
+                if (candidate == null)
+                {
+                    candidate = searchLocalResources(reqs[reqIdx]);
+                    if (candidate == null)
+                    {
+                        candidate = searchResolvingResources(reqs[reqIdx]);
+                        if (candidate == null)
+                        {
+                            candidate = searchRemoteResources(reqs[reqIdx]);
+                        }
+                    }
+                }
+
+                if ((candidate == null) && !reqs[reqIdx].isOptional())
+                {
+                    // The resolve failed.
+                    result = false;
+                    // Associated the current resource to the requirement
+                    // in the unsatisfied requirement map.
+                    Resource[] resources = (Resource[]) m_unsatisfiedMap.get(reqs[reqIdx]);
+                    if (resources == null)
+                    {
+                        resources = new Resource[] { resource };
+                    }
+                    else
+                    {
+                        Resource[] tmp = new Resource[resources.length + 1];
+                        System.arraycopy(resources, 0, tmp, 0, resources.length);
+                        tmp[resources.length] = resource;
+                        resources = tmp;
+                    }
+                    m_unsatisfiedMap.put(reqs[reqIdx], resources);
+                }
+                else if (candidate != null)
+                {
+                    // The resolved succeeded; record the candidate
+                    // as either optional or required.
+                    if (reqs[reqIdx].isOptional())
+                    {
+                        m_optionalSet.add(candidate);
+                    }
+                    else
+                    {
+                        m_requiredSet.add(candidate);
+                    }
+
+                    // Add the reason why the candidate was selected.
+                    addReason(candidate, reqs[reqIdx]);
+
+                    // Try to resolve the candidate.
+                    if (!resolve(candidate))
+                    {
+                        result = false;
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+    private Resource searchAddedResources(Requirement req)
+    {
+        for (Iterator iter = m_addedSet.iterator(); iter.hasNext(); )
+        {
+            Resource resource = (Resource) iter.next();
+            Capability[] caps = resource.getCapabilities();
+            for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+            {
+                if (req.isSatisfied(caps[capIdx]))
+                {
+                    // The requirement is already satisfied an existing
+                    // resource, return the resource.
+                    return resource;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Resource searchLocalResources(Requirement req)
+    {
+        Resource[] resources = m_local.getResources();
+        for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+        {
+            Capability[] caps = resources[resIdx].getCapabilities();
+            for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+            {
+                if (req.isSatisfied(caps[capIdx]))
+                {
+                    return resources[resIdx];
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Resource searchResolvingResources(Requirement req)
+    {
+        Resource[] resources = (Resource[])
+            m_resolveSet.toArray(new Resource[m_resolveSet.size()]);
+        for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+        {
+            Capability[] caps = resources[resIdx].getCapabilities();
+            for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+            {
+                if (req.isSatisfied(caps[capIdx]))
+                {
+                    return resources[resIdx];
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Resource searchRemoteResources(Requirement req)
+    {
+        // For now, guess that if there is a version associated with
+        // the candidate capability that we should choose the highest
+        // version; otherwise, choose the resource with the greatest
+        // number of capabilities.
+        // TODO: OBR - This could probably be improved.
+        Resource best = null;
+        Version bestVersion = null;
+        Repository[] repos = m_admin.listRepositories();
+        for (int repoIdx = 0; (repos != null) && (repoIdx < repos.length); repoIdx++)
+        {
+            Resource[] resources = repos[repoIdx].getResources();
+            for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+            {
+                Capability[] caps = resources[resIdx].getCapabilities();
+                for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+                {
+                    if (req.isSatisfied(caps[capIdx]))
+                    {
+                        if (best == null)
+                        {
+                            best = resources[resIdx];
+                            Object v = caps[capIdx].getProperties().get(Resource.VERSION);
+                            if ((v != null) && (v instanceof Version))
+                            {
+                                bestVersion = (Version) v;
+                            }
+                        }
+                        else
+                        {
+                            Object v = caps[capIdx].getProperties().get(Resource.VERSION);
+
+                            // If there is no version, then select the resource
+                            // with the greatest number of capabilities.
+                            if ((v == null) && (bestVersion == null)
+                                && (best.getCapabilities().length < caps.length))
+                            {
+                                best = resources[resIdx];
+                                bestVersion = (Version) v;
+                            }
+                            else if ((v != null) && (v instanceof Version))
+                            {
+                                // If there is no best version or if the current
+                                // resource's version is lower, then select it.
+                                if ((bestVersion == null) || (bestVersion.compareTo(v) < 0))
+                                {
+                                    best = resources[resIdx];
+                                    bestVersion = (Version) v;
+                                }
+                                // If the current resource version is equal to the
+                                // best, then select the one with the greatest
+                                // number of capabilities.
+                                else if ((bestVersion != null) && (bestVersion.compareTo(v) == 0)
+                                    && (best.getCapabilities().length < caps.length))
+                                {
+                                    best = resources[resIdx];
+                                    bestVersion = (Version) v;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return best;
+    }
+
+    public synchronized void deploy(boolean start)
+    {
+        // Must resolve if not already resolved.
+        if (!m_resolved && !resolve())
+        {
+            // TODO: OBR - Use logger if possible.
+            System.err.println("Resolver: Cannot resolve target resources.");
+            return;
+        }
+
+        // Check to make sure that our local state cache is up-to-date
+        // and error if it is not. This is not completely safe, because
+        // the state can still change during the operation, but we will
+        // be optimistic. This could also be made smarter so that it checks
+        // to see if the local state changes overlap with the resolver.
+        if (m_local.getLastModified() != m_local.getCurrentTimeStamp())
+        {
+            throw new IllegalStateException("Framework state has changed, must resolve again.");
+        }
+
+        // Eliminate duplicates from target, required, optional resources.
+        Map deployMap = new HashMap();
+        Resource[] resources = getAddedResources();
+        for (int i = 0; (resources != null) && (i < resources.length); i++)
+        {
+            deployMap.put(resources[i], resources[i]);
+        }
+        resources = getRequiredResources();
+        for (int i = 0; (resources != null) && (i < resources.length); i++)
+        {
+            deployMap.put(resources[i], resources[i]);
+        }
+        resources = getOptionalResources();
+        for (int i = 0; (resources != null) && (i < resources.length); i++)
+        {
+            deployMap.put(resources[i], resources[i]);
+        }
+        Resource[] deployResources = (Resource[])
+            deployMap.keySet().toArray(new Resource[deployMap.size()]);
+
+        // List to hold all resources to be started.
+        List startList = new ArrayList();
+
+        // Deploy each resource, which will involve either finding a locally
+        // installed resource to update or the installation of a new version
+        // of the resource to be deployed.
+        for (int i = 0; i < deployResources.length; i++)
+        {
+            // For the resource being deployed, see if there is an older
+            // version of the resource already installed that can potentially
+            // be updated.
+            LocalRepositoryImpl.LocalResourceImpl localResource =
+                findUpdatableLocalResource(deployResources[i]);
+            // If a potentially updatable older version was found,
+            // then verify that updating the local resource will not
+            // break any of the requirements of any of the other
+            // resources being deployed.
+            if ((localResource != null) &&
+                isResourceUpdatable(localResource, deployResources[i], deployResources))
+            {
+                // Only update if it is a different version.
+                if (!localResource.equals(deployResources[i]))
+                {
+                    // Update the installed bundle.
+                    try
+                    {
+                        localResource.getBundle().update(deployResources[i].getURL().openStream());
+    
+                        // If necessary, save the updated bundle to be
+                        // started later.
+                        if (start)
+                        {
+                            startList.add(localResource.getBundle());
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        // TODO: OBR - Use logger if possible.
+                        System.err.println("Resolver: Update error - " + Util.getBundleName(localResource.getBundle()));
+                        ex.printStackTrace(System.err);
+                        return;
+                    }
+                }
+            }
+            else
+            {
+                // Install the bundle.
+                try
+                {
+                    // Perform the install, but do not use the actual
+                    // bundle JAR URL for the bundle location, since this will
+                    // limit OBR's ability to manipulate bundle versions. Instead,
+                    // use a unique timestamp as the bundle location.
+                    URL url = deployResources[i].getURL();
+                    if (url != null)
+                    {
+                        Bundle bundle = m_context.installBundle(
+                            "obr://"
+                            + deployResources[i].getSymbolicName()
+                            + "/" + System.currentTimeMillis(),
+                            url.openStream());
+    
+                        // If necessary, save the installed bundle to be
+                        // started later.
+                        if (start)
+                        {
+                            startList.add(bundle);
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    // TODO: OBR - Use logger if possible.
+                    System.err.println("Resolver: Install error - "
+                        + deployResources[i].getSymbolicName());
+                    ex.printStackTrace(System.err);
+                    return;
+                }
+            }
+        }
+
+        for (int i = 0; i < startList.size(); i++)
+        {
+            try
+            {
+                ((Bundle) startList.get(i)).start();
+            }
+            catch (BundleException ex)
+            {
+                // TODO: OBR - Use logger if possible.
+                System.err.println("Resolver: Start error - " + ex);
+            }
+        }
+    }
+
+    private void addReason(Resource resource, Requirement req)
+    {
+        Requirement[] reasons = (Requirement[]) m_reasonMap.get(resource);
+        if (reasons == null)
+        {
+            reasons = new Requirement[] { req };
+        }
+        else
+        {
+            Requirement[] tmp = new Requirement[reasons.length + 1];
+            System.arraycopy(reasons, 0, tmp, 0, reasons.length);
+            tmp[reasons.length] = req;
+            reasons = tmp;
+        }
+        m_reasonMap.put(resource, reasons);
+    }
+
+    // TODO: OBR - Think about this again and make sure that deployment ordering
+    // won't impact it...we need to update the local state too.
+    private LocalResourceImpl findUpdatableLocalResource(Resource resource)
+    {
+        // Determine if any other versions of the specified resource
+        // already installed.
+        Resource[] localResources = findLocalResources(resource.getSymbolicName());
+        if (localResources != null)
+        {
+            // Since there are local resources with the same symbolic
+            // name installed, then we must determine if we can
+            // update an existing resource or if we must install
+            // another one. Loop through all local resources with same
+            // symbolic name and find the first one that can be updated
+            // without breaking constraints of existing local resources.
+            for (int i = 0; i < localResources.length; i++)
+            {
+                if (isResourceUpdatable(localResources[i], resource, m_local.getResources()))
+                {
+                    return (LocalResourceImpl) localResources[i];
+                }
+            }
+        }
+        return null;
+    }
+
+    private Resource[] findLocalResources(String symName)
+    {
+        Resource[] localResources = m_local.getResources();
+
+        List matchList = new ArrayList();
+        for (int i = 0; i < localResources.length; i++)
+        {
+            String localSymName = localResources[i].getSymbolicName();
+            if ((localSymName != null) && localSymName.equals(symName))
+            {
+                matchList.add(localResources[i]);
+            }
+        }
+        return (Resource[]) matchList.toArray(new Resource[matchList.size()]);
+    }
+
+    private boolean isResourceUpdatable(
+        Resource oldVersion, Resource newVersion, Resource[] resources)
+    {
+        // Get all of the local resolvable requirements for the old
+        // version of the resource from the specified resource array.
+        Requirement[] reqs = getResolvableRequirements(oldVersion, resources);
+
+        // Now make sure that all of the requirements resolved by the
+        // old version of the resource can also be resolved by the new
+        // version of the resource.
+        Capability[] caps = newVersion.getCapabilities();
+        if (caps == null)
+        {
+            return false;
+        }
+        for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+        {
+            boolean satisfied = false;
+            for (int capIdx = 0; !satisfied && (capIdx < caps.length); capIdx++)
+            {
+                if (reqs[reqIdx].isSatisfied(caps[capIdx]))
+                {
+                    satisfied = true;
+                }
+            }
+
+            // If any of the previously resolved requirements cannot
+            // be resolved, then the resource is not updatable.
+            if (!satisfied)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    
+    private Requirement[] getResolvableRequirements(Resource resource, Resource[] resources)
+    {
+        // For the specified resource, find all requirements that are
+        // satisfied by any of its capabilities in the specified resource
+        // array.
+        Capability[] caps = resource.getCapabilities();
+        if ((caps != null) && (caps.length > 0))
+        {
+            List reqList = new ArrayList();
+            for (int capIdx = 0; capIdx < caps.length; capIdx++)
+            {
+                boolean added = false;
+                for (int resIdx = 0; !added && (resIdx < resources.length); resIdx++)
+                {
+                    Requirement[] reqs = resources[resIdx].getRequirements();
+                    for (int reqIdx = 0;
+                        (reqs != null) && (reqIdx < reqs.length);
+                        reqIdx++)
+                    {
+                        if (reqs[reqIdx].isSatisfied(caps[capIdx]))
+                        {
+                            added = true;
+                            reqList.add(reqs[reqIdx]);
+                        }
+                    }
+                }
+            }
+            return (Requirement[])
+                reqList.toArray(new Requirement[reqList.size()]);
+        }
+        return null;
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceComparator.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceComparator.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceComparator.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceComparator.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,33 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+import java.util.Comparator;
+
+import org.osgi.service.obr.Resource;
+
+class ResourceComparator implements Comparator
+{
+    public int compare(Object o1, Object o2)
+    {
+        Resource r1 = (Resource) o1;
+        Resource r2 = (Resource) o2;
+        String name1 = (String) r1.getPresentationName();
+        String name2 = (String) r2.getPresentationName();
+        return name1.compareToIgnoreCase(name2);
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceComparator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,291 @@
+package org.apache.felix.bundlerepository;
+
+import java.net.*;
+import java.util.*;
+
+import org.osgi.framework.Version;
+import org.osgi.service.obr.*;
+
+public class ResourceImpl implements Resource, Map
+{
+    private final String URI = "uri";
+
+    private Repository m_repo = null;
+    private Map m_map = null;
+    private List m_catList = new ArrayList();
+    private List m_capList = new ArrayList();
+    private List m_reqList = new ArrayList();
+
+    private String m_resourceURI = "";
+    private String m_docURI = "";
+    private String m_licenseURI = "";
+    private String m_sourceURI = "";
+    private boolean m_converted = false;
+
+    public ResourceImpl()
+    {
+        this(null);
+    }
+
+    public ResourceImpl(ResourceImpl resource)
+    {
+        m_map = new TreeMap(new Comparator() {
+            public int compare(Object o1, Object o2)
+            {
+                return o1.toString().compareToIgnoreCase(o2.toString());
+            }
+        });
+
+        if (resource != null)
+        {
+            resource.putAll(resource.getProperties());
+            m_catList.addAll(resource.m_catList);
+            m_capList.addAll(resource.m_capList);
+            m_reqList.addAll(resource.m_reqList);
+        }
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o instanceof Resource)
+        {
+            return ((Resource) o).getSymbolicName().equals(getSymbolicName())
+                && ((Resource) o).getVersion().equals(getVersion());
+        }
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return getSymbolicName().hashCode() ^ getVersion().hashCode();
+    }
+
+    public Map getProperties()
+    {
+        if (!m_converted)
+        {
+            convertURItoURL();
+        }
+        return m_map;
+    }
+
+    public String getPresentationName()
+    {
+        return (String) m_map.get(PRESENTATION_NAME);
+    }
+
+    public String getSymbolicName()
+    {
+        return (String) m_map.get(SYMBOLIC_NAME);
+    }
+
+    public String getId()
+    {
+        return (String) m_map.get(ID);
+    }
+
+    public Version getVersion()
+    {
+        return (Version) m_map.get(VERSION);
+    }
+
+    public URL getURL()
+    {
+        if (!m_converted)
+        {
+            convertURItoURL();
+        }
+        return (URL) m_map.get(URL);
+    }
+
+    public Requirement[] getRequirements()
+    {
+        return (Requirement[]) m_reqList.toArray(new Requirement[m_reqList.size()]);
+    }
+
+    public void addRequire(Requirement req)
+    {
+System.out.println("ADDING REQUIREMENTS PROPERLY");
+        m_reqList.add(req);
+    }
+
+    public Capability[] getCapabilities()
+    {
+System.out.println("ADDING CAPABILITIES PROPERLY");
+        return (Capability[]) m_capList.toArray(new Capability[m_capList.size()]);
+    }
+
+    // TODO: OBR - Should this be a property?
+    public void addCapability(Capability cap)
+    {
+        m_capList.add(cap);
+    }
+
+    public String[] getCategories()
+    {
+        return (String[]) m_catList.toArray(new String[m_catList.size()]);
+    }
+
+    public void addCategory(CategoryImpl cat)
+    {
+        m_catList.add(cat.getId());
+    }
+
+    public Repository getRepository()
+    {
+        return m_repo;
+    }
+
+    protected void setRepository(Repository repo)
+    {
+        m_repo = repo;
+    }
+
+    //
+    // Map interface methods.
+    //
+
+    public int size()
+    {
+        return m_map.size();
+    }
+
+    public void clear()
+    {
+        m_map.clear();
+    }
+
+    public boolean isEmpty()
+    {
+        return m_map.isEmpty();
+    }
+
+    public boolean containsKey(Object key)
+    {
+        return m_map.containsKey(key);
+    }
+
+    public boolean containsValue(Object value)
+    {
+        return m_map.containsValue(value);
+    }
+
+    public Collection values()
+    {
+        return m_map.values();
+    }
+
+    public void putAll(Map t)
+    {
+        m_map.putAll(t);
+    }
+
+    public Set entrySet()
+    {
+        return m_map.entrySet();
+    }
+
+    public Set keySet()
+    {
+        return m_map.keySet();
+    }
+
+    public Object get(Object key)
+    {
+        return m_map.get(key);
+    }
+
+    public Object remove(Object key)
+    {
+        return m_map.remove(key);
+    }
+
+    public Object put(Object key, Object value)
+    {
+        // Capture the URIs since they might be relative, so we
+        // need to defer setting the actual URL value until they
+        // are used so that we will know our repository and its
+        // base URL.
+        if (key.equals(LICENSE_URL))
+        {
+            m_licenseURI = (String) value;
+        }
+        else if (key.equals(DOCUMENTATION_URL))
+        {
+            m_docURI = (String) value;
+        }
+        else if (key.equals(SOURCE_URL))
+        {
+            m_sourceURI = (String) value;
+        }
+        else if (key.equals(URI))
+        {
+            m_resourceURI = (String) value;
+        }
+        else
+        {
+            if (key.equals(VERSION))
+            {
+                value = new Version(value.toString());
+            }
+            else if (key.equals(SIZE))
+            {
+                value = Long.valueOf(value.toString());
+            }
+            // TODO: OBR - These should be handled by the "add" methods above.
+            else if (key.equals("require"))
+            {
+System.out.println("ADDING REQUIREMENTS IMPROPERLY!!!!!!!!!!!!!!!");
+                m_reqList.add(value);
+                return null;
+            }
+            else if (key.equals("capability"))
+            {
+System.out.println("ADDING CAPABILITIES IMPROPERLY!!!!!!!!!!!!!!!");
+                m_capList.add(value);
+                return null;
+            }
+            else if (key.equals("category"))
+            {
+                m_catList.add(value);
+                return null;
+            }
+    
+            return m_map.put(key, value);
+        }
+
+        return null;
+    }
+
+    private void convertURItoURL()
+    {
+        if (m_repo != null)
+        {
+            try
+            {
+                URL base = m_repo.getURL();
+                if (m_resourceURI != null)
+                {
+                    m_map.put(URL, new URL(base, m_resourceURI));
+                }
+                if (m_docURI != null)
+                {
+                    m_map.put(DOCUMENTATION_URL, new URL(base, m_docURI));
+                }
+                if (m_licenseURI != null)
+                {
+                    m_map.put(LICENSE_URL, new URL(base, m_licenseURI));
+                }
+                if (m_sourceURI != null)
+                {
+                    m_map.put(SOURCE_URL, new URL(base, m_sourceURI));
+                }
+                m_converted = true;
+            }
+            catch (MalformedURLException ex)
+            {
+                ex.printStackTrace(System.err);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/Util.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/Util.java?rev=391296&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/Util.java (added)
+++ incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/Util.java Tue Apr  4 06:17:11 2006
@@ -0,0 +1,254 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   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.apache.felix.bundlerepository;
+
+import java.io.*;
+import java.util.*;
+import java.util.StringTokenizer;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+public class Util
+{
+    public static String getClassName(String className)
+    {
+        if (className == null)
+        {
+            className = "";
+        }
+        return (className.lastIndexOf('.') < 0)
+            ? "" : className.substring(className.lastIndexOf('.') + 1);
+    }
+
+    public static String getBundleName(Bundle bundle)
+    {
+        String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+        return (name == null)
+            ? "Bundle " + Long.toString(bundle.getBundleId())
+            : name;
+    }
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return an array of string tokens or null if there were no tokens.
+    **/
+    public static String[] parseDelimitedString(String value, String delim)
+    {
+        if (value == null)
+        {
+           value = "";
+        }
+
+        List list = new ArrayList();
+
+        int CHAR = 1;
+        int DELIMITER = 2;
+        int STARTQUOTE = 4;
+        int ENDQUOTE = 8;
+
+        StringBuffer sb = new StringBuffer();
+
+        int expecting = (CHAR | DELIMITER | STARTQUOTE);
+        
+        for (int i = 0; i < value.length(); i++)
+        {
+            char c = value.charAt(i);
+
+            boolean isDelimiter = (delim.indexOf(c) >= 0);
+            boolean isQuote = (c == '"');
+
+            if (isDelimiter && ((expecting & DELIMITER) > 0))
+            {
+                list.add(sb.toString().trim());
+                sb.delete(0, sb.length());
+                expecting = (CHAR | DELIMITER | STARTQUOTE);
+            }
+            else if (isQuote && ((expecting & STARTQUOTE) > 0))
+            {
+                sb.append(c);
+                expecting = CHAR | ENDQUOTE;
+            }
+            else if (isQuote && ((expecting & ENDQUOTE) > 0))
+            {
+                sb.append(c);
+                expecting = (CHAR | STARTQUOTE | DELIMITER);
+            }
+            else if ((expecting & CHAR) > 0)
+            {
+                sb.append(c);
+            }
+            else
+            {
+                throw new IllegalArgumentException("Invalid delimited string: " + value);
+            }
+        }
+
+        if (sb.length() > 0)
+        {
+            list.add(sb.toString().trim());
+        }
+
+        return (String[]) list.toArray(new String[list.size()]);
+    }
+
+    public static int compareVersion(int[] v1, int[] v2)
+    {
+        if (v1[0] > v2[0])
+        {
+            return 1;
+        }
+        else if (v1[0] < v2[0])
+        {
+            return -1;
+        }
+        else if (v1[1] > v2[1])
+        {
+            return 1;
+        }
+        else if (v1[1] < v2[1])
+        {
+            return -1;
+        }
+        else if (v1[2] > v2[2])
+        {
+            return 1;
+        }
+        else if (v1[2] < v2[2])
+        {
+            return -1;
+        }
+        return 0;
+    }
+
+    private static final byte encTab[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+        0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
+        0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
+        0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+        0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
+        0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f };
+
+    private static final byte decTab[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1,
+        -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1,
+        -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+        18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29,
+        30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+        48, 49, 50, 51, -1, -1, -1, -1, -1 };
+
+    public static String base64Encode(String s) throws IOException
+    {
+        return encode(s.getBytes(), 0);
+    }
+
+    /**
+     * Encode a raw byte array to a Base64 String.
+     * 
+     * @param in Byte array to encode.
+     * @param len Length of Base64 lines. 0 means no line breaks.
+    **/
+    public static String encode(byte[] in, int len) throws IOException
+    {
+        ByteArrayOutputStream baos = null;
+        ByteArrayInputStream bais = null;
+        try
+        {
+            baos = new ByteArrayOutputStream();
+            bais = new ByteArrayInputStream(in);
+            encode(bais, baos, len);
+            // ASCII byte array to String
+            return (new String(baos.toByteArray()));
+        }
+        finally
+        {
+            if (baos != null)
+            {
+                baos.close();
+            }
+            if (bais != null)
+            {
+                bais.close();
+            }
+        }
+    }
+
+    public static void encode(InputStream in, OutputStream out, int len)
+        throws IOException
+    {
+
+        // Check that length is a multiple of 4 bytes
+        if (len % 4 != 0)
+        {
+            throw new IllegalArgumentException("Length must be a multiple of 4");
+        }
+
+        // Read input stream until end of file
+        int bits = 0;
+        int nbits = 0;
+        int nbytes = 0;
+        int b;
+
+        while ((b = in.read()) != -1)
+        {
+            bits = (bits << 8) | b;
+            nbits += 8;
+            while (nbits >= 6)
+            {
+                nbits -= 6;
+                out.write(encTab[0x3f & (bits >> nbits)]);
+                nbytes++;
+                // New line
+                if (len != 0 && nbytes >= len)
+                {
+                    out.write(0x0d);
+                    out.write(0x0a);
+                    nbytes -= len;
+                }
+            }
+        }
+
+        switch (nbits)
+        {
+            case 2:
+                out.write(encTab[0x3f & (bits << 4)]);
+                out.write(0x3d); // 0x3d = '='
+                out.write(0x3d);
+                break;
+            case 4:
+                out.write(encTab[0x3f & (bits << 2)]);
+                out.write(0x3d);
+                break;
+        }
+
+        if (len != 0)
+        {
+            if (nbytes != 0)
+            {
+                out.write(0x0d);
+                out.write(0x0a);
+            }
+            out.write(0x0d);
+            out.write(0x0a);
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/Util.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message