You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2005/08/16 20:34:41 UTC

svn commit: r233031 [7/21] - in /incubator/oscar/trunk: ./ etc/ lib/ src/ src/org/ src/org/apache/ src/org/apache/osgi/ src/org/apache/osgi/bundle/ src/org/apache/osgi/bundle/bundlerepository/ src/org/apache/osgi/bundle/bundlerepository/kxmlsax/ src/or...

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/FilterImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/FilterImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/FilterImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/FilterImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,240 @@
+/*
+ *   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.osgi.framework;
+
+import java.io.CharArrayReader;
+import java.io.IOException;
+import java.util.*;
+
+import org.apache.osgi.framework.util.CaseInsensitiveMap;
+import org.apache.osgi.framework.util.ldap.*;
+import org.osgi.framework.*;
+
+/**
+ * This class implements an RFC 1960-based filter. The syntax of the
+ * filter string is the string representation of LDAP search filters
+ * as defined in RFC 1960. These filters are used to search for services
+ * and to track services using <tt>ServiceTracker</tt> objects.
+**/
+public class FilterImpl implements Filter
+{
+    private LogWrapper m_logger = null;
+    private String m_toString = null;
+    private Evaluator m_evaluator = null;
+    private SimpleMapper m_mapper = null;
+
+// TODO: FilterImpl needs a logger, this is a hack to get FrameworkUtil to compile.
+    public FilterImpl(String expr) throws InvalidSyntaxException
+    {
+        this(null, expr);
+    }
+
+    /**
+     * Construct a filter for a given filter expression string.
+     * @param expr the filter expression string for the filter.
+    **/
+    public FilterImpl(LogWrapper logger, String expr) throws InvalidSyntaxException
+    {
+        m_logger = logger;
+        if (expr == null)
+        {
+            throw new InvalidSyntaxException("Filter cannot be null", null);
+        }
+
+        if (expr != null)
+        {
+            CharArrayReader car = new CharArrayReader(expr.toCharArray());
+            LdapLexer lexer = new LdapLexer(car);
+            Parser parser = new Parser(lexer);
+            try
+            {
+                if (!parser.start())
+                {
+                    throw new InvalidSyntaxException(
+                        "Failed to parse LDAP query.", expr);
+                }
+            }
+            catch (ParseException ex)
+            {
+                throw new InvalidSyntaxException(
+                    ex.getMessage(), expr);
+            }
+            catch (IOException ex)
+            {
+                throw new InvalidSyntaxException(
+                    ex.getMessage(), expr);
+            }
+            m_evaluator = new Evaluator(parser.getProgram());
+            m_mapper = new SimpleMapper();
+        }
+    }
+
+    /**
+     * Compares the <tt>Filter</tt> object to another.
+     * @param o the object to compare this <tt>Filter</tt> against.
+     * @return If the other object is a <tt>Filter</tt> object, it
+     *         returns <tt>this.toString().equals(obj.toString())</tt>;
+     *         <tt>false</tt> otherwise.
+    **/
+    public boolean equals(Object o)
+    {
+        if (o == null)
+        {
+            return false;
+        }
+        else if (o instanceof Filter)
+        {
+            return toString().equals(o.toString());
+        }
+        return false;
+    }
+
+    /**
+     * Returns the hash code for the <tt>Filter</tt> object.
+     * @return The value <tt>this.toString().hashCode()</tt>.
+    **/
+    public int hashCode()
+    {
+        return toString().hashCode();
+    }
+
+    /**
+     * Filter using a <tt>Dictionary</tt> object. The <tt>Filter</tt>
+     * is executed using the <tt>Dictionary</tt> object's keys and values.
+     * @param dict the <tt>Dictionary</tt> object whose keys and values
+     *             are used to determine a match.
+     * @return <tt>true</tt> if the <tt>Dictionary</tt> object's keys
+     *         and values match this filter; <tt>false</tt> otherwise.
+     * @throws IllegalArgumentException if the dictionary contains case
+     *         variants of the same key name.
+    **/
+    public boolean match(Dictionary dict)
+        throws IllegalArgumentException
+    {
+        try
+        {
+            m_mapper.setSource(dict);
+            return m_evaluator.evaluate(m_mapper);
+        }
+        catch (AttributeNotFoundException ex)
+        {
+            m_logger.log(LogWrapper.LOG_DEBUG, "FilterImpl: " + ex);
+        }
+        catch (EvaluationException ex)
+        {
+            m_logger.log(LogWrapper.LOG_ERROR, "FilterImpl: " + toString(), ex);
+        }
+        return false;
+    }
+
+    /**
+     * Filter using a service's properties. The <tt>Filter</tt>
+     * is executed using the properties of the referenced service.
+     * @param ref A reference to the service whose properties
+     *             are used to determine a match.
+     * @return <tt>true</tt> if the service's properties match this
+     *         filter; <tt>false</tt> otherwise.
+    **/
+    public boolean match(ServiceReference ref)
+    {
+        try
+        {
+            m_mapper.setSource(ref);
+            return m_evaluator.evaluate(m_mapper);
+        }
+        catch (AttributeNotFoundException ex)
+        {
+            m_logger.log(LogWrapper.LOG_DEBUG, "FilterImpl: " + ex);
+        }
+        catch (EvaluationException ex)
+        {
+            m_logger.log(LogWrapper.LOG_ERROR, "FilterImpl: " + toString(), ex);
+        }
+        return false;
+    }
+
+    public boolean matchCase(Dictionary dictionary)
+    {
+        // TODO: Implement Filter.matchCase()
+        return false;
+    }
+
+    /**
+     * Returns the <tt>Filter</tt> object's filter string.
+     * @return Filter string.
+    **/
+    public String toString()
+    {
+        if (m_toString == null)
+        {
+            m_toString = m_evaluator.toStringInfix();
+        }
+        return m_toString;
+    }
+
+    static class SimpleMapper implements Mapper
+    {
+        private ServiceReference m_ref = null;
+        private Map m_map = null;
+
+        public void setSource(ServiceReference ref)
+        {
+            m_ref = ref;
+            m_map = null;
+        }
+
+        public void setSource(Dictionary dict)
+        {
+            if (m_map == null)
+            {
+                m_map = new CaseInsensitiveMap();
+            }
+            else
+            {
+                m_map.clear();
+            }
+
+            if (dict != null)
+            {
+                Enumeration keys = dict.keys();
+                while (keys.hasMoreElements())
+                {
+                    Object key = keys.nextElement();
+                    if (m_map.get(key) == null)
+                    {
+                        m_map.put(key, dict.get(key));
+                    }
+                    else
+                    {
+                        throw new IllegalArgumentException(
+                            "Duplicate attribute: " + key.toString());
+                    }
+                }
+            }
+            m_ref = null;
+        }
+
+        public Object lookup(String name)
+        {
+            if (m_map == null)
+            {
+                return m_ref.getProperty(name);
+            }
+            return m_map.get(name);
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/FrameworkUtil.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/FrameworkUtil.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/FrameworkUtil.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/FrameworkUtil.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,29 @@
+/*
+ *   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.osgi.framework;
+
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+public class FrameworkUtil
+{
+	public static Filter createFilter(String filter)
+        throws InvalidSyntaxException
+    {
+		return new FilterImpl(filter);
+	}
+}

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/LogWrapper.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/LogWrapper.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/LogWrapper.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/LogWrapper.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,143 @@
+/*
+ *   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.osgi.framework;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * <p>
+ * This class mimics the standard OSGi <tt>LogService</tt> interface. An
+ * instance of this class will be used by the framework for all logging. Currently,
+ * the implementation of this class just sends log messages to standard output,
+ * but in the future it will be modified to use a log service if one is
+ * installed in the framework. To do so, it will need to use reflection to
+ * call the log service methods, since it will not have access to the
+ * <tt>LogService</tt> class.
+ * </p>
+**/
+// TODO: Modify LogWrapper to get LogService service object and invoke with reflection.
+public class LogWrapper
+{
+    public static final int LOG_ERROR = 1;
+    public static final int LOG_WARNING = 2;
+    public static final int LOG_INFO = 3;
+    public static final int LOG_DEBUG = 4;
+
+    private Object m_logObj = null;
+
+    public LogWrapper()
+    {
+    }
+
+    public void log(int level, String msg)
+    {
+        synchronized (this)
+        {
+            if (m_logObj != null)
+            {
+// Will use reflection.
+//                m_logObj.log(level, msg);
+            }
+            else
+            {
+                _log(null, level, msg, null);
+            }
+        }
+    }
+
+    public void log(int level, String msg, Throwable ex)
+    {
+        synchronized (this)
+        {
+            if (m_logObj != null)
+            {
+// Will use reflection.
+//                m_logObj.log(level, msg);
+            }
+            else
+            {
+                _log(null, level, msg, ex);
+            }
+        }
+    }
+
+    public void log(ServiceReference sr, int level, String msg)
+    {
+        synchronized (this)
+        {
+            if (m_logObj != null)
+            {
+// Will use reflection.
+//                m_logObj.log(level, msg);
+            }
+            else
+            {
+                _log(sr, level, msg, null);
+            }
+        }
+    }
+
+    public void log(ServiceReference sr, int level, String msg, Throwable ex)
+    {
+        synchronized (this)
+        {
+            if (m_logObj != null)
+            {
+// Will use reflection.
+//                m_logObj.log(level, msg);
+            }
+            else
+            {
+                _log(sr, level, msg, ex);
+            }
+        }
+    }
+    
+    private void _log(ServiceReference sr, int level, String msg, Throwable ex)
+    {
+        String s = (sr == null) ? null : "SvcRef " + sr;
+        s = (s == null) ? msg : s + " " + msg;
+        s = (ex == null) ? s : s + " (" + ex + ")";
+        switch (level)
+        {
+            case LOG_DEBUG:
+                System.out.println("DEBUG: " + s);
+                break;
+            case LOG_ERROR:
+                System.out.println("ERROR: " + s);
+                if (ex != null)
+                {
+                    if ((ex instanceof BundleException) &&
+                        (((BundleException) ex).getNestedException() != null))
+                    {
+                        ex = ((BundleException) ex).getNestedException();
+                    }
+                    ex.printStackTrace();
+                }
+                break;
+            case LOG_INFO:
+                System.out.println("INFO: " + s);
+                break;
+            case LOG_WARNING:
+                System.out.println("WARNING: " + s);
+                break;
+            default:
+                System.out.println("UNKNOWN[" + level + "]: " + s);
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/Main.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/Main.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/Main.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/Main.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,481 @@
+/*
+ *   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.osgi.framework;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import org.apache.osgi.framework.cache.DefaultBundleCache;
+import org.apache.osgi.framework.util.CaseInsensitiveMap;
+import org.apache.osgi.framework.util.MutablePropertyResolverImpl;
+
+/**
+ * <p>
+ * This class is the default way to instantiate and execute the framework. It is not
+ * intended to be the only way to instantiate and execute the framework; rather, it is
+ * one example of how to do so. When embedding the framework in a host application,
+ * this class can serve as a simple guide of how to do so. It may even be
+ * worthwhile to reuse some of its property handling capabilities. This class
+ * is completely static and is only intended to start a single instance of
+ * the framework.
+ * </p>
+**/
+public class Main
+{
+    /**
+     * The system property name used to specify an URL to the system
+     * property file.
+    **/
+    public static final String SYSTEM_PROPERTIES_PROP = "felix.system.properties";
+    /**
+     * The default name used for the system properties file.
+    **/
+    public static final String SYSTEM_PROPERTIES_FILE_VALUE = "system.properties";
+    /**
+     * The system property name used to specify an URL to the configuration
+     * property file to be used for the created the framework instance.
+    **/
+    public static final String CONFIG_PROPERTIES_PROP = "felix.config.properties";
+    /**
+     * The default name used for the configuration properties file.
+    **/
+    public static final String CONFIG_PROPERTIES_FILE_VALUE = "config.properties";
+
+    private static Felix m_felix = null;
+
+    /**
+     * <p>
+     * This method performs the main task of constructing an framework instance
+     * and starting its execution. The following functions are performed
+     * when invoked:
+     * </p>
+     * <ol>
+     *   <li><i><b>Read the system properties file.<b></i> This is a file
+     *       containing properties to be pushed into <tt>System.setProperty()</tt>
+     *       before starting the framework. This mechanism is mainly shorthand
+     *       for people starting the framework from the command line to avoid having
+     *       to specify a bunch of <tt>-D</tt> system property definitions.
+     *       The only properties defined in this file that will impact the framework's
+     *       behavior are the those concerning setting HTTP proxies, such as
+     *       <tt>http.proxyHost</tt>, <tt>http.proxyPort</tt>, and
+     *       <tt>http.proxyAuth</tt>.
+     *   </li>
+     *   <li><i><b>Perform system property variable substitution on system
+     *       properties.</b></i> Any system properties in the system property
+     *       file whose value adheres to <tt>${&lt;system-prop-name&gt;}</tt>
+     *       syntax will have their value substituted with the appropriate
+     *       system property value.
+     *   </li>
+     *   <li><i><b>Read the framework's configuration property file.</b></i> This is
+     *       a file containing properties used to configure the framework
+     *       instance and to pass configuration information into
+     *       bundles installed into the framework instance. The configuration
+     *       property file is called <tt>config.properties</tt> by default
+     *       and is located in the same directory as the <tt>felix.jar</tt>
+     *       file, which is typically in the <tt>lib/</tt> directory of the
+     *       Felix installation directory. It is possible to use a different
+     *       location for the property file by specifying the desired URL
+     *       using the <tt>felix.config.properties</tt> system property;
+     *       this should be set using the <tt>-D</tt> syntax when executing
+     *       the JVM. Refer to the
+     *       <a href="Felix.html#start(org.apache.osgi.framework.util.MutablePropertyResolver, org.apache.osgi.framework.util.MutablePropertyResolver, java.util.List)">
+     *       <tt>Felix.start()</tt></a> method documentation for more
+     *       information on the framework configuration options.
+     *   </li>
+     *   <li><i><b>Perform system property variable substitution on configuration
+     *       properties.</b></i> Any configuration properties whose value adheres to
+     *       <tt>${&lt;system-prop-name&gt;}</tt> syntax will have their value
+     *       substituted with the appropriate system property value.
+     *   </li>
+     *   <li><i><b>Ensure the default bundle cache has sufficient information to
+     *       initialize.</b></i> The default implementation of the bundle cache
+     *       requires either a profile name or a profile directory in order to
+     *       start. The configuration properties are checked for at least one
+     *       of the <tt>felix.cache.profile</tt> or <tt>felix.cache.profiledir</tt>
+     *       properties. If neither is found, the user is asked to supply a profile
+     *       name that is added to the configuration property set. See the
+     *       <a href="cache/DefaultBundleCache.html"><tt>DefaultBundleCache</tt></a>
+     *       documentation for more details its configuration options.
+     *   </li>
+     *   <li><i><b>Creates and starts a framework instance.</b></i> A simple
+     *       <a href="util/MutablePropertyResolver.html"><tt>MutablePropertyResolver</tt></a>
+     *       is created for the configuration property file and is passed
+     *       into the framework when it is started.
+     *   </li>
+     * </ol>
+     * <p>
+     * It should be noted that simply starting an instance of the framework is not enough
+     * to create an interactive session with it. It is necessary to install
+     * and start bundles that provide an interactive shell; this is generally
+     * done by specifying an "auto-start" property in the framework configuration
+     * property file. If no interactive shell bundles are installed or if
+     * the configuration property file cannot be found, the framework will appear to
+     * be hung or deadlocked. This is not the case, it is executing correctly,
+     * there is just no way to interact with it. Refer to the
+     * <a href="Felix.html#start(org.apache.osgi.framework.util.MutablePropertyResolver, org.apache.osgi.framework.util.MutablePropertyResolver, java.util.List)">
+     * <tt>Felix.start()</tt></a> method documentation for more information on
+     * framework configuration options.
+     * </p>
+     * @param argv An array of arguments, all of which are ignored.
+     * @throws Exception If an error occurs.
+    **/
+    public static void main(String[] argv) throws Exception
+    {
+        // Load system properties.
+        Main.loadSystemProperties();
+
+        // Read configuration properties.
+        Properties configProps = Main.readConfigProperties();
+
+        // See if the profile name property was specified.
+        String profileName = configProps.getProperty(DefaultBundleCache.CACHE_PROFILE_PROP);
+
+        // See if the profile directory property was specified.
+        String profileDirName = configProps.getProperty(DefaultBundleCache.CACHE_PROFILE_DIR_PROP);
+
+        // Print welcome banner.
+        System.out.println("\nWelcome to Felix.");
+        System.out.println("=================\n");
+
+        // If no profile or profile directory is specified in the
+        // properties, then ask for a profile name.
+        if ((profileName == null) && (profileDirName == null))
+        {
+            System.out.print("Enter profile name: ");
+            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+            try
+            {
+                profileName = in.readLine();
+            }
+            catch (IOException ex)
+            {
+                System.err.println("Could not read input.");
+                System.exit(-1);
+            }
+            System.out.println("");
+            if (profileName.length() != 0)
+            {
+                configProps.setProperty(DefaultBundleCache.CACHE_PROFILE_PROP, profileName);
+            }
+        }
+
+        // A profile directory or name must be specified.
+        if ((profileDirName == null) && (profileName.length() == 0))
+        {
+            System.err.println("You must specify a profile name or directory.");
+            System.exit(-1);
+        }
+
+        try
+        {
+            // Now create an instance of the framework.
+            m_felix = new Felix();
+            m_felix.start(
+                new MutablePropertyResolverImpl(new CaseInsensitiveMap(configProps)),
+                null);
+        }
+        catch (Exception ex)
+        {
+            System.err.println("Could not create framework: " + ex);
+            ex.printStackTrace();
+            System.exit(-1);
+        }
+    }
+
+    /**
+     * <p>
+     * Loads the properties in the system property file associated with the
+     * framework installation into <tt>System.setProperty()</tt>. These properties
+     * are not directly used by the framework in anyway. By default, the system property
+     * file is located in the same directory as the <tt>felix.jar</tt> file and
+     * is called "<tt>system.properties</tt>". This may be changed by setting the
+     * "<tt>felix.system.properties</tt>" system property to an
+     * arbitrary URL.
+     * </p>
+    **/
+    public static void loadSystemProperties()
+    {
+        // The system properties file is either specified by a system
+        // property or it is in the same directory as the Felix JAR file.
+        // Try to load it from one of these places.
+
+        // See if the property URL was specified as a property.
+        URL propURL = null;
+        String custom = System.getProperty(SYSTEM_PROPERTIES_PROP);
+        if (custom != null)
+        {
+            try
+            {
+                propURL = new URL(custom);
+            }
+            catch (MalformedURLException ex)
+            {
+                System.err.print("Main: " + ex);
+                return;
+            }
+        }
+        else
+        {
+            // Determine where felix.jar is located by looking at the
+            // system class path.
+            String jarLoc = null;
+            String classpath = System.getProperty("java.class.path");
+            int index = classpath.toLowerCase().indexOf("felix.jar");
+            int start = classpath.lastIndexOf(File.pathSeparator, index) + 1;
+            if (index > start)
+            {
+                jarLoc = classpath.substring(start, index);
+                if (jarLoc.length() == 0)
+                {
+                    jarLoc = ".";
+                }
+            }
+            else
+            {
+                // Can't figure it out so use the current directory as default.
+                jarLoc = System.getProperty("user.dir");
+            }
+
+            try
+            {
+                propURL = new File(jarLoc, SYSTEM_PROPERTIES_FILE_VALUE).toURL();
+            }
+            catch (MalformedURLException ex)
+            {
+                System.err.print("Main: " + ex);
+                return;
+            }
+        }
+
+        // Read the properties file.
+        Properties props = new Properties();
+        InputStream is = null;
+        try
+        {
+            is = propURL.openConnection().getInputStream();
+            props.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex)
+        {
+            // Ignore file not found.
+        }
+        catch (Exception ex)
+        {
+            System.err.println(
+                "Main: Error loading system properties from " + propURL);
+            System.err.println("Main: " + ex);
+            try
+            {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2)
+            {
+                // Nothing we can do.
+            }
+            return;
+        }
+
+        // Perform variable substitution for system properties.
+        for (Enumeration e = props.propertyNames(); e.hasMoreElements(); )
+        {
+            String name = (String) e.nextElement();
+            System.setProperty(name, substVars((String) props.getProperty(name)));
+        }
+    }
+
+    /**
+     * <p>
+     * Reads the configuration properties in the configuration property
+     * file associated with the framework installation; these properties are
+     * only accessible to the framework and are intended for configuration
+     * purposes. By default, the configuration property file is located in
+     * the same directory as the <tt>felix.jar</tt> file and is called
+     * "<tt>config.properties</tt>". This may be changed by setting the
+     * "<tt>felix.config.properties</tt>" system property to an
+     * arbitrary URL.
+     * </p>
+     * @return A <tt>Properties</tt> instance or <tt>null</tt> if there was an error.
+    **/
+    public static Properties readConfigProperties()
+    {
+        // The config properties file is either specified by a system
+        // property or it is in the same directory as the Felix JAR file.
+        // Try to load it from one of these places.
+
+        // See if the property URL was specified as a property.
+        URL propURL = null;
+        String custom = System.getProperty(CONFIG_PROPERTIES_PROP);
+        if (custom != null)
+        {
+            try
+            {
+                propURL = new URL(custom);
+            }
+            catch (MalformedURLException ex)
+            {
+                System.err.print("Main: " + ex);
+                return null;
+            }
+        }
+        else
+        {
+            // Determine where felix.jar is located by looking at the
+            // system class path.
+            String jarLoc = null;
+            String classpath = System.getProperty("java.class.path");
+            int index = classpath.toLowerCase().indexOf("felix.jar");
+            int start = classpath.lastIndexOf(File.pathSeparator, index) + 1;
+            if (index > start)
+            {
+                jarLoc = classpath.substring(start, index);
+                if (jarLoc.length() == 0)
+                {
+                    jarLoc = ".";
+                }
+            }
+            else
+            {
+                // Can't figure it out so use the current directory as default.
+                jarLoc = System.getProperty("user.dir");
+            }
+
+            try
+            {
+                propURL = new File(jarLoc, CONFIG_PROPERTIES_FILE_VALUE).toURL();
+            }
+            catch (MalformedURLException ex)
+            {
+                System.err.print("Main: " + ex);
+                return null;
+            }
+        }
+
+        // Read the properties file.
+        Properties props = new Properties();
+        InputStream is = null;
+        try
+        {
+            is = propURL.openConnection().getInputStream();
+            props.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex)
+        {
+            // Ignore file not found.
+        }
+        catch (Exception ex)
+        {
+            System.err.println(
+                "Error loading config properties from " + propURL);
+            System.err.println("Main: " + ex);
+            try
+            {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2)
+            {
+                // Nothing we can do.
+            }
+            return null;
+        }
+
+        // Perform variable substitution for system properties.
+        for (Enumeration e = props.propertyNames(); e.hasMoreElements(); )
+        {
+            String name = (String) e.nextElement();
+            props.setProperty(name, substVars((String) props.getProperty(name)));
+        }
+
+        return props;
+    }
+
+    private static final String DELIM_START = "${";
+    private static final char DELIM_STOP  = '}';
+    private static final int DELIM_START_LEN = 2;
+    private static final int DELIM_STOP_LEN  = 1;
+
+    /**
+     * <p>
+     * This method performs system property variable substitution on the
+     * specified string value. If the specified string contains the
+     * syntax <tt>${&lt;system-prop-name&gt;}</tt>, then the corresponding
+     * system property value is substituted for the marker.
+     * </p>
+     * @param val The string on which to perform system property substitution.
+     * @return The value of the specified string after system property substitution.
+     * @throws IllegalArgumentException If there was a syntax error in the
+     *         system property variable marker syntax.
+    **/
+    public static String substVars(String val)
+        throws IllegalArgumentException
+    {
+        StringBuffer sbuf = new StringBuffer();
+
+        if (val == null)
+        {
+            return val;
+        }
+
+        int i = 0;
+        int j, k;
+
+        while (true)
+        {
+            j = val.indexOf(DELIM_START, i);
+            if (j == -1)
+            {
+                if (i == 0)
+                {
+                    return val;
+                }
+                else
+                {
+                    sbuf.append(val.substring(i, val.length()));
+                    return sbuf.toString();
+                }
+            }
+            else
+            {
+                sbuf.append(val.substring(i, j));
+                k = val.indexOf(DELIM_STOP, j);
+                if (k == -1)
+                {
+                    throw new IllegalArgumentException(
+                    '"' + val +
+                    "\" has no closing brace. Opening brace at position "
+                    + j + '.');
+                }
+                else
+                {
+                    j += DELIM_START_LEN;
+                    String key = val.substring(j, k);
+                    // Try system properties.
+                    String replacement = System.getProperty(key, null);
+                    if (replacement != null)
+                    {
+                        sbuf.append(replacement);
+                    }
+                    i = k + DELIM_STOP_LEN;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiLibrarySource.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiLibrarySource.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiLibrarySource.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiLibrarySource.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,179 @@
+/*
+ *   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.osgi.framework;
+
+import org.apache.osgi.framework.cache.BundleCache;
+import org.apache.osgi.framework.util.LibraryInfo;
+import org.apache.osgi.moduleloader.LibrarySource;
+import org.osgi.framework.Constants;
+
+public class OSGiLibrarySource implements LibrarySource
+{
+    private LogWrapper m_logger = null;
+    private boolean m_opened = false;
+    private BundleCache m_cache = null;
+    private long m_bundleId = -1;
+    private int m_revision = -1;
+    private String m_os = null;
+    private String m_processor = null;
+    private LibraryInfo[] m_libraries = null;
+
+    public OSGiLibrarySource(
+        LogWrapper logger, BundleCache cache, long bundleId, int revision,
+        String os, String processor, LibraryInfo[] libraries)
+    {
+        m_logger = logger;
+        m_cache = cache;
+        m_bundleId = bundleId;
+        m_revision = revision;
+        m_os = normalizePropertyValue(Constants.FRAMEWORK_OS_NAME, os);
+        m_processor = normalizePropertyValue(Constants.FRAMEWORK_PROCESSOR, processor);
+        m_libraries = libraries;
+    }
+
+    public void open()
+    {
+        m_opened = true;
+    }
+
+    public void close()
+    {
+        m_opened = false;
+    }
+
+    public String getPath(String name) throws IllegalStateException
+    {
+        if (!m_opened)
+        {
+            throw new IllegalStateException("OSGiLibrarySource is not open");
+        }
+
+        if (m_libraries != null)
+        {
+            String libname = System.mapLibraryName(name);
+
+            // Check to see if we have a matching library.
+            // TODO: This "matching" algorithm does not fully
+            // match the spec and should be improved.
+            LibraryInfo library = null;
+            for (int i = 0; (library == null) && (i < m_libraries.length); i++)
+            {
+                boolean osOkay = checkOS(m_libraries[i].getOSNames());
+                boolean procOkay = checkProcessor(m_libraries[i].getProcessors());
+                if (m_libraries[i].getName().endsWith(libname) && osOkay && procOkay)
+                {
+                    library = m_libraries[i];
+                }
+            }
+
+            if (library != null)
+            {
+                try {
+                    return m_cache.getArchive(m_bundleId)
+                        .findLibrary(m_revision, library.getName());
+                } catch (Exception ex) {
+                    m_logger.log(LogWrapper.LOG_ERROR, "OSGiLibrarySource: Error finding library.", ex);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private boolean checkOS(String[] osnames)
+    {
+        for (int i = 0; (osnames != null) && (i < osnames.length); i++)
+        {
+            String osname =
+                normalizePropertyValue(Constants.FRAMEWORK_OS_NAME, osnames[i]);
+            if (m_os.equals(osname))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkProcessor(String[] processors)
+    {
+        for (int i = 0; (processors != null) && (i < processors.length); i++)
+        {
+            String processor =
+                normalizePropertyValue(Constants.FRAMEWORK_PROCESSOR, processors[i]);
+            if (m_processor.equals(processor))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This is simply a hack to try to create some standardized
+     * property values, since there seems to be many possible
+     * values for each JVM implementation.  Currently, this
+     * focuses on Windows and Linux and will certainly need
+     * to be changed in the future or at least edited.
+    **/
+    public static String normalizePropertyValue(String prop, String value)
+    {
+        prop = prop.toLowerCase();
+        value = value.toLowerCase();
+
+        if (prop.equals(Constants.FRAMEWORK_OS_NAME))
+        {
+            if (value.startsWith("linux"))
+            {
+                return "linux";
+            }
+            else if (value.startsWith("win"))
+            {
+                String os = "win";
+                if (value.indexOf("95") >= 0)
+                {
+                    os = "win95";
+                }
+                else if (value.indexOf("98") >= 0)
+                {
+                    os = "win98";
+                }
+                else if (value.indexOf("NT") >= 0)
+                {
+                    os = "winnt";
+                }
+                else if (value.indexOf("2000") >= 0)
+                {
+                    os = "win2000";
+                }
+                else if (value.indexOf("xp") >= 0)
+                {
+                    os = "winxp";
+                }
+                return os;
+            }
+        }
+        else if (prop.equals(Constants.FRAMEWORK_PROCESSOR))
+        {
+            if (value.endsWith("86"))
+            {
+                return "x86";
+            }
+        }
+
+        return value;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiURLPolicy.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiURLPolicy.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiURLPolicy.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/OSGiURLPolicy.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,133 @@
+/*
+ *   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.osgi.framework;
+
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+import org.apache.osgi.framework.util.FelixConstants;
+import org.apache.osgi.moduleloader.*;
+
+public class OSGiURLPolicy implements URLPolicy
+{
+    private Felix m_felix = null;
+    private BundleURLStreamHandler m_handler = null;
+    private FakeURLStreamHandler m_fakeHandler = null;
+
+    public OSGiURLPolicy(Felix felix)
+    {
+        m_felix = felix;
+    }
+
+    public URL createCodeSourceURL(ModuleManager mgr, Module module)
+    {
+        URL url = null;
+/*
+        BundleImpl bundle = null;
+        try
+        {
+            bundle = (BundleImpl)
+                m_felix.getBundle(BundleInfo.getBundleIdFromModuleId(module.getId()));
+            if (bundle != null)
+            {
+                url = new URL(bundle.getInfo().getLocation());
+            }
+        }
+        catch (NumberFormatException ex)
+        {
+            url = null;
+        }
+        catch (MalformedURLException ex)
+        {
+            if (m_fakeHandler == null)
+            {
+                m_fakeHandler = new FakeURLStreamHandler();
+            }
+            try
+            {
+                url = new URL(null,
+                    FelixConstants.FAKE_URL_PROTOCOL_VALUE
+                    + "//" + bundle.getLocation(), m_fakeHandler);
+            }
+            catch (Exception ex2)
+            {
+                url = null;
+            }
+        }
+*/
+        return url;
+    }
+
+    public URL createResourceURL(ModuleManager mgr, Module module, int rsIdx, String name)
+    {
+        if (m_handler == null)
+        {
+            m_handler = new BundleURLStreamHandler(mgr);
+        }
+
+        // Add a slash if there is one already, otherwise
+        // the is no slash separating the host from the file
+        // in the resulting URL.
+        if (!name.startsWith("/"))
+        {
+            name = "/" + name;
+        }
+
+        try
+        {
+            if (System.getSecurityManager() != null)
+            {
+                return (URL) AccessController.doPrivileged(
+                    new CreateURLPrivileged(module.getId(), rsIdx, name));
+            }
+            else
+            {
+                return new URL(FelixConstants.BUNDLE_URL_PROTOCOL,
+                    module.getId(), -1, "/" + rsIdx + name, m_handler);
+            }
+        }
+        catch (Exception ex)
+        {
+            System.err.println("OSGiURLPolicy: " + ex);
+            return null;
+        }
+    }
+
+    /**
+     * This simple class is used to perform the privileged action of
+     * creating a URL using the "bundle:" protocol stream handler.
+    **/
+    private class CreateURLPrivileged implements PrivilegedExceptionAction
+    {
+        private String m_id = null;
+        private int m_rsIdx = 0;
+        private String m_name = null;
+
+        public CreateURLPrivileged(String id, int rsIdx, String name)
+        {
+            m_id = id;
+            m_rsIdx = rsIdx;
+            m_name = name;
+        }
+
+        public Object run() throws Exception
+        {
+            return new URL("bundle", m_id, -1, "/" + m_rsIdx + m_name, m_handler);
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminActivator.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminActivator.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminActivator.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminActivator.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,43 @@
+/*
+ *   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.osgi.framework;
+
+import org.osgi.framework.*;
+
+class PackageAdminActivator implements BundleActivator
+{
+    private Felix m_felix = null;
+    private ServiceRegistration m_reg = null;
+
+    public PackageAdminActivator(Felix felix)
+    {
+        m_felix = felix;
+    }
+
+    public void start(BundleContext context) throws Exception
+    {
+        m_reg = context.registerService(
+            org.osgi.service.packageadmin.PackageAdmin.class.getName(),
+            new PackageAdminImpl(m_felix),
+            null);
+    }
+
+    public void stop(BundleContext context) throws Exception
+    {
+        m_reg.unregister();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/PackageAdminImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,189 @@
+/*
+ *   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.osgi.framework;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.packageadmin.*;
+
+class PackageAdminImpl implements PackageAdmin, Runnable
+{
+    private Felix m_felix = null;
+    private Bundle[][] m_reqBundles = null;
+
+    public PackageAdminImpl(Felix felix)
+    {
+        m_felix = felix;
+
+        // Start a thread to perform asynchronous package refreshes.
+        Thread t = new Thread(this, "FelixPackageAdmin");
+        t.setDaemon(true);
+        t.start();
+    }
+
+    /**
+     * Returns the exported package associated with the specified
+     * package name.
+     *
+     * @param name the name of the exported package to find.
+     * @return the exported package or null if no matching package was found.
+    **/
+    public ExportedPackage getExportedPackage(String name)
+    {
+        return m_felix.getExportedPackage(name);
+    }
+
+    /**
+     * Returns the packages exported by the specified bundle.
+     *
+     * @param bundle the bundle whose exported packages are to be returned.
+     * @return an array of packages exported by the bundle or null if the
+     *         bundle does not export any packages.
+    **/
+    public ExportedPackage[] getExportedPackages(Bundle b)
+    {
+        return m_felix.getExportedPackages(b);
+    }
+
+    /**
+     * The OSGi specification states that refreshing packages is
+     * asynchronous; this method simply notifies the package admin
+     * thread to do a refresh.
+     * @param bundles array of bundles to refresh or <tt>null</tt> to refresh
+     *                any bundles in need of refreshing.
+    **/
+    public synchronized void refreshPackages(Bundle[] bundles)
+        throws SecurityException
+    {
+        // Save our request parameters and notify all.
+        if (m_reqBundles == null)
+        {
+            m_reqBundles = new Bundle[][] { bundles };
+        }
+        else
+        {
+            Bundle[][] newReqBundles = new Bundle[m_reqBundles.length + 1][];
+            System.arraycopy(m_reqBundles, 0,
+                newReqBundles, 0, m_reqBundles.length);
+            newReqBundles[m_reqBundles.length] = bundles;
+            m_reqBundles = newReqBundles;
+        }
+        notifyAll();
+    }
+
+    /**
+     * The OSGi specification states that package refreshes happen
+     * asynchronously; this is the run() method for the package
+     * refreshing thread.
+    **/
+    public void run()
+    {
+        // This thread loops forever, thus it should
+        // be a daemon thread.
+        Bundle[] bundles = null;
+        while (true)
+        {
+            synchronized (this)
+            {
+                // Wait for a refresh request.
+                while (m_reqBundles == null)
+                {
+                    try
+                    {
+                        wait();
+                    }
+                    catch (InterruptedException ex)
+                    {
+                    }
+                }
+
+                // Get the bundles parameter for the current
+                // refresh request.
+                if (m_reqBundles != null)
+                {
+                    bundles = m_reqBundles[0];
+                }
+            }
+
+            // Perform refresh.
+            m_felix.refreshPackages(bundles);
+
+            // Remove the first request since it is now completed.
+            synchronized (this)
+            {
+                if (m_reqBundles.length == 1)
+                {
+                    m_reqBundles = null;
+                }
+                else
+                {
+                    Bundle[][] newReqBundles = new Bundle[m_reqBundles.length - 1][];
+                    System.arraycopy(m_reqBundles, 1,
+                        newReqBundles, 0, m_reqBundles.length - 1);
+                    m_reqBundles = newReqBundles;
+                }
+            }
+        }
+    }
+
+    public ExportedPackage[] getExportedPackages(String name)
+    {
+        // TODO: Implement PackageAdmin.getExportedPackages()
+        return null;
+    }
+
+    public boolean resolveBundles(Bundle[] bundles)
+    {
+        // TODO: Implement PackageAdmin.resolveBundles()
+        return false;
+    }
+
+    public RequiredBundle[] getRequiredBundles(String symbolicName)
+    {
+        // TODO: Implement PackageAdmin.getRequiredBundles()
+        return null;
+    }
+
+    public Bundle[] getBundles(String symbolicName, String versionRange)
+    {
+        // TODO: Implement PackageAdmin.getBundles()
+        return null;
+    }
+
+    public Bundle[] getFragments(Bundle bundle)
+    {
+        // TODO: Implement PackageAdmin.getFragments()
+        return null;
+    }
+
+    public Bundle[] getHosts(Bundle bundle)
+    {
+        // TODO: Implement PackageAdmin.getHosts()
+        return null;
+    }
+
+    public Bundle getBundle(Class clazz)
+    {
+        // TODO: Implement PackageAdmin.getBundle()
+        return null;
+    }
+
+    public int getBundleType(Bundle bundle)
+    {
+        // TODO: Implement PackageAdmin.getBundleType()
+        return 0;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceReferenceImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceReferenceImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceReferenceImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceReferenceImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,175 @@
+/*
+ *   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.osgi.framework;
+
+import org.apache.osgi.framework.searchpolicy.R4SearchPolicy;
+import org.apache.osgi.framework.searchpolicy.R4Wire;
+import org.apache.osgi.framework.util.FelixConstants;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+class ServiceReferenceImpl implements ServiceReference
+{
+    private ServiceRegistrationImpl m_registration = null;
+    private Bundle m_bundle = null;
+
+    public ServiceReferenceImpl(ServiceRegistrationImpl reg, Bundle bundle)
+    {
+        m_registration = reg;
+        m_bundle = bundle;
+    }
+
+    protected ServiceRegistrationImpl getServiceRegistration()
+    {
+        return m_registration;
+    }
+
+    public Object getProperty(String s)
+    {
+        return m_registration.getProperty(s);
+    }
+
+    public String[] getPropertyKeys()
+    {
+        return m_registration.getPropertyKeys();
+    }
+
+    public Bundle getBundle()
+    {
+        return m_bundle;
+    }
+
+    public Bundle[] getUsingBundles()
+    {
+        return m_registration.getUsingBundles();
+    }
+
+    public boolean equals(Object obj)
+    {
+        try
+        {
+            ServiceReferenceImpl ref = (ServiceReferenceImpl) obj;
+            return ref.m_registration == m_registration;
+        }
+        catch (ClassCastException ex)
+        {
+            // Ignore and return false.
+        }
+        catch (NullPointerException ex)
+        {
+            // Ignore and return false.
+        }
+
+        return false;
+    }
+
+    public int hashCode()
+    {
+        if (m_registration.getReference() != null)
+        {
+            if (m_registration.getReference() != this)
+            {
+                return m_registration.getReference().hashCode();
+            }
+            return super.hashCode();
+        }
+        return 0;
+    }
+
+    public String toString()
+    {
+        String[] ocs = (String[]) getProperty("objectClass");
+        String oc = "[";
+        for(int i = 0; i < ocs.length; i++)
+        {
+            oc = oc + ocs[i];
+            if (i < ocs.length - 1)
+                oc = oc + ", ";
+        }
+        oc = oc + "]";
+        return oc;
+    }
+
+    public boolean isAssignableTo(Bundle requester, String className)
+    {
+        // Always return true if the requester is the same as the provider.
+        if (requester == m_bundle)
+        {
+            return true;
+        }
+
+        // Boolean flag.
+        boolean allow = true;
+        // Get the package.
+        String pkgName =
+            org.apache.osgi.moduleloader.Util.getClassPackage(className);
+        // Get package wiring from service provider and requester.
+        R4Wire requesterWire = R4SearchPolicy.getWire(
+            ((BundleImpl) requester).getInfo().getCurrentModule(), pkgName);
+        R4Wire providerWire = R4SearchPolicy.getWire(
+            ((BundleImpl) m_bundle).getInfo().getCurrentModule(), pkgName);
+
+        // There are three situations that may occur here:
+        //   1. The requester does not have a wire for the package.
+        //   2. The provider does not have a wire for the package.
+        //   3. Both have a wire for the package.
+        // For case 1, we do not filter the service reference since we
+        // assume that the bundle is using reflection or that it won't
+        // use that class at all since it does not import it. For
+        // case 2, we have to try to load the class from the class
+        // loader of the service object and then compare the class
+        // loaders to determine if we should filter the service
+        // refernce. In case 3, we simply compare the exporting
+        // modules from the package wiring to determine if we need
+        // to filter the service reference.
+        
+        // Case 1: Always include service reference.
+        if (requesterWire == null)
+        {
+            // This is an intentional no-op.
+        }
+        // Case 2: Only include service reference if the service
+        // object uses the same class as the requester.
+        else if (providerWire == null)
+        {
+            try
+            {
+                // Load the class from the requesting bundle.
+                Class requestClass =
+                    ((BundleImpl) requester).getInfo().getCurrentModule().getClassLoader()
+                        .loadClass(className);
+                // Get the service registration and ask it to check
+                // if the service object is assignable to the requesting
+                // bundle's class.
+                allow = getServiceRegistration().isClassAccessible(requestClass);
+            }
+            catch (Exception ex)
+            {
+                // This should not happen, filter to be safe.
+                allow = false;
+            }
+        }
+        // Case 3: Include service reference if the wires have the
+        // same source module.
+        else
+        {
+            allow = providerWire.m_module.equals(requesterWire.m_module);
+        }
+
+        return allow;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistrationImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistrationImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistrationImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistrationImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,276 @@
+/*
+ *   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.osgi.framework;
+
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.*;
+
+import org.apache.osgi.framework.util.CaseInsensitiveMap;
+import org.osgi.framework.*;
+
+class ServiceRegistrationImpl implements ServiceRegistration
+{
+    // Service registry.
+    private ServiceRegistry m_registry = null;
+    // Bundle implementing the service.
+    private Bundle m_bundle = null;
+    // Interfaces associated with the service object.
+    private String[] m_classes = null;
+    // Service Id associated with the service object.
+    private Long m_serviceId = null;
+    // Service object.
+    private Object m_svcObj = null;
+    // Service factory interface.
+    private ServiceFactory m_factory = null;
+    // Associated property dictionary.
+    private Map m_propMap = null;
+    // Re-usable service reference.
+    private ServiceReferenceImpl m_ref = null;
+
+    public ServiceRegistrationImpl(
+        ServiceRegistry registry, Bundle bundle,
+        String[] classes, Long serviceId,
+        Object svcObj, Dictionary dict)
+    {
+        m_registry = registry;
+        m_bundle = bundle;
+        m_classes = classes;
+        m_serviceId = serviceId;
+        m_svcObj = svcObj;
+        m_factory = (m_svcObj instanceof ServiceFactory)
+            ? (ServiceFactory) m_svcObj : null;
+
+        initializeProperties(dict);
+
+        // This reference is the "standard" reference for this
+        // service and will always be returned by getReference().
+        // Since all reference to this service are supposed to
+        // be equal, we use the hashcode of this reference for
+        // a references to this service in ServiceReference.
+        m_ref = new ServiceReferenceImpl(this, m_bundle);
+    }
+
+    protected boolean isValid()
+    {
+        return (m_svcObj != null);
+    }
+
+    public ServiceReference getReference()
+    {
+        return m_ref;
+    }
+
+    public void setProperties(Dictionary dict)
+    {
+        // Make sure registration is valid.
+        if (!isValid())
+        {
+            throw new IllegalStateException(
+                "The service registration is no longer valid.");
+        }
+        // Set the properties.
+        initializeProperties(dict);
+        // Tell registry about it.
+        m_registry.servicePropertiesModified(this);
+    }
+
+    public void unregister()
+    {
+        m_registry.unregisterService(m_bundle, this);
+        m_svcObj = null;
+        m_factory = null;
+    }
+
+    //
+    // Utility methods.
+    //
+
+    /**
+     * This method determines if the class loader of the service object
+     * has access to the specified class.
+     * @param clazz the class to test for reachability.
+     * @return <tt>true</tt> if the specified class is reachable from the
+     *         service object's class loader, <tt>false</tt> otherwise.
+    **/
+    protected boolean isClassAccessible(Class clazz)
+    {
+        ClassLoader loader = (m_factory != null)
+            ? m_factory.getClass().getClassLoader()
+            : m_svcObj.getClass().getClassLoader();
+        try
+        {
+            Class target = loader.loadClass(clazz.getName());
+            return (target.getClassLoader() == clazz.getClassLoader());
+        }
+        catch (Exception ex)
+        {
+        }
+        return false;
+    }
+
+    protected Object getProperty(String key)
+    {
+        return m_propMap.get(key);
+    }
+
+    private transient ArrayList m_list = new ArrayList();
+
+    protected String[] getPropertyKeys()
+    {
+        synchronized (m_list)
+        {
+            m_list.clear();
+            Iterator i = m_propMap.entrySet().iterator();
+            while (i.hasNext())
+            {
+                Map.Entry entry = (Map.Entry) i.next();
+                m_list.add(entry.getKey());
+            }
+            return (String[]) m_list.toArray(new String[m_list.size()]);
+        }
+    }
+
+    protected Bundle[] getUsingBundles()
+    {
+        return m_registry.getUsingBundles(m_ref);
+    }
+
+    protected Object getService(Bundle acqBundle)
+    {
+        // If the service object is a service factory, then
+        // let it create the service object.
+        if (m_factory != null)
+        {
+            try
+            {
+                if (System.getSecurityManager() != null)
+                {
+                    return AccessController.doPrivileged(
+                        new ServiceFactoryPrivileged(acqBundle, null));
+                }
+                else
+                {
+                    return getFactoryUnchecked(acqBundle);
+                }
+            }
+            catch (Exception ex)
+            {
+                m_registry.getLogger().log(
+                    LogWrapper.LOG_ERROR, "ServiceRegistrationImpl: Error getting service.", ex);
+                return null;
+            }
+        }
+        else
+        {
+            return m_svcObj;
+        }
+    }
+
+    protected void ungetService(Bundle relBundle, Object svcObj)
+    {
+        // If the service object is a service factory, then
+        // let is release the service object.
+        if (m_factory != null)
+        {
+            try
+            {
+                if (System.getSecurityManager() != null)
+                {
+                    AccessController.doPrivileged(
+                        new ServiceFactoryPrivileged(relBundle, svcObj));
+                }
+                else
+                {
+                    ungetFactoryUnchecked(relBundle, svcObj);
+                }
+            }
+            catch (Exception ex)
+            {
+                m_registry.getLogger().log(
+                    LogWrapper.LOG_ERROR, "ServiceRegistrationImpl: Error ungetting service.", ex);
+            }
+        }
+    }
+
+    private void initializeProperties(Dictionary dict)
+    {
+        // Create a case insensitive map.
+        if (m_propMap == null)
+        {
+            m_propMap = new CaseInsensitiveMap();
+        }
+        else
+        {
+            m_propMap.clear();
+        }
+
+        if (dict != null)
+        {
+            Enumeration keys = dict.keys();
+            while (keys.hasMoreElements())
+            {
+                Object key = keys.nextElement();
+                m_propMap.put(key, dict.get(key));
+            }
+        }
+
+        // Add the framework assigned properties.
+        m_propMap.put(Constants.OBJECTCLASS, m_classes);
+        m_propMap.put(Constants.SERVICE_ID, m_serviceId);
+    }
+
+    private Object getFactoryUnchecked(Bundle bundle)
+    {
+        return m_factory.getService(bundle, this);
+    }
+
+    private void ungetFactoryUnchecked(Bundle bundle, Object svcObj)
+    {
+        m_factory.ungetService(bundle, this, svcObj);
+    }
+
+    /**
+     * This simple class is used to ensure that when a service factory
+     * is called, that no other classes on the call stack interferes
+     * with the permissions of the factory itself.
+    **/
+    private class ServiceFactoryPrivileged implements PrivilegedExceptionAction
+    {
+        private Bundle m_bundle = null;
+        private Object m_svcObj = null;
+
+        public ServiceFactoryPrivileged(Bundle bundle, Object svcObj)
+        {
+            m_bundle = bundle;
+            m_svcObj = svcObj;
+        }
+
+        public Object run() throws Exception
+        {
+            if (m_svcObj == null)
+            {
+                return getFactoryUnchecked(m_bundle);
+            }
+            else
+            {
+                ungetFactoryUnchecked(m_bundle, m_svcObj);
+            }
+            return null;
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistry.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistry.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistry.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/ServiceRegistry.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,522 @@
+/*
+ *   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.osgi.framework;
+
+import java.util.*;
+
+import org.apache.osgi.framework.util.FelixConstants;
+import org.osgi.framework.*;
+
+public class ServiceRegistry
+{
+    private LogWrapper m_logger = null;
+    private long m_currentServiceId = 1L;
+    // Maps bundle to an array of service registrations.
+    private Map m_serviceRegsMap = new HashMap();
+    // Maps bundle to an array of usage counts.
+    private Map m_inUseMap = new HashMap();
+
+    private ServiceListener m_serviceListener = null;
+
+    public ServiceRegistry(LogWrapper logger)
+    {
+        m_logger = logger;
+    }
+
+    public synchronized ServiceReference[] getRegisteredServices(Bundle bundle)
+    {
+        ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
+        if (regs != null)
+        {
+            ServiceReference[] refs = new ServiceReference[regs.length];
+            for (int i = 0; i < refs.length; i++)
+            {
+                refs[i] = regs[i].getReference();
+            }
+            return refs;
+        }
+        return null;
+    }
+
+    public ServiceRegistration registerService(
+        Bundle bundle, String[] classNames, Object svcObj, Dictionary dict)
+    {
+        ServiceRegistration reg = null;
+
+        synchronized (this)
+        {
+            // Create the service registration.
+            reg = new ServiceRegistrationImpl(
+                this, bundle, classNames, new Long(m_currentServiceId++), svcObj, dict);
+            // Get the bundles current registered services.
+            ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
+            m_serviceRegsMap.put(bundle, addServiceRegistration(regs, reg));
+        }
+        fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+        return reg;
+    }
+
+    public void unregisterService(Bundle bundle, ServiceRegistration reg)
+    {
+        synchronized (this)
+        {
+            ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
+            m_serviceRegsMap.put(bundle, removeServiceRegistration(regs, reg));
+        }
+        fireServiceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()));
+    }
+
+    public void unregisterServices(Bundle bundle)
+    {
+        // Simply remove all service registrations for the bundle.
+        ServiceRegistration[] regs = null;
+        synchronized (this)
+        {
+            regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
+            m_serviceRegsMap.remove(bundle);
+        }
+
+        // Fire all events outside of synchronized block.
+        for (int i = 0; (regs != null) && (i < regs.length); i++)
+        {
+            fireServiceChanged(
+                new ServiceEvent(ServiceEvent.UNREGISTERING, regs[i].getReference()));
+        }
+    }
+
+    public synchronized List getServiceReferences(String className, Filter filter)
+        throws InvalidSyntaxException
+    {
+        // Create a filtered list of service references.
+        List list = new ArrayList();
+
+        // Iterator over all service registrations.
+        for (Iterator i = m_serviceRegsMap.entrySet().iterator(); i.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry) i.next();
+            ServiceRegistration[] regs = (ServiceRegistration[]) entry.getValue();
+
+            for (int regIdx = 0;
+                (regs != null) && (regIdx < regs.length);
+                regIdx++)
+            {
+                // Determine if the registered services matches
+                // the search criteria.
+                boolean matched = false;
+
+                // If className is null, then look at filter only.
+                if ((className == null) &&
+                    ((filter == null) || filter.match(regs[regIdx].getReference())))
+                {
+                    matched = true;
+                }
+                // If className is not null, then first match the
+                // objectClass property before looking at the
+                // filter.
+                else if (className != null)
+                {
+                    String[] objectClass = (String[])
+                        ((ServiceRegistrationImpl) regs[regIdx]).getProperty(FelixConstants.OBJECTCLASS);
+                    for (int classIdx = 0;
+                        classIdx < objectClass.length;
+                        classIdx++)
+                    {
+                        if (objectClass[classIdx].equals(className) &&
+                            ((filter == null) || filter.match(regs[regIdx].getReference())))
+                        {
+                            matched = true;
+                            break;
+                        }
+                    }
+                }
+
+                // Add reference if it was a match.
+                if (matched)
+                {
+                    list.add(regs[regIdx].getReference());
+                }
+            }
+        }
+
+        return list;
+    }
+
+    public synchronized ServiceReference[] getServicesInUse(Bundle bundle)
+    {
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        if (usages != null)
+        {
+            ServiceReference[] refs = new ServiceReference[usages.length];
+            for (int i = 0; i < refs.length; i++)
+            {
+                refs[i] = usages[i].m_ref;
+            }
+            return refs;
+        }
+        return null;
+    }
+
+    public synchronized Object getService(Bundle bundle, ServiceReference ref)
+    {
+        // Get usage counts for specified bundle.
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+
+        // Make sure the service registration is still valid.
+        if (!((ServiceReferenceImpl) ref).getServiceRegistration().isValid())
+        {
+            // If the service registration is not valid, then this means
+            // that the service provider unregistered the service. The spec
+            // says that calls to get an unregistered service should always
+            // return null (assumption: even if it is currently cached
+            // by the bundle). So in this case, flush the service reference
+            // from the cache and return null.
+            m_inUseMap.put(bundle, removeUsageCount(usages, ref));
+
+            // It is not necessary to unget the service object from
+            // the providing bundle, since the associated service is
+            // unregistered and hence not in the list of registered services
+            // of the providing bundle. This is precisely why the service
+            // registration was not found above in the first place.
+            return null;
+        }
+
+        // Get the service registration.
+        ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+
+        // Get the usage count, if any.
+        UsageCount usage = getUsageCount(usages, ref);
+       
+        // If the service object is cached, then increase the usage
+        // count and return the cached service object.
+        Object svcObj = null;
+        if (usage != null)
+        {
+            usage.m_count++;
+            svcObj = usage.m_svcObj;
+        }
+        else
+        {
+            // Get service object from service registration.
+            svcObj = reg.getService(bundle);
+
+            // Cache the service object.
+            if (svcObj != null)
+            {
+                m_inUseMap.put(bundle, addUsageCount(usages, ref, svcObj));
+            }
+        }
+
+        return svcObj;
+    }
+
+    public synchronized boolean ungetService(Bundle bundle, ServiceReference ref)
+    {
+        // Get usage count.
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        UsageCount usage = getUsageCount(usages, ref);
+
+        // If no usage count, then return.
+        if (usage == null)
+        {
+            return false;
+        }
+
+        // Make sure the service registration is still valid.
+        if (!((ServiceReferenceImpl) ref).getServiceRegistration().isValid())
+        {
+            // If the service registration is not valid, then this means
+            // that the service provider unregistered the service. The spec
+            // says that calls to get an unregistered service should always
+            // return null (assumption: even if it is currently cached
+            // by the bundle). So in this case, flush the service reference
+            // from the cache and return null.
+            m_inUseMap.put(bundle, removeUsageCount(usages, ref));
+            return false;
+        }
+
+        // Decrement usage count.
+        usage.m_count--;
+
+        // Remove reference when usage count goes to zero
+        // and unget the service object from the exporting
+        // bundle.
+        if (usage.m_count == 0)
+        {
+            m_inUseMap.put(bundle, removeUsageCount(usages, ref));
+            ServiceRegistrationImpl reg =
+                ((ServiceReferenceImpl) ref).getServiceRegistration();
+            reg.ungetService(bundle, usage.m_svcObj);
+            usage.m_svcObj = null;
+        }
+
+        // Return true if the usage count is greater than zero.
+        return (usage.m_count > 0);
+    }
+
+
+    /**
+     * This is a utility method to release all services being
+     * used by the specified bundle.
+     * @param bundle the bundle whose services are to be released.
+    **/
+    public synchronized void ungetServices(Bundle bundle)
+    {
+        UsageCount[] usages = (UsageCount[]) m_inUseMap.get(bundle);
+        if (usages == null)
+        {
+            return;
+        }
+
+        // Remove each service object from the
+        // service cache.
+        for (int i = 0; i < usages.length; i++)
+        {
+            // Keep ungetting until all usage count is zero.
+            while (ungetService(bundle, usages[i].m_ref))
+            {
+                // Empty loop body.
+            }
+        }
+    }
+
+    public synchronized Bundle[] getUsingBundles(ServiceReference ref)
+    {
+        Bundle[] bundles = null;
+        for (Iterator iter = m_inUseMap.entrySet().iterator(); iter.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            Bundle bundle = (Bundle) entry.getKey();
+            UsageCount[] usages = (UsageCount[]) entry.getValue();
+            for (int useIdx = 0; useIdx < usages.length; useIdx++)
+            {
+                if (usages[useIdx].m_ref.equals(ref))
+                {
+                    // Add the bundle to the array to be returned.
+                    if (bundles == null)
+                    {
+                        bundles = new Bundle[] { bundle };
+                    }
+                    else
+                    {
+                        Bundle[] nbs = new Bundle[bundles.length + 1];
+                        System.arraycopy(bundles, 0, nbs, 0, bundles.length);
+                        nbs[bundles.length] = bundle;
+                        bundles = nbs;
+                    }
+                }
+            }
+        }
+        return bundles;
+    }
+
+    public void servicePropertiesModified(ServiceRegistration reg)
+    {
+        fireServiceChanged(new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()));
+    }
+
+    public LogWrapper getLogger()
+    {
+        return m_logger;
+    }
+
+    private static ServiceRegistration[] addServiceRegistration(
+        ServiceRegistration[] regs, ServiceRegistration reg)
+    {
+        if (regs == null)
+        {
+            regs = new ServiceRegistration[] { reg };
+        }
+        else
+        {
+            ServiceRegistration[] newRegs = new ServiceRegistration[regs.length + 1];
+            System.arraycopy(regs, 0, newRegs, 0, regs.length);
+            newRegs[regs.length] = reg;
+            regs = newRegs;
+        }
+        return regs;
+    }
+
+    private static ServiceRegistration[] removeServiceRegistration(
+        ServiceRegistration[] regs, ServiceRegistration reg)
+    {
+        for (int i = 0; (regs != null) && (i < regs.length); i++)
+        {
+            if (regs[i].equals(reg))
+            {
+                // If this is the only usage, then point to empty list.
+                if ((regs.length - 1) == 0)
+                {
+                    regs = new ServiceRegistration[0];
+                }
+                // Otherwise, we need to do some array copying.
+                else
+                {
+                    ServiceRegistration[] newRegs = new ServiceRegistration[regs.length - 1];
+                    System.arraycopy(regs, 0, newRegs, 0, i);
+                    if (i < newRegs.length)
+                    {
+                        System.arraycopy(
+                            regs, i + 1, newRegs, i, newRegs.length - i);
+                    }
+                    regs = newRegs;
+                }
+            }
+        }      
+        return regs;
+    }
+
+    public synchronized void addServiceListener(ServiceListener l)
+    {
+        m_serviceListener = ServiceListenerMulticaster.add(m_serviceListener, l);
+    }
+
+    public synchronized void removeServiceListener(ServiceListener l)
+    {
+        m_serviceListener = ServiceListenerMulticaster.remove(m_serviceListener, l);
+    }
+
+    protected void fireServiceChanged(ServiceEvent event)
+    {
+        // Grab a copy of the listener list.
+        ServiceListener listener = m_serviceListener;
+        // If not null, then dispatch event.
+        if (listener != null)
+        {
+            m_serviceListener.serviceChanged(event);
+        }
+    }
+
+    private static class ServiceListenerMulticaster implements ServiceListener
+    {
+        protected ServiceListener m_a = null, m_b = null;
+
+        protected ServiceListenerMulticaster(ServiceListener a, ServiceListener b)    
+        {        
+            m_a = a;        
+            m_b = b;    
+        }    
+    
+        public void serviceChanged(ServiceEvent e)    
+        {
+            m_a.serviceChanged(e);
+            m_b.serviceChanged(e);
+        }
+    
+        public static ServiceListener add(ServiceListener a, ServiceListener b)
+        {
+            if (a == null)
+            {
+                return b;
+            }
+            else if (b == null)
+            {
+                return a;
+            }
+            else
+            {
+                return new ServiceListenerMulticaster(a, b);
+            }
+        }
+    
+        public static ServiceListener remove(ServiceListener a, ServiceListener b)
+        {
+            if ((a == null) || (a == b))
+            {
+                return null;
+            }
+            else if (a instanceof ServiceListenerMulticaster)
+            {
+                return add(
+                    remove(((ServiceListenerMulticaster) a).m_a, b),
+                    remove(((ServiceListenerMulticaster) a).m_b, b));
+            }
+            else
+            {
+                return a;
+            }
+        }
+    }
+
+    private static UsageCount getUsageCount(UsageCount[] usages, ServiceReference ref)
+    {
+        for (int i = 0; (usages != null) && (i < usages.length); i++)
+        {
+            if (usages[i].m_ref.equals(ref))
+            {
+                return usages[i];
+            }
+        }
+        return null;
+    }
+
+    private static UsageCount[] addUsageCount(UsageCount[] usages, ServiceReference ref, Object svcObj)
+    {
+        UsageCount usage = new UsageCount();
+        usage.m_ref = ref;
+        usage.m_svcObj = svcObj;
+        usage.m_count++;
+
+        if (usages == null)
+        {
+            usages = new UsageCount[] { usage };
+        }
+        else
+        {
+            UsageCount[] newUsages = new UsageCount[usages.length + 1];
+            System.arraycopy(usages, 0, newUsages, 0, usages.length);
+            newUsages[usages.length] = usage;
+            usages = newUsages;
+        }
+        return usages;
+    }
+
+    private static UsageCount[] removeUsageCount(UsageCount[] usages, ServiceReference ref)
+    {
+        for (int i = 0; (usages != null) && (i < usages.length); i++)
+        {
+            if (usages[i].m_ref.equals(ref))
+            {
+                // If this is the only usage, then point to empty list.
+                if ((usages.length - 1) == 0)
+                {
+                    usages = new UsageCount[0];
+                }
+                // Otherwise, we need to do some array copying.
+                else
+                {
+                    UsageCount[] newUsages= new UsageCount[usages.length - 1];
+                    System.arraycopy(usages, 0, newUsages, 0, i);
+                    if (i < newUsages.length)
+                    {
+                        System.arraycopy(
+                            usages, i + 1, newUsages, i, newUsages.length - i);
+                    }
+                    usages = newUsages;
+                }
+            }
+        }
+        
+        return usages;
+    }
+
+    private static class UsageCount
+    {
+        public int m_count = 0;
+        public ServiceReference m_ref = null;
+        public Object m_svcObj = null;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelActivator.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelActivator.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelActivator.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelActivator.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,43 @@
+/*
+ *   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.osgi.framework;
+
+import org.osgi.framework.*;
+
+class StartLevelActivator implements BundleActivator
+{
+    private Felix m_felix = null;
+    private ServiceRegistration m_reg = null;
+
+    public StartLevelActivator(Felix felix)
+    {
+        m_felix = felix;
+    }
+
+    public void start(BundleContext context) throws Exception
+    {
+        m_reg = context.registerService(
+            org.osgi.service.startlevel.StartLevel.class.getName(),
+            new StartLevelImpl(m_felix),
+            null);
+    }
+
+    public void stop(BundleContext context) throws Exception
+    {
+        m_reg.unregister();
+    }
+}