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 [8/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/StartLevelImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/StartLevelImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,147 @@
+/*
+ *   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.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.AdminPermission;
+import org.osgi.framework.Bundle;
+import org.osgi.service.startlevel.StartLevel;
+
+/**
+ * @author rickhall
+ *
+ * To change the template for this generated type comment go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+**/
+public class StartLevelImpl implements StartLevel, Runnable
+{
+    private Felix m_felix = null;
+    private List m_requestList = null;
+    // Reusable admin permission.
+    private static AdminPermission m_adminPerm = new AdminPermission();
+    
+    public StartLevelImpl(Felix felix)
+    {
+        m_felix = felix;
+        m_requestList = new ArrayList();
+
+        // Start a thread to perform asynchronous package refreshes.
+        Thread t = new Thread(this, "FelixStartLevel");
+        t.setDaemon(true);
+        t.start();
+    }
+    
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#getStartLevel()
+    **/
+    public int getStartLevel()
+    {
+        return m_felix.getStartLevel();
+    }
+
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#setStartLevel(int)
+    **/
+    public void setStartLevel(int startlevel)
+    {
+        if (System.getSecurityManager() != null)
+        {
+            AccessController.checkPermission(m_adminPerm);
+        }
+        else if (startlevel <= 0)
+        {
+            throw new IllegalArgumentException(
+                "Start level must be greater than zero.");
+        }
+        synchronized (m_requestList)
+        {
+            m_requestList.add(new Integer(startlevel));
+            m_requestList.notifyAll();
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#getBundleStartLevel(org.osgi.framework.Bundle)
+    **/
+    public int getBundleStartLevel(Bundle bundle)
+    {
+        return m_felix.getBundleStartLevel(bundle);
+    }
+
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#setBundleStartLevel(org.osgi.framework.Bundle, int)
+    **/
+    public void setBundleStartLevel(Bundle bundle, int startlevel)
+    {
+        m_felix.setBundleStartLevel(bundle, startlevel);
+    }
+
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#getInitialBundleStartLevel()
+    **/
+    public int getInitialBundleStartLevel()
+    {
+        return m_felix.getInitialBundleStartLevel();
+    }
+
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#setInitialBundleStartLevel(int)
+    **/
+    public void setInitialBundleStartLevel(int startlevel)
+    {
+        m_felix.setInitialBundleStartLevel(startlevel);
+    }
+
+    /* (non-Javadoc)
+     * @see org.osgi.service.startlevel.StartLevel#isBundlePersistentlyStarted(org.osgi.framework.Bundle)
+    **/
+    public boolean isBundlePersistentlyStarted(Bundle bundle)
+    {
+        return m_felix.isBundlePersistentlyStarted(bundle);
+    }
+
+    public void run()
+    {
+        int startLevel = 0;
+
+        // This thread loops forever, thus it should
+        // be a daemon thread.
+        while (true)
+        {
+            synchronized (m_requestList)
+            {
+                // Wait for a request.
+                while (m_requestList.size() == 0)
+                {
+                    try {
+                        m_requestList.wait();
+                    } catch (InterruptedException ex) {
+                    }
+                }
+                
+                // Get the requested start level.
+                startLevel = ((Integer) m_requestList.remove(0)).intValue();
+            }
+
+            // Set the new start level.
+            m_felix.setFrameworkStartLevel(startLevel);
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundle.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundle.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundle.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundle.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,277 @@
+/*
+ *   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.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+
+import org.apache.osgi.framework.searchpolicy.*;
+import org.apache.osgi.framework.util.CaseInsensitiveMap;
+import org.apache.osgi.framework.util.FelixConstants;
+import org.apache.osgi.moduleloader.LibrarySource;
+import org.apache.osgi.moduleloader.ResourceSource;
+import org.osgi.framework.*;
+
+
+class SystemBundle extends BundleImpl
+{
+    private List m_activatorList = null;
+    private BundleActivator m_activator = null;
+    private Thread m_shutdownThread = null;
+    private Object[][] m_attributes = null;
+    private ResourceSource[] m_resSources = null;
+    private LibrarySource[] m_libSources = null;
+
+    protected SystemBundle(Felix felix, BundleInfo info, List activatorList)
+        throws BundleException
+    {
+        super(felix, info);
+
+        // Create an activator list if necessary.
+        if (activatorList == null)
+        {
+            activatorList = new ArrayList();
+        }
+
+        // Add the bundle activator for the package admin service.
+        activatorList.add(new PackageAdminActivator(felix));
+
+        // Add the bundle activator for the start level service.
+        activatorList.add(new StartLevelActivator(felix));
+
+        m_activatorList = activatorList;
+
+        // The system bundle exports framework packages as well as
+        // arbitrary user-defined packages from the system class path.
+        // We must construct the system bundle's export metadata.
+
+        // Get system property that specifies which class path
+        // packages should be exported by the system bundle.
+        R4Package[] classPathPkgs = null;
+        try
+        {
+            classPathPkgs = R4Package.parseImportOrExportHeader(
+                getFelix().getConfig().get(FelixConstants.FRAMEWORK_SYSTEMPACKAGES));
+        }
+        catch (Exception ex)
+        {
+            getFelix().getLogger().log(
+                LogWrapper.LOG_ERROR,
+                "Error parsing system bundle export statement.", ex);
+        }
+
+        // Now, create the list of standard framework exports for
+        // the system bundle.
+        R4Package[] exports = new R4Package[classPathPkgs.length + 3];
+
+        exports[0] = new R4Package(
+            "org.osgi.framework",
+            new R4Directive[0],
+            new R4Attribute[] { new R4Attribute("version", "1.2.0", false) });
+
+        exports[1] = new R4Package(
+            "org.osgi.service.packageadmin",
+            new R4Directive[0],
+            new R4Attribute[] { new R4Attribute("version", "1.2.0", false) });
+
+        exports[2] = new R4Package(
+            "org.osgi.service.startlevel",
+            new R4Directive[0],
+            new R4Attribute[] { new R4Attribute("version", "1.0.0", false) });
+
+        // Copy the class path exported packages.
+        System.arraycopy(classPathPkgs, 0, exports, 3, classPathPkgs.length);
+
+        m_attributes = new Object[][] {
+            new Object[] { R4SearchPolicy.EXPORTS_ATTR, exports },
+            new Object[] { R4SearchPolicy.IMPORTS_ATTR, new R4Package[0] }
+        };
+
+        m_resSources = new ResourceSource[0];
+
+        m_libSources = null;
+
+        String exportString = "";
+        for (int i = 0; i < exports.length; i++)
+        {
+            exportString = exportString +
+            exports[i].getId()
+            + "; specification-version=\""
+            + exports[i].getVersionLow().toString() + "\"";
+
+            if (i < (exports.length - 1))
+            {
+                exportString = exportString + ", ";
+                exportString = exportString +
+                    exports[i].getId()
+                    + "; specification-version=\""
+                    + exports[i].getVersionLow().toString() + "\", ";
+            }
+        }
+
+        // Initialize header map as a case insensitive map.
+        Map map = new CaseInsensitiveMap();
+        map.put(FelixConstants.BUNDLE_VERSION, FelixConstants.FELIX_VERSION_VALUE);
+        map.put(FelixConstants.BUNDLE_NAME, "System Bundle");
+        map.put(FelixConstants.BUNDLE_DESCRIPTION,
+            "This bundle is system specific; it implements various system services.");
+        map.put(FelixConstants.EXPORT_PACKAGE, exportString);
+        ((SystemBundleArchive) getInfo().getArchive()).setManifestHeader(map);
+    }
+
+    public Object[][] getAttributes()
+    {
+        return m_attributes;
+    }
+
+    public ResourceSource[] getResourceSources()
+    {
+        return m_resSources;
+    }
+
+    public LibrarySource[] getLibrarySources()
+    {
+        return m_libSources;
+    }
+
+    public synchronized void start() throws BundleException
+    {
+        // The system bundle is only started once and it
+        // is started by the framework.
+        if (getState() == Bundle.ACTIVE)
+        {
+            throw new BundleException("Cannot start the system bundle.");
+        }
+
+        getInfo().setState(Bundle.STARTING);
+
+        try {
+            getInfo().setContext(new BundleContextImpl(getFelix(), this));
+            getActivator().start(getInfo().getContext());
+        } catch (Throwable throwable) {
+throwable.printStackTrace();
+            throw new BundleException(
+                "Unable to start system bundle.", throwable);
+        }
+
+        // Do NOT set the system bundle state to active yet, this
+        // must be done after all other bundles have been restarted.
+        // This will be done after the framework is initialized.
+    }
+
+    public synchronized void stop() throws BundleException
+    {
+        if (System.getSecurityManager() != null)
+        {
+            AccessController.checkPermission(new AdminPermission());
+        }
+
+        // Spec says stop() on SystemBundle should return immediately and
+        // shutdown framework on another thread.
+        if (getFelix().getStatus() == Felix.RUNNING_STATUS)
+        {
+            // Initial call of stop, so kick off shutdown.
+            m_shutdownThread = new Thread("FelixShutdown") {
+                public void run()
+                {
+                    try
+                    {
+                        getFelix().shutdown();
+                    }
+                    catch (Exception ex)
+                    {
+                        getFelix().getLogger().log(
+                            LogWrapper.LOG_ERROR,
+                            "SystemBundle: Error while shutting down.", ex);
+                    }
+
+                    // Only shutdown the JVM if the framework is running stand-alone.
+                    String embedded = getFelix().getConfig()
+                        .get(FelixConstants.EMBEDDED_EXECUTION_PROP);
+                    boolean isEmbedded = (embedded == null)
+                        ? false : embedded.equals("true");
+                    if (!isEmbedded)
+                    {
+                        if (System.getSecurityManager() != null)
+                        {
+                            AccessController.doPrivileged(new PrivilegedAction() {
+                                public Object run()
+                                {
+                                    System.exit(0);
+                                    return null;
+                                }
+                            });
+                        }
+                        else
+                        {
+                            System.exit(0);
+                        }
+                    }
+                }
+            };
+            getInfo().setState(Bundle.STOPPING);
+            m_shutdownThread.start();
+        }
+        else if ((getFelix().getStatus() == Felix.STOPPING_STATUS) &&
+                 (Thread.currentThread() == m_shutdownThread))
+        {
+            // Callback from shutdown thread, so do our own stop.
+            try
+            {
+                getActivator().stop(getInfo().getContext());
+            }
+            catch (Throwable throwable)
+            {
+                throw new BundleException(
+                        "Unable to stop system bundle.", throwable);
+            }
+        }
+    }
+
+    public synchronized void uninstall() throws BundleException
+    {
+        throw new BundleException("Cannot uninstall the system bundle.");
+    }
+
+    public synchronized void update() throws BundleException
+    {
+        update(null);
+    }
+
+    public synchronized void update(InputStream is) throws BundleException
+    {
+        if (System.getSecurityManager() != null)
+        {
+            AccessController.checkPermission(new AdminPermission());
+        }
+
+        // TODO: This is supposed to stop and then restart the framework.
+        throw new BundleException("System bundle update not implemented yet.");
+    }
+
+    protected BundleActivator getActivator()
+        throws Exception
+    {
+        if (m_activator == null)
+        {
+            m_activator = new SystemBundleActivator(getFelix(), m_activatorList);
+        }
+        return m_activator;
+    }
+}

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleActivator.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleActivator.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleActivator.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleActivator.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,61 @@
+/*
+ *   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.List;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+class SystemBundleActivator implements BundleActivator
+{
+    private Felix m_felix = null;
+    private List m_activatorList = null;
+    private BundleContext m_context = null;
+
+    SystemBundleActivator(Felix felix, List activatorList)
+    {
+        this.m_felix = felix;
+        this.m_activatorList = activatorList;
+    }
+
+    public void start(BundleContext context) throws Exception
+    {
+        this.m_context = context;
+
+        // Start all activators.
+        if (m_activatorList != null)
+        {
+            for (int i = 0; i < m_activatorList.size(); i++)
+            {
+                ((BundleActivator) m_activatorList.get(i)).start(context);
+            }
+        }
+    }
+
+    public void stop(BundleContext context) throws Exception
+    {
+        if (m_activatorList != null)
+        {
+            // Stop all activators.
+            for (int i = 0; i < m_activatorList.size(); i++)
+            {
+                ((BundleActivator) m_activatorList.get(i)).stop(context);
+            }
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleArchive.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleArchive.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleArchive.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/SystemBundleArchive.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,109 @@
+/*
+ *   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.File;
+import java.util.Map;
+
+import org.apache.osgi.framework.cache.BundleArchive;
+import org.apache.osgi.framework.util.FelixConstants;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+
+public class SystemBundleArchive implements BundleArchive
+{
+    private Map m_headerMap = null;
+
+    public long getId()
+    {
+        return 0;
+    }
+    
+    public String getLocation()
+        throws Exception
+    {
+        return FelixConstants.SYSTEM_BUNDLE_LOCATION;
+    }
+
+    public int getPersistentState()
+        throws Exception
+    {
+        return Bundle.ACTIVE;
+    }
+
+    public void setPersistentState(int state)
+        throws Exception
+    {
+    }
+
+    public int getStartLevel()
+        throws Exception
+    {
+        return FelixConstants.SYSTEMBUNDLE_DEFAULT_STARTLEVEL;
+    }
+
+    public void setStartLevel(int level)
+        throws Exception
+    {
+    }
+
+    public File getDataFile(String fileName)
+        throws Exception
+    {
+        return null;
+    }
+
+    public BundleActivator getActivator(ClassLoader loader)
+        throws Exception
+    {
+        return null;
+    }
+
+    public void setActivator(Object obj)
+        throws Exception
+    {
+    }
+
+    public int getRevisionCount()
+        throws Exception
+    {
+        return 1;
+    }
+
+    public Map getManifestHeader(int revision)
+        throws Exception
+    {
+        return m_headerMap;
+    }
+    
+    protected void setManifestHeader(Map headerMap)
+    {
+        m_headerMap = headerMap;
+    }
+
+    public String[] getClassPath(int revision)
+        throws Exception
+    {
+        return null;
+    }
+
+    public String findLibrary(int revision, String libName)
+        throws Exception
+    {
+        return null;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleArchive.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleArchive.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleArchive.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleArchive.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,194 @@
+/*
+ *   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.cache;
+
+import java.io.File;
+import java.util.Map;
+
+import org.osgi.framework.BundleActivator;
+
+/**
+ * <p>
+ * This interface represents an individual cached bundle in the
+ * bundle cache. Felix uses this interface to access all information
+ * about the associated bundle's cached information. Classes that implement
+ * this interface will be related to a specific implementation of the
+ * <tt>BundleCache</tt> interface.
+ * </p>
+ * @see org.apache.osgi.framework.BundleCache
+**/
+public interface BundleArchive
+{
+    /**
+     * <p>
+     * Returns the identifier of the bundle associated with this archive.
+     * </p>
+     * @return the identifier of the bundle associated with this archive.
+    **/
+    public long getId();
+    
+    /**
+     * <p>
+     * Returns the location string of the bundle associated with this archive.
+     * </p>
+     * @return the location string of the bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public String getLocation()
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the persistent state of the bundle associated with the archive;
+     * this value will be either <tt>Bundle.INSTALLED</tt> or <tt>Bundle.ACTIVE</tt>.
+     * </p>
+     * @return the persistent state of the bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public int getPersistentState()
+        throws Exception;
+
+    /**
+     * <p>
+     * Sets the persistent state of the bundle associated with this archive;
+     * this value will be either <tt>Bundle.INSTALLED</tt> or <tt>Bundle.ACTIVE</tt>.
+     * </p>
+     * @param state the new bundle state to write to the archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public void setPersistentState(int state)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the start level of the bundle associated with this archive.
+     * </p>
+     * @return the start level of the bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public int getStartLevel()
+        throws Exception;
+
+    /**
+     * <p>
+     * Sets the start level of the bundle associated with this archive.
+     * </p>
+     * @param level the new bundle start level to write to the archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public void setStartLevel(int level)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns an appropriate data file for the bundle associated with the
+     * archive using the supplied file name.
+     * </p>
+     * @return a <tt>File</tt> corresponding to the requested data file for
+     *         the bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public File getDataFile(String fileName)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the persistent bundle activator of the bundle associated with
+     * this archive; this is a non-standard OSGi method that is only called
+     * when Felix is running in non-strict OSGi mode.
+     * </p>
+     * @param loader the class loader to use when trying to instantiate
+     *        the bundle activator.
+     * @return the persistent bundle activator of the bundle associated with
+     *         this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public BundleActivator getActivator(ClassLoader loader)
+        throws Exception;
+
+    /**
+     * <p>
+     * Sets the persistent bundle activator of the bundle associated with
+     * this archive; this is a non-standard OSGi method that is only called
+     * when Felix is running in non-strict OSGi mode.
+     * </p>
+     * @param obj the new persistent bundle activator to write to the archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public void setActivator(Object obj)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the number of revisions of the bundle associated with the
+     * archive. When a bundle is updated, the previous version of the bundle
+     * is maintained along with the new revision until old revisions are
+     * purged. The revision count reflects how many revisions of the bundle
+     * are currently available in the cache.
+     * </p>
+     * @return the number of revisions of the bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public int getRevisionCount()
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the main attributes of the JAR file manifest header of the
+     * specified revision of the bundle associated with this archive. The
+     * returned map should be case insensitive.
+     * </p>
+     * @param revision the specified revision.
+     * @return the case-insensitive JAR file manifest header of the specified
+     *         revision of the bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public Map getManifestHeader(int revision)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns an array of <tt>String</tt>s that represent the class path of
+     * the specified revision of the bundle associated with this archive.
+     * Currently, these values are restricted to absolute paths in the file
+     * system, but this may be lifted in the future (perhaps they should be
+     * <tt>ResourceSource</tt>s from the Module Loader.
+     * </p>
+     * @param revision the specified revision.
+     * @return a <tt>String</tt> array of the absolute path names that
+     *         comprise the class path of the specified revision of the
+     *         bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public String[] getClassPath(int revision)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the absolute file path for the specified native library of the
+     * specified revision of the bundle associated with this archive.
+     * </p>
+     * @param revision the specified revision.
+     * @param libName the name of the library.
+     * @return a <tt>String</tt> that contains the absolute path name to
+     *         the requested native library of the specified revision of the
+     *         bundle associated with this archive.
+     * @throws java.lang.Exception if any error occurs.
+    **/
+    public String findLibrary(int revision, String libName)
+        throws Exception;
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleCache.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleCache.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleCache.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/cache/BundleCache.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,148 @@
+/*
+ *   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.cache;
+
+import java.io.InputStream;
+
+import org.apache.osgi.framework.LogWrapper;
+import org.apache.osgi.framework.util.PropertyResolver;
+
+/**
+ * <p>
+ * This interface represents the storage mechanism that Felix uses for
+ * caching bundles. It is possible for multiple implementations of
+ * this interface to exist for different storage technologies, such as the
+ * file system, memory, or a database. Felix includes a default implementation
+ * of this interface that uses the file system. Felix allows you to specify
+ * alternative implementations to use by specifying a class name via the
+ * <tt>felix.cache.class</tt> system property. Bundle cache implemenations
+ * should implement this interface and provide a default constructor.
+ * </p>
+ * @see org.apache.osgi.framework.BundleArchive
+**/
+public interface BundleCache
+{
+    /**
+     * <p>
+     * This method is called before using the BundleCache implementation
+     * to initialize it and to pass it a reference to its associated
+     * configuration property resolver and logger. The <tt>BundleCache</tt>
+     * implementation should not use <tt>System.getProperty()</tt> directly
+     * for configuration properties, it should use the property resolver
+     * instance passed into this method. The property resolver
+     * provides access to properties passed into the Felix instance's
+     * constructor. This approach allows multiple instances of Felix to
+     * exist in memory at the same time, but for
+     * them to be configured differently. For example, an application may
+     * want two instances of Felix, where each instance stores their cache
+     * in a different location in the file system. When using multiple
+     * instances of Felix in memory at the same time, system properties
+     * should be avoided and all properties should be passed in to Felix's
+     * constructor.
+     * </p>
+     * @param cfg the property resolver for obtaining configuration properties.
+     * @param logger the logger to use for reporting errors.
+     * @throws Exception if any error occurs.
+    **/
+    public void initialize(PropertyResolver cfg, LogWrapper logger)
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns all cached bundle archives.
+     * </p>
+     * @return an array of all cached bundle archives.
+     * @throws Exception if any error occurs.
+    **/
+    public BundleArchive[] getArchives()
+        throws Exception;
+
+    /**
+     * <p>
+     * Returns the bundle archive associated with the specified
+     * bundle indentifier.
+     * </p>
+     * @param id the identifier of the bundle archive to retrieve.
+     * @return the bundle archive assocaited with the specified bundle identifier.
+     * @throws Exception if any error occurs.
+    **/
+    public BundleArchive getArchive(long id)
+        throws Exception;
+
+    /**
+     * <p>
+     * Creates a new bundle archive for the specified bundle
+     * identifier using the supplied location string and input stream. The
+     * contents of the bundle JAR file should be read from the supplied
+     * input stream, which will not be <tt>null</tt>. The input stream is
+     * closed by the caller; the implementation is only responsible for
+     * closing streams it opens. If this method completes successfully, then
+     * it means that the initial bundle revision of the specified bundle was
+     * successfully cached.
+     * </p>
+     * @param id the identifier of the bundle associated with the new archive.
+     * @param location the location of the bundle associated with the new archive.
+     * @param is the input stream to the bundle's JAR file.
+     * @return the created bundle archive.
+     * @throws Exception if any error occurs.
+    **/
+    public BundleArchive create(long id, String location, InputStream is)
+        throws Exception;
+
+    /**
+     * <p>
+     * Saves an updated revision of the specified bundle to
+     * the bundle cache using the supplied input stream. The contents of the
+     * updated bundle JAR file should be read from the supplied input stream,
+     * which will not be <tt>null</tt>. The input stream is closed by the
+     * caller; the implementation is only responsible for closing streams
+     * it opens. Updating a bundle in the cache does not replace the current
+     * revision of the bundle, it makes a new revision available. If this
+     * method completes successfully, then it means that the number of
+     * revisions of the specified bundle has increased by one.
+     * </p>
+     * @param ba the bundle archive of the bundle to update.
+     * @param is the input stream to the bundle's updated JAR file.
+     * @throws Exception if any error occurs.
+    **/
+    public void update(BundleArchive ba, InputStream is)
+        throws Exception;
+
+    /**
+     * <p>
+     * Purges all old revisions of the specified bundle from
+     * the cache. If this method completes successfully, then it means that
+     * only the most current revision of the bundle should exist in the cache.
+     * </p>
+     * @param ba the bundle archive of the bundle to purge.
+     * @throws Exception if any error occurs.
+    **/
+    public void purge(BundleArchive ba)
+        throws Exception;
+
+    /**
+     * <p>
+     * Removes the specified bundle from the cache. If this method
+     * completes successfully, there should be no trace of the removed bundle
+     * in the cache.
+     * </p>
+     * @param ba the bundle archive of the bundle to remove.
+     * @throws Exception if any error occurs.
+    **/
+    public void remove(BundleArchive ba)
+        throws Exception;
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleArchive.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleArchive.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleArchive.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleArchive.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,1471 @@
+/*
+ *   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.cache;
+
+import java.io.*;
+import java.security.*;
+import java.util.*;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.apache.osgi.framework.LogWrapper;
+import org.apache.osgi.framework.util.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+
+/**
+ * <p>
+ * This class, combined with <tt>DefaultBundleCache</tt>, implements the
+ * default file system-based bundle cache for Felix.
+ * </p>
+ * @see org.apache.osgi.framework.util.DefaultBundleCache
+**/
+public class DefaultBundleArchive implements BundleArchive
+{
+    private static final transient String BUNDLE_JAR_FILE = "bundle.jar";
+    private static final transient String BUNDLE_LOCATION_FILE = "bundle.location";
+    private static final transient String BUNDLE_STATE_FILE = "bundle.state";
+    private static final transient String BUNDLE_START_LEVEL_FILE = "bundle.startlevel";
+    private static final transient String REFRESH_COUNTER_FILE = "refresh.counter";
+    private static final transient String BUNDLE_ACTIVATOR_FILE = "bundle.activator";
+
+    private static final transient String REVISION_DIRECTORY = "version";
+    private static final transient String EMBEDDED_DIRECTORY = "embedded";
+    private static final transient String LIBRARY_DIRECTORY = "lib";
+    private static final transient String DATA_DIRECTORY = "data";
+
+    private static final transient String ACTIVE_STATE = "active";
+    private static final transient String INSTALLED_STATE = "installed";
+    private static final transient String UNINSTALLED_STATE = "uninstalled";
+
+    private LogWrapper m_logger = null;
+    private long m_id = -1;
+    private File m_dir = null;
+    private String m_location = null;
+    private int m_persistentState = -1;
+    private int m_startLevel = -1;
+    private Map m_currentHeader = null;
+
+    private long m_refreshCount = -1;
+    private int m_revisionCount = -1;
+
+    public DefaultBundleArchive(LogWrapper logger, File dir, long id, String location, InputStream is)    
+        throws Exception
+    {
+        this(logger, dir, id);
+        m_location = location;
+
+        // Try to save and pre-process the bundle JAR.
+        try
+        {
+            initialize(is);
+        }
+        catch (Exception ex)
+        {
+            if (!deleteDirectoryTree(dir))
+            {
+                m_logger.log(
+                    LogWrapper.LOG_ERROR,
+                    "Unable to delete the archive directory: " + id);
+            }
+            throw ex;
+        }
+    }
+
+    public DefaultBundleArchive(LogWrapper logger, File dir, long id)
+    {
+        m_logger = logger;
+        m_dir = dir;
+        m_id = id;
+        if (m_id <= 0)
+        {
+            throw new IllegalArgumentException(
+                "Bundle ID cannot be less than or equal to zero.");
+        }
+    }
+
+    private void initialize(InputStream is)
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.INITIALIZE_ACTION, this, is));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            initializeUnchecked(is);
+        }
+    }
+
+    private void initializeUnchecked(InputStream is)
+        throws Exception
+    {
+        FileWriter fw = null;
+        BufferedWriter bw = null;
+
+        try
+        {
+            // Create archive directory.
+            if (!m_dir.mkdir())
+            {
+                m_logger.log(
+                    LogWrapper.LOG_ERROR,
+                    "DefaultBundleArchive: Unable to create archive directory.");
+                throw new IOException("Unable to create archive directory.");
+            }
+
+            // Save location string.
+            File file = new File(m_dir, BUNDLE_LOCATION_FILE);
+            fw = new FileWriter(file);
+            bw = new BufferedWriter(fw);
+            bw.write(m_location, 0, m_location.length());
+
+            // Create version/revision directory for bundle JAR.
+            // Since this is only called when the bundle JAR is
+            // first saved, the update and revision will always
+            // be "0.0" for the directory name.
+            File revisionDir = new File(m_dir, REVISION_DIRECTORY + "0.0");
+            if (!revisionDir.mkdir())
+            {
+                m_logger.log(
+                    LogWrapper.LOG_ERROR,
+                    "DefaultBundleArchive: Unable to create revision directory.");
+                throw new IOException("Unable to create revision directory.");
+            }
+
+            // Save the bundle jar file.
+            file = new File(revisionDir, BUNDLE_JAR_FILE);
+            copy(is, file);
+
+            // This will always be revision zero.
+            preprocessBundleJar(0, revisionDir);
+
+        }
+        finally
+        {
+            if (is != null) is.close();
+            if (bw != null) bw.close();
+            if (fw != null) fw.close();
+        }
+    }
+
+    public File getDirectory()
+    {
+        return m_dir;
+    }
+
+    public long getId()
+    {
+        return m_id;
+    }
+
+    public String getLocation()
+        throws Exception
+    {
+        if (m_location != null)
+        {
+            return m_location;
+        }
+        else if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return (String) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.GET_LOCATION_ACTION, this));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            return getLocationUnchecked();
+        }
+    }
+
+    private String getLocationUnchecked()
+        throws Exception
+    {
+        // Get bundle location file.
+        File locFile = new File(m_dir, BUNDLE_LOCATION_FILE);
+
+        // Read bundle location.
+        FileReader fr = null;
+        BufferedReader br = null;
+        try
+        {
+            fr = new FileReader(locFile);
+            br = new BufferedReader(fr);
+            m_location = br.readLine();
+            return m_location;
+        }
+        finally
+        {
+            if (br != null) br.close();
+            if (fr != null) fr.close();
+        }
+    }
+
+    public int getPersistentState()
+        throws Exception
+    {
+        if (m_persistentState >= 0)
+        {
+            return m_persistentState;
+        }
+        else if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return ((Integer) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.GET_PERSISTENT_STATE_ACTION, this))).intValue();
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            return getPersistentStateUnchecked();
+        }
+    }
+
+    private int getPersistentStateUnchecked()
+        throws Exception
+    {
+        // Get bundle state file.
+        File stateFile = new File(m_dir, BUNDLE_STATE_FILE);
+
+        // If the state file doesn't exist, then
+        // assume the bundle was installed.
+        if (!stateFile.exists())
+        {
+            return Bundle.INSTALLED;
+        }
+
+        // Read the bundle state.
+        FileReader fr = null;
+        BufferedReader br= null;
+        try
+        {
+            fr = new FileReader(stateFile);
+            br = new BufferedReader(fr);
+            String s = br.readLine();
+            if (s.equals(ACTIVE_STATE))
+            {
+                m_persistentState = Bundle.ACTIVE;
+            }
+            else if (s.equals(UNINSTALLED_STATE))
+            {
+                m_persistentState = Bundle.UNINSTALLED;
+            }
+            else
+            {
+                m_persistentState = Bundle.INSTALLED;
+            }
+            return m_persistentState;
+        }
+        finally
+        {
+            if (br != null) br.close();
+            if (fr != null) fr.close();
+        }
+    }
+
+    public void setPersistentState(int state)
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.SET_PERSISTENT_STATE_ACTION, this, state));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            setPersistentStateUnchecked(state);
+        }
+    }
+
+    private void setPersistentStateUnchecked(int state)
+        throws Exception
+    {
+        // Get bundle state file.
+        File stateFile = new File(m_dir, BUNDLE_STATE_FILE);
+
+        // Write the bundle state.
+        FileWriter fw = null;
+        BufferedWriter bw= null;
+        try
+        {
+            fw = new FileWriter(stateFile);
+            bw = new BufferedWriter(fw);
+            String s = null;
+            switch (state)
+            {
+                case Bundle.ACTIVE:
+                    s = ACTIVE_STATE;
+                    break;
+                case Bundle.UNINSTALLED:
+                    s = UNINSTALLED_STATE;
+                    break;
+                default:
+                    s = INSTALLED_STATE;
+                    break;
+            }
+            bw.write(s, 0, s.length());
+            m_persistentState = state;
+        }
+        catch (IOException ex)
+        {
+            m_logger.log(
+                LogWrapper.LOG_ERROR,
+                "DefaultBundleArchive: Unable to record state: " + ex);
+            throw ex;
+        }
+        finally
+        {
+            if (bw != null) bw.close();
+            if (fw != null) fw.close();
+        }
+    }
+
+    public int getStartLevel()
+        throws Exception
+    {
+        if (m_startLevel >= 0)
+        {
+            return m_startLevel;
+        }
+        else if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return ((Integer) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.GET_START_LEVEL_ACTION, this))).intValue();
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            return getStartLevelUnchecked();
+        }
+    }
+
+    private int getStartLevelUnchecked()
+        throws Exception
+    {
+        // Get bundle start level file.
+        File levelFile = new File(m_dir, BUNDLE_START_LEVEL_FILE);
+
+        // If the start level file doesn't exist, then
+        // return an error.
+        if (!levelFile.exists())
+        {
+            return -1;
+        }
+
+        // Read the bundle start level.
+        FileReader fr = null;
+        BufferedReader br= null;
+        try
+        {
+            fr = new FileReader(levelFile);
+            br = new BufferedReader(fr);
+            m_startLevel = Integer.parseInt(br.readLine());
+            return m_startLevel;
+        }
+        finally
+        {
+            if (br != null) br.close();
+            if (fr != null) fr.close();
+        }
+    }
+
+    public void setStartLevel(int level)
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.SET_START_LEVEL_ACTION, this, level));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            setStartLevelUnchecked(level);
+        }
+    }
+
+    private void setStartLevelUnchecked(int level)
+        throws Exception
+    {
+        // Get bundle start level file.
+        File levelFile = new File(m_dir, BUNDLE_START_LEVEL_FILE);
+
+        // Write the bundle start level.
+        FileWriter fw = null;
+        BufferedWriter bw = null;
+        try
+        {
+            fw = new FileWriter(levelFile);
+            bw = new BufferedWriter(fw);
+            String s = Integer.toString(level);
+            bw.write(s, 0, s.length());
+            m_startLevel = level;
+        }
+        catch (IOException ex)
+        {
+            m_logger.log(
+                LogWrapper.LOG_ERROR,
+                "DefaultBundleArchive: Unable to record start leel: " + ex);
+            throw ex;
+        }
+        finally
+        {
+            if (bw != null) bw.close();
+            if (fw != null) fw.close();
+        }
+    }
+
+    public File getDataFile(String fileName)
+        throws Exception
+    {
+        // Do some sanity checking.
+        if ((fileName.length() > 0) && (fileName.charAt(0) == File.separatorChar))
+            throw new IllegalArgumentException("The data file path must be relative, not absolute.");
+        else if (fileName.indexOf("..") >= 0)
+            throw new IllegalArgumentException("The data file path cannot contain a reference to the \"..\" directory.");
+
+        // Get bundle data directory.
+        File dataDir = new File(m_dir, DATA_DIRECTORY);
+
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.CREATE_DATA_DIR_ACTION, this, dataDir));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            createDataDirectoryUnchecked(dataDir);
+        }
+
+        // Return the data file.
+        return new File(dataDir, fileName);
+    }
+
+    private void createDataDirectoryUnchecked(File dir)
+        throws Exception
+    {
+        // Create data directory if necessary.
+        if (!dir.exists())
+        {
+            if (!dir.mkdir())
+            {
+                throw new IOException("Unable to create bundle data directory.");
+            }
+        }
+    }
+
+    public BundleActivator getActivator(ClassLoader loader)
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return (BundleActivator) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.GET_ACTIVATOR_ACTION, this, loader));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            return getActivatorUnchecked(loader);
+        }
+    }
+
+    private BundleActivator getActivatorUnchecked(ClassLoader loader)
+        throws Exception
+    {
+        // Get bundle activator file.
+        File activatorFile = new File(m_dir, BUNDLE_ACTIVATOR_FILE);
+        // If the activator file doesn't exist, then
+        // assume there isn't one.
+        if (!activatorFile.exists())
+            return null;
+
+        // Deserialize the activator object.
+        InputStream is = null;
+        ObjectInputStreamX ois = null;
+        try
+        {
+            is = new FileInputStream(activatorFile);
+            ois = new ObjectInputStreamX(is, loader);
+            Object o = ois.readObject();
+            return (BundleActivator) o;
+        }
+        catch (Exception ex)
+        {
+            m_logger.log(
+                LogWrapper.LOG_ERROR,
+                "DefaultBundleArchive: Trying to deserialize - " + ex);
+        }
+        finally
+        {
+            if (ois != null) ois.close();
+            if (is != null) is.close();
+        }
+
+        return null;
+    }
+
+    public void setActivator(Object obj)
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.SET_ACTIVATOR_ACTION, this, obj));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            setActivatorUnchecked(obj);
+        }
+    }
+
+    private void setActivatorUnchecked(Object obj)
+        throws Exception
+    {
+        if (!(obj instanceof Serializable))
+        {
+            return;
+        }
+
+        // Get bundle activator file.
+        File activatorFile = new File(m_dir, BUNDLE_ACTIVATOR_FILE);
+
+        // Serialize the activator object.
+        OutputStream os = null;
+        ObjectOutputStream oos = null;
+        try
+        {
+            os = new FileOutputStream(activatorFile);
+            oos = new ObjectOutputStream(os);
+            oos.writeObject(obj);
+        }
+        catch (IOException ex)
+        {
+            m_logger.log(
+                LogWrapper.LOG_ERROR,
+                "DefaultBundleArchive: Unable to serialize activator - " + ex);
+            throw ex;
+        }
+        finally
+        {
+            if (oos != null) oos.close();
+            if (os != null) os.close();
+        }
+    }
+
+    public int getRevisionCount()
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return ((Integer) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.GET_REVISION_COUNT_ACTION, this))).intValue();
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            return getRevisionCountUnchecked();
+        }
+    }
+
+    public int getRevisionCountUnchecked()
+    {
+        // We should always have at least one revision
+        // directory, so try to count them if the value
+        // has not been initialized yet.
+        if (m_revisionCount <= 0)
+        {
+            m_revisionCount = 0;
+            File[] children = m_dir.listFiles();
+            for (int i = 0; (children != null) && (i < children.length); i++)
+            {
+                if (children[i].getName().startsWith(REVISION_DIRECTORY))
+                {
+                    m_revisionCount++;
+                }
+            }
+        }
+        return m_revisionCount;
+    }
+
+    public Map getManifestHeader(int revision)
+        throws Exception
+    {
+        // If the request is for the current revision header,
+        // then return the cached copy if it is present.
+        if ((revision == (getRevisionCount() - 1)) && (m_currentHeader != null))
+        {
+            return m_currentHeader;
+        }
+
+        // Get the revision directory.
+        File revisionDir = new File(
+            m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
+
+        // Get the embedded resource.
+        JarFile jarFile = null;
+
+        try
+        {
+            // Create JarFile object using privileged block.
+            if (System.getSecurityManager() != null)
+            {
+                jarFile = (JarFile) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.OPEN_BUNDLE_JAR_ACTION, this, revisionDir));
+            }
+            else
+            {
+                jarFile = openBundleJarUnchecked(revisionDir);
+            }
+
+            // Error if no jar file.
+            if (jarFile == null)
+            {
+                throw new IOException("No JAR file found.");
+            }
+
+            // Get manifest.
+            Manifest mf = jarFile.getManifest();
+            // Create a case insensitive map of manifest attributes.
+            Map map = new CaseInsensitiveMap(mf.getMainAttributes());
+            // If the request is for the current revision's header,
+            // then cache it.
+            if (revision == (getRevisionCount() - 1))
+            {
+                m_currentHeader = map;
+            }
+            return map;
+
+        } catch (PrivilegedActionException ex) {
+            throw ((PrivilegedActionException) ex).getException();
+        } finally {
+            if (jarFile != null) jarFile.close();
+        }
+    }
+
+    private JarFile openBundleJarUnchecked(File revisionDir)
+        throws Exception
+    {
+        // Get bundle jar file.
+        File bundleJar = new File(revisionDir, BUNDLE_JAR_FILE);
+        // Get bundle jar file.
+        return new JarFile(bundleJar);
+    }
+
+    public String[] getClassPath(int revision)
+        throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return (String []) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.GET_CLASS_PATH_ACTION, this, revision));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            return getClassPathUnchecked(revision);
+        }
+    }
+
+    private String[] getClassPathUnchecked(int revision)
+        throws Exception
+    {
+        // Get the revision directory.
+        File revisionDir = new File(
+            m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
+
+        // Get the bundle's manifest header.
+        Map map = getManifestHeader(revision);
+        if (map == null)
+        {
+            map = new HashMap();
+        }
+
+        // Find class path meta-data.
+        String classPath = null;
+        Iterator iter = map.entrySet().iterator();
+        while ((classPath == null) && iter.hasNext())
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (entry.getKey().toString().toLowerCase().equals(
+                FelixConstants.BUNDLE_CLASSPATH.toLowerCase()))
+            {
+                classPath = entry.getValue().toString();
+            }
+        }
+
+        // Parse the class path into strings.
+        String[] classPathStrings = Util.parseDelimitedString(
+            classPath, FelixConstants.CLASS_PATH_SEPARATOR);
+
+        if (classPathStrings == null)
+        {
+            classPathStrings = new String[0];
+        }
+
+        // Now, check for "." in the class path.
+        boolean includeDot = false;
+        for (int i = 0; !includeDot && (i < classPathStrings.length); i++)
+        {
+            if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
+            {
+                includeDot = true;
+            }
+        }
+
+        // Include all JARs in the embedded jar directory, since they
+        // were extracted when the bundle was initially saved.
+        File embedDir = new File(revisionDir, EMBEDDED_DIRECTORY);
+        String[] paths = null;
+        if (embedDir.exists())
+        {
+            // The size of the paths array is the number of
+            // embedded JAR files plus one, if we need to include
+            // ".", otherwise it is just the number of JAR files.
+            // If "." is included, then it will be added to the
+            // first place in the path array below.
+            File[] children = embedDir.listFiles();
+            int size = (children == null) ? 0 : children.length;
+            size = (includeDot) ? size + 1 : size;
+            paths = new String[size];
+            for (int i = 0; i < children.length; i++)
+            {
+                // If we are including "." then skip the first slot,
+                // because this is where we will put the bundle JAR file.
+                paths[(includeDot) ? i + 1 : i] = children[i].getPath();
+            }
+        }
+
+        // If there is nothing on the class path, then include
+        // "." by default, as per the spec.
+        if ((paths == null) || (paths.length == 0))
+        {
+            includeDot = true;
+            paths = new String[1];
+        }
+
+        // Put the bundle jar file first, if included.
+        if (includeDot)
+        {
+            paths[0] = revisionDir + File.separator + BUNDLE_JAR_FILE;
+        }
+
+        return paths;
+    }
+
+//  TODO: This will need to consider security.
+    public String findLibrary(int revision, String libName)
+        throws Exception
+    {
+        return findLibraryUnchecked(revision, libName);
+    }
+
+    private String findLibraryUnchecked(int revision, String libName)
+        throws Exception
+    {
+        // Get the revision directory.
+        File revisionDir = new File(
+            m_dir.getAbsoluteFile(),
+            REVISION_DIRECTORY + getRefreshCount() + "." + revision);
+
+        // Get bundle lib directory.
+        File libDir = new File(revisionDir, LIBRARY_DIRECTORY);
+        // Get lib file.
+        File libFile = new File(libDir, File.separatorChar + libName);
+        // Make sure that the library's parent directory exists;
+        // it may be in a sub-directory.
+        libDir = libFile.getParentFile();
+        if (!libDir.exists())
+        {
+            if (!libDir.mkdirs())
+            {
+                throw new IOException("Unable to create library directory.");
+            }
+        }
+        // Extract the library from the JAR file if it does not
+        // already exist.
+        if (!libFile.exists())
+        {
+            JarFile jarFile = null;
+            InputStream is = null;
+
+            try
+            {
+                jarFile = openBundleJarUnchecked(revisionDir);
+                ZipEntry ze = jarFile.getEntry(libName);
+                if (ze == null)
+                {
+                    throw new IOException("No JAR entry: " + libName);
+                }
+                is = new BufferedInputStream(
+                    jarFile.getInputStream(ze), DefaultBundleCache.BUFSIZE);
+                if (is == null)
+                {
+                    throw new IOException("No input stream: " + libName);
+                }
+
+                // Create the file.
+                copy(is, libFile);
+
+            }
+            finally
+            {
+                if (jarFile != null) jarFile.close();
+                if (is != null) is.close();
+            }
+        }
+
+        return libFile.toString();
+    }
+
+    /**
+     * This utility method is used to retrieve the current refresh
+     * counter value for the bundle. This value is used when generating
+     * the bundle JAR directory name where native libraries are extracted.
+     * This is necessary because Sun's JVM requires a one-to-one mapping
+     * between native libraries and class loaders where the native library
+     * is uniquely identified by its absolute path in the file system. This
+     * constraint creates a problem when a bundle is refreshed, because it
+     * gets a new class loader. Using the refresh counter to generate the name
+     * of the bundle JAR directory resolves this problem because each time
+     * bundle is refresh, the native library will have a unique name.
+     * As a result of the unique name, the JVM will then reload the
+     * native library without a problem.
+    **/
+    private long getRefreshCount()
+        throws Exception
+    {
+        // If we have already read the update counter file,
+        // then just return the result.
+        if (m_refreshCount >= 0)
+        {
+            return m_refreshCount;
+        }
+
+        // Get update counter file.
+        File counterFile = new File(m_dir, REFRESH_COUNTER_FILE);
+
+        // If the update counter file doesn't exist, then
+        // assume the counter is at zero.
+        if (!counterFile.exists())
+        {
+            return 0;
+        }
+
+        // Read the bundle update counter.
+        FileReader fr = null;
+        BufferedReader br = null;
+        try
+        {
+            fr = new FileReader(counterFile);
+            br = new BufferedReader(fr);
+            long counter = Long.parseLong(br.readLine());
+            return counter;
+        }
+        finally
+        {
+            if (br != null) br.close();
+            if (fr != null) fr.close();
+        }
+    }
+
+    /**
+     * This utility method is used to retrieve the current refresh
+     * counter value for the bundle. This value is used when generating
+     * the bundle JAR directory name where native libraries are extracted.
+     * This is necessary because Sun's JVM requires a one-to-one mapping
+     * between native libraries and class loaders where the native library
+     * is uniquely identified by its absolute path in the file system. This
+     * constraint creates a problem when a bundle is refreshed, because it
+     * gets a new class loader. Using the refresh counter to generate the name
+     * of the bundle JAR directory resolves this problem because each time
+     * bundle is refresh, the native library will have a unique name.
+     * As a result of the unique name, the JVM will then reload the
+     * native library without a problem.
+    **/
+    private void setRefreshCount(long counter)
+        throws Exception
+    {
+        // Get update counter file.
+        File counterFile = new File(m_dir, REFRESH_COUNTER_FILE);
+
+        // Write the update counter.
+        FileWriter fw = null;
+        BufferedWriter bw = null;
+        try
+        {
+            fw = new FileWriter(counterFile);
+            bw = new BufferedWriter(fw);
+            String s = Long.toString(counter);
+            bw.write(s, 0, s.length());
+            m_refreshCount = counter;
+        }
+        catch (IOException ex)
+        {
+            m_logger.log(
+                LogWrapper.LOG_ERROR,
+                "DefaultBundleArchive: Unable to write counter: " + ex);
+            throw ex;
+        }
+        finally
+        {
+            if (bw != null) bw.close();
+            if (fw != null) fw.close();
+        }
+    }
+
+    //
+    // File-oriented utility methods.
+    //
+
+    protected static boolean deleteDirectoryTree(File target)
+    {
+        if (!target.exists())
+        {
+            return true;
+        }
+
+        if (target.isDirectory())
+        {
+            File[] files = target.listFiles();
+            for (int i = 0; i < files.length; i++)
+            {
+                deleteDirectoryTree(files[i]);
+            }
+        }
+
+        return target.delete();
+    }
+
+    /**
+     * This method copies an input stream to the specified file.
+     * <p>
+     * Security: This method must be called from within a <tt>doPrivileged()</tt>
+     * block since it accesses the disk.
+     * @param is the input stream to copy.
+     * @param outputFile the file to which the input stream should be copied.
+    **/
+    private void copy(InputStream is, File outputFile)
+        throws IOException
+    {
+        OutputStream os = null;
+
+        try
+        {
+            os = new BufferedOutputStream(
+                new FileOutputStream(outputFile), DefaultBundleCache.BUFSIZE);
+            byte[] b = new byte[DefaultBundleCache.BUFSIZE];
+            int len = 0;
+            while ((len = is.read(b)) != -1)
+                os.write(b, 0, len);
+        }
+        finally
+        {
+            if (is != null) is.close();
+            if (os != null) os.close();
+        }
+    }
+
+    /**
+     * This method pre-processes a bundle JAR file making it ready
+     * for use. This entails extracting all embedded JAR files and
+     * all native libraries.
+     * @throws java.lang.Exception if any error occurs while processing JAR file.
+    **/
+    private void preprocessBundleJar(int revision, File revisionDir)
+        throws Exception
+    {
+        //
+        // Create special directories so that we can avoid checking
+        // for their existence all the time.
+        //
+
+        File embedDir = new File(revisionDir, EMBEDDED_DIRECTORY);
+        if (!embedDir.exists())
+        {
+            if (!embedDir.mkdir())
+            {
+                throw new IOException("Could not create embedded JAR directory.");
+            }
+        }
+
+        File libDir = new File(revisionDir, LIBRARY_DIRECTORY);
+        if (!libDir.exists())
+        {
+            if (!libDir.mkdir())
+            {
+                throw new IOException("Unable to create native library directory.");
+            }
+        }
+
+        //
+        // This block extracts all embedded JAR files.
+        //
+
+        try
+        {
+            // Get the bundle's manifest header.
+            Map map = getManifestHeader(revision);
+            if (map == null)
+            {
+                map = new HashMap();
+            }
+
+            // Find class path meta-data.
+            String classPath = null;
+            Iterator iter = map.entrySet().iterator();
+            while ((classPath == null) && iter.hasNext())
+            {
+                Map.Entry entry = (Map.Entry) iter.next();
+                if (entry.getKey().toString().toLowerCase().equals(
+                    FelixConstants.BUNDLE_CLASSPATH.toLowerCase()))
+                {
+                    classPath = entry.getValue().toString();
+                }
+            }
+
+            // Parse the class path into strings.
+            String[] classPathStrings = Util.parseDelimitedString(
+                classPath, FelixConstants.CLASS_PATH_SEPARATOR);
+
+            if (classPathStrings == null)
+            {
+                classPathStrings = new String[0];
+            }
+
+            for (int i = 0; i < classPathStrings.length; i++)
+            {
+                if (!classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
+                {
+                    extractEmbeddedJar(revisionDir, classPathStrings[i]);
+                }
+            }
+
+        }
+        catch (PrivilegedActionException ex)
+        {
+            throw ((PrivilegedActionException) ex).getException();
+        }
+    }
+
+    /**
+     * This method extracts an embedded JAR file from the bundle's
+     * JAR file.
+     * <p>
+     * Security: This method must be called from within a <tt>doPrivileged()</tt>
+     * block since it accesses the disk.
+     * @param id the identifier of the bundle that owns the embedded JAR file.
+     * @param jarPath the path to the embedded JAR file inside the bundle JAR file.
+    **/
+    private void extractEmbeddedJar(File revisionDir, String jarPath)
+        throws Exception
+    {
+        // Remove leading slash if present.
+        jarPath = (jarPath.charAt(0) == '/') ? jarPath.substring(1) : jarPath;
+        // Get only the JAR file name.
+        String jarName = (jarPath.lastIndexOf('/') >= 0)
+            ? jarPath.substring(jarPath.lastIndexOf('/') + 1) : jarPath;
+
+        // If JAR is already extracted, then don't
+        // re-extract it...
+        File embedFile = new File(
+            revisionDir, EMBEDDED_DIRECTORY + File.separatorChar + jarName);
+        if (!embedFile.exists())
+        {
+            JarFile jarFile = null;
+            InputStream is = null;
+
+            try
+            {
+                jarFile = openBundleJarUnchecked(revisionDir);
+                ZipEntry ze = jarFile.getEntry(jarPath);
+                if (ze == null)
+                {
+                    throw new IOException("No JAR entry: " + jarPath);
+                }
+                is = new BufferedInputStream(jarFile.getInputStream(ze), DefaultBundleCache.BUFSIZE);
+                if (is == null)
+                {
+                    throw new IOException("No input stream: " + jarPath);
+                }
+
+                // Create the file.
+                copy(is, embedFile);
+
+            }
+            finally
+            {
+                if (jarFile != null) jarFile.close();
+                if (is != null) is.close();
+            }
+        }
+    }
+
+    // INCREASES THE REVISION COUNT.    
+    protected void update(InputStream is) throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.UPDATE_ACTION, this, is));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            updateUnchecked(is);
+        }
+    }
+
+    // INCREASES THE REVISION COUNT.    
+    private void updateUnchecked(InputStream is) throws Exception
+    {
+        File revisionDir = null;
+
+        try
+        {
+            // Create the new revision directory.
+            int revision = getRevisionCountUnchecked();
+            revisionDir = new File(
+                m_dir, REVISION_DIRECTORY
+                + getRefreshCount() + "." + revision);
+            if (!revisionDir.mkdir())
+            {
+                throw new IOException("Unable to create revision directory.");
+            }
+
+            // Save the new revision bundle jar file.
+            File file = new File(revisionDir, BUNDLE_JAR_FILE);
+            copy(is, file);
+
+            preprocessBundleJar(revision, revisionDir);
+        }
+        catch (Exception ex)
+        {
+            if ((revisionDir != null) && revisionDir.exists())
+            {
+                try
+                {
+                    deleteDirectoryTree(revisionDir);
+                }
+                catch (Exception ex2)
+                {
+                    // There is very little we can do here.
+                    m_logger.log(
+                        LogWrapper.LOG_ERROR,
+                        "Unable to remove partial revision directory.", ex2);
+                }
+            }
+            throw ex;
+        }
+
+        // If everything was successful, then update
+        // the revision count.
+        m_revisionCount++;
+        // Clear the cached revision header, since it is
+        // no longer the current revision.
+        m_currentHeader = null;
+    }
+
+    // DECREASES THE REVISION COUNT.    
+    protected void purge() throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.PURGE_ACTION, this));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            purgeUnchecked();
+        }
+    }
+    
+    // DECREASES THE REVISION COUNT.    
+    private void purgeUnchecked() throws Exception
+    {
+        // Get the current update count.
+        long update = getRefreshCount();
+        // Get the current revision count.
+        int count = getRevisionCountUnchecked();
+
+        File revisionDir = null;
+        for (int i = 0; i < count - 1; i++)
+        {
+            revisionDir = new File(m_dir, REVISION_DIRECTORY + update + "." + i);
+            if (revisionDir.exists())
+            {
+                deleteDirectoryTree(revisionDir);
+            }
+        }
+        // Increment the update count.
+        setRefreshCount(update + 1);
+
+        // Rename the current revision to be the current update.
+        File currentDir = new File(m_dir, REVISION_DIRECTORY + (update + 1) + ".0");
+        revisionDir = new File(m_dir, REVISION_DIRECTORY + update + "." + (count - 1));
+        revisionDir.renameTo(currentDir);
+        
+        // If everything is successful, then set the revision
+        // count to one.
+        m_revisionCount = 1;
+        // Although the cached current header should stay the same
+        // here, clear it for consistency.
+        m_currentHeader = null;
+    }
+
+    protected void remove() throws Exception
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.REMOVE_ACTION, this));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+        else
+        {
+            removeUnchecked();
+        }
+    }
+    
+    private void removeUnchecked() throws Exception
+    {
+        deleteDirectoryTree(m_dir);
+    }
+
+    //
+    // Utility class for performing privileged actions.
+    //
+
+    private static class PrivilegedAction implements PrivilegedExceptionAction
+    {
+        private static final int INITIALIZE_ACTION = 0;
+        private static final int UPDATE_ACTION = 1;
+        private static final int PURGE_ACTION = 2;
+        private static final int REMOVE_ACTION = 3;
+        private static final int GET_REVISION_COUNT_ACTION = 4;
+        private static final int GET_LOCATION_ACTION = 5;
+        private static final int GET_PERSISTENT_STATE_ACTION = 6;
+        private static final int SET_PERSISTENT_STATE_ACTION = 7;
+        private static final int GET_START_LEVEL_ACTION = 8;
+        private static final int SET_START_LEVEL_ACTION = 9;
+        private static final int OPEN_BUNDLE_JAR_ACTION = 10;
+        private static final int CREATE_DATA_DIR_ACTION = 11;
+        private static final int GET_CLASS_PATH_ACTION = 12;
+        private static final int GET_ACTIVATOR_ACTION = 13;
+        private static final int SET_ACTIVATOR_ACTION = 14;
+
+        private int m_action = 0;
+        private DefaultBundleArchive m_archive = null;
+        private InputStream m_isArg = null;
+        private int m_intArg = 0;
+        private File m_fileArg = null;
+        private ClassLoader m_loaderArg = null;
+        private Object m_objArg = null;
+
+        public PrivilegedAction(int action, DefaultBundleArchive archive)
+        {
+            m_action = action;
+            m_archive = archive;
+        }
+
+        public PrivilegedAction(int action, DefaultBundleArchive archive, InputStream isArg)
+        {
+            m_action = action;
+            m_archive = archive;
+            m_isArg = isArg;
+        }
+
+        public PrivilegedAction(int action, DefaultBundleArchive archive, int intArg)
+        {
+            m_action = action;
+            m_archive = archive;
+            m_intArg = intArg;
+        }
+
+        public PrivilegedAction(int action, DefaultBundleArchive archive, File fileArg)
+        {
+            m_action = action;
+            m_archive = archive;
+            m_fileArg = fileArg;
+        }
+
+        public PrivilegedAction(int action, DefaultBundleArchive archive, ClassLoader loaderArg)
+        {
+            m_action = action;
+            m_archive = archive;
+            m_loaderArg = loaderArg;
+        }
+
+        public PrivilegedAction(int action, DefaultBundleArchive archive, Object objArg)
+        {
+            m_action = action;
+            m_archive = archive;
+            m_objArg = objArg;
+        }
+
+        public Object run() throws Exception
+        {
+            switch (m_action)
+            {
+                case INITIALIZE_ACTION:
+                    m_archive.initializeUnchecked(m_isArg);
+                    return null;
+                case UPDATE_ACTION:
+                    m_archive.updateUnchecked(m_isArg);
+                    return null;
+                case PURGE_ACTION:
+                    m_archive.purgeUnchecked();
+                    return null;
+                case REMOVE_ACTION:
+                    m_archive.removeUnchecked();
+                    return null;
+                case GET_REVISION_COUNT_ACTION:
+                    return new Integer(m_archive.getRevisionCountUnchecked());
+                case GET_LOCATION_ACTION:
+                    return m_archive.getLocationUnchecked();
+                case GET_PERSISTENT_STATE_ACTION:
+                    return new Integer(m_archive.getPersistentStateUnchecked());
+                case SET_PERSISTENT_STATE_ACTION:
+                    m_archive.setPersistentStateUnchecked(m_intArg);
+                    return null;
+                case GET_START_LEVEL_ACTION:
+                    return new Integer(m_archive.getStartLevelUnchecked());
+                case SET_START_LEVEL_ACTION:
+                    m_archive.setStartLevelUnchecked(m_intArg);
+                    return null;
+                case OPEN_BUNDLE_JAR_ACTION:
+                    return m_archive.openBundleJarUnchecked(m_fileArg);
+                case CREATE_DATA_DIR_ACTION:
+                    m_archive.createDataDirectoryUnchecked(m_fileArg);
+                    return null;
+                case GET_CLASS_PATH_ACTION:
+                    return m_archive.getClassPathUnchecked(m_intArg);
+                case GET_ACTIVATOR_ACTION:
+                    return m_archive.getActivatorUnchecked(m_loaderArg);
+                case SET_ACTIVATOR_ACTION:
+                    m_archive.setActivatorUnchecked(m_objArg);
+                    return null;
+            }
+
+            throw new IllegalArgumentException("Invalid action specified.");
+        }
+    }
+}
\ No newline at end of file