blob: 529022a2e8e073ebd67d693f0aa44fc2f64db634 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.framework;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import org.apache.felix.framework.cache.*;
import org.apache.felix.framework.util.*;
import org.apache.felix.framework.util.manifestparser.*;
import org.apache.felix.moduleloader.*;
import org.osgi.framework.*;
class SystemBundle extends BundleImpl implements IModuleDefinition, PrivilegedAction
{
private List m_activatorList = null;
private Map m_activatorContextMap = null;
private IContentLoader m_contentLoader = null;
private ICapability[] m_exports = null;
private Set m_exportNames = null;
private Thread m_shutdownThread = null;
protected SystemBundle(Felix felix, BundleInfo info, List activatorList)
{
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));
// Add the bundle activator for the url handler service.
activatorList.add(new URLHandlersActivator(felix));
m_activatorList = activatorList;
info.setActivator(new SystemBundleActivator());
// 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.
try
{
m_exports = ManifestParser.parseExportHeader(
getFelix().getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES));
}
catch (Exception ex)
{
m_exports = new ICapability[0];
getFelix().getLogger().log(
Logger.LOG_ERROR,
"Error parsing system bundle export statement: "
+ getFelix().getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES), ex);
}
m_contentLoader = new SystemBundleContentLoader();
// Initialize header map as a case insensitive map.
Map map = new StringMap(false);
map.put(FelixConstants.BUNDLE_VERSION,
getFelix().getConfig().get(FelixConstants.FELIX_VERSION_PROPERTY));
map.put(FelixConstants.BUNDLE_SYMBOLICNAME,
FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME);
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_SERVICE, "org.osgi.service.packageadmin.PackageAdmin,org.osgi.service.startlevel.StartLevel");
parseAndAddExports(map);
((SystemBundleArchive) getInfo().getArchive()).setManifestHeader(map);
}
private void parseAndAddExports(Map headers)
{
StringBuffer exportSB = new StringBuffer("");
Set exportNames = new HashSet();
for (int i = 0; i < m_exports.length; i++)
{
if (i > 0)
{
exportSB.append(", ");
}
exportSB.append(((Capability) m_exports[i]).getPackageName());
exportSB.append("; version=\"");
exportSB.append(((Capability) m_exports[i]).getPackageVersion().toString());
exportSB.append("\"");
exportNames.add(((Capability) m_exports[i]).getPackageName());
}
m_exportNames = exportNames;
headers.put(FelixConstants.EXPORT_PACKAGE, exportSB.toString());
}
public IContentLoader getContentLoader()
{
return m_contentLoader;
}
public void start() throws BundleException
{
// The system bundle is only started once and it
// is started by the framework.
if (getState() == Bundle.ACTIVE)
{
return;
}
getInfo().setState(Bundle.STARTING);
try
{
getInfo().setBundleContext(new BundleContextImpl(getFelix(), this));
getInfo().getActivator().start(getInfo().getBundleContext());
}
catch (Throwable throwable)
{
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 void stop() throws BundleException
{
super.stop();
}
public void uninstall() throws BundleException
{
throw new BundleException("Cannot uninstall the system bundle.");
}
public void update() throws BundleException
{
update(null);
}
public void update(InputStream is) throws BundleException
{
Object sm = System.getSecurityManager();
if (sm != null)
{
((SecurityManager) sm).checkPermission(new AdminPermission(this,
AdminPermission.EXECUTE));
}
// TODO: This is supposed to stop and then restart the framework.
throw new BundleException("System bundle update not implemented yet.");
}
public ICapability[] getCapabilities()
{
return m_exports;
}
public IRequirement[] getDynamicRequirements()
{
return null;
}
public R4Library[] getLibraries()
{
return null;
}
public IRequirement[] getRequirements()
{
return null;
}
private final ThreadLocal m_tempBundle = new ThreadLocal();
void addExtensionBundle(BundleImpl bundle)
{
if (System.getSecurityManager() != null)
{
m_tempBundle.set(bundle);
try
{
AccessController.doPrivileged(this);
}
finally
{
m_tempBundle.set(null);
}
}
else
{
_addExtensionBundle(bundle);
}
}
public Object run()
{
_addExtensionBundle((BundleImpl) m_tempBundle.get());
return null;
}
private void _addExtensionBundle(BundleImpl bundle)
{
SystemBundleArchive systemArchive =
(SystemBundleArchive) getInfo().getArchive();
Map headers;
ICapability[] exports;
try
{
headers = new StringMap(systemArchive.getManifestHeader(
systemArchive.getRevisionCount() - 1), false);
exports = ManifestParser.parseExportHeader((String)
bundle.getInfo().getCurrentHeader().get(Constants.EXPORT_PACKAGE));
}
catch (Exception ex)
{
getFelix().getLogger().log(
Logger.LOG_ERROR,
"Error parsing extension bundle export statement: "
+ bundle.getInfo().getCurrentHeader().get(Constants.EXPORT_PACKAGE), ex);
return;
}
try
{
Method addURL =
URLClassLoader.class.getDeclaredMethod("addURL",
new Class[] {URL.class});
addURL.setAccessible(true);
addURL.invoke(getClass().getClassLoader(),
new Object[] {bundle.getEntry("/")});
}
catch (Exception ex)
{
getFelix().getLogger().log(Logger.LOG_WARNING,
"Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?", ex);
throw new UnsupportedOperationException(
"Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?");
}
ICapability[] temp = new ICapability[m_exports.length + exports.length];
System.arraycopy(m_exports, 0, temp, 0, m_exports.length);
System.arraycopy(exports, 0, temp, m_exports.length, exports.length);
m_exports = temp;
parseAndAddExports(headers);
systemArchive.setManifestHeader(headers);
}
void startExtensionBundle(BundleImpl bundle)
{
String activatorClass = (String)
bundle.getInfo().getCurrentHeader().get(
FelixConstants.FELIX_EXTENSION_ACTIVATOR);
if (activatorClass != null)
{
try
{
BundleActivator activator = (BundleActivator)
getClass().getClassLoader().loadClass(
activatorClass.trim()).newInstance();
m_activatorList.add(activator);
if (m_activatorContextMap == null)
{
m_activatorContextMap = new HashMap();
}
BundleContext context = new BundleContextImpl(getFelix(), bundle);
m_activatorContextMap.put(activator, context);
activator.start(context);
}
catch (Throwable ex)
{
getFelix().getLogger().log(Logger.LOG_WARNING,
"Unable to start Felix Extension Activator", ex);
}
}
}
private class SystemBundleActivator implements BundleActivator, Runnable
{
public void start(BundleContext context) throws Exception
{
getInfo().setBundleContext(context);
// Start all activators.
for (int i = 0; i < m_activatorList.size(); i++)
{
((BundleActivator) m_activatorList.get(i)).start(context);
}
}
public void stop(BundleContext context) throws Exception
{
getInfo().setBundleContext(context);
// 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(this, "FelixShutdown");
m_shutdownThread.start();
}
}
public void run()
{
// First, start the framework shutdown, which will
// stop all bundles.
try
{
getFelix().shutdownInternalStart();
}
catch (Exception ex)
{
getFelix().getLogger().log(
Logger.LOG_ERROR,
"SystemBundle: Error while shutting down.", ex);
}
// Next, stop all system bundle activators.
if (m_activatorList != null)
{
// Stop all activators.
for (int i = 0; i < m_activatorList.size(); i++)
{
try
{
if ((m_activatorContextMap != null) &&
m_activatorContextMap.containsKey(m_activatorList.get(i)))
{
((BundleActivator) m_activatorList.get(i)).stop(
(BundleContext) m_activatorContextMap.get(
m_activatorList.get(i)));
}
else
{
((BundleActivator) m_activatorList.get(i)).stop(getInfo().getBundleContext());
}
}
catch (Throwable throwable)
{
getFelix().getLogger().log(
Logger.LOG_WARNING,
"Exception stopping a system bundle activator.",
throwable);
}
}
}
// Lastly, complete the shutdown.
try
{
getFelix().shutdownInternalFinish();
}
catch (Exception ex)
{
getFelix().getLogger().log(
Logger.LOG_ERROR,
"SystemBundle: Error while shutting down.", ex);
}
}
}
private class SystemBundleContentLoader implements IContentLoader
{
private ISearchPolicy m_searchPolicy = null;
private IURLPolicy m_urlPolicy = null;
public void open()
{
// Nothing needed here.
}
public void close()
{
// Nothing needed here.
}
public IContent getContent()
{
return null;
}
public ISearchPolicy getSearchPolicy()
{
return m_searchPolicy;
}
public void setSearchPolicy(ISearchPolicy searchPolicy)
{
m_searchPolicy = searchPolicy;
}
public IURLPolicy getURLPolicy()
{
return m_urlPolicy;
}
public void setURLPolicy(IURLPolicy urlPolicy)
{
m_urlPolicy = urlPolicy;
}
public Class getClass(String name)
{
if (!m_exportNames.contains(Util.getClassPackage(name)))
{
return null;
}
try
{
return getClass().getClassLoader().loadClass(name);
}
catch (ClassNotFoundException ex)
{
getFelix().getLogger().log(
Logger.LOG_WARNING,
ex.getMessage(),
ex);
}
return null;
}
public URL getResource(String name)
{
return getClass().getClassLoader().getResource(name);
}
public Enumeration getResources(String name)
{
try
{
return getClass().getClassLoader().getResources(name);
}
catch (IOException ex)
{
return null;
}
}
public URL getResourceFromContent(String name)
{
// There is no content for the system bundle, so return null.
return null;
}
public boolean hasInputStream(int index, String urlPath) throws IOException
{
return (getClass().getClassLoader().getResource(urlPath) != null);
}
public InputStream getInputStream(int index, String urlPath) throws IOException
{
return getClass().getClassLoader().getResourceAsStream(urlPath);
}
public String findLibrary(String name)
{
// No native libs associated with the system bundle.
return null;
}
}
}