FELIX-884 and FELIX-887: Applying combined patch FELIX-884-4.patch with
two small modifications:
- react to INSTALLED and UNINSTALLED bundle events instead
of STARTING/STOPPING since we are interested in just the bundle
definition
- fix a formatting issue with the synchronized blocks
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@736585 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java
index befe74a..de13ad3 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java
@@ -56,5 +56,6 @@
public void stop(BundleContext context)
{
+ m_repoAdmin.dispose();
}
}
\ No newline at end of file
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java
index 914af73..78cd147 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/LocalRepositoryImpl.java
@@ -19,20 +19,32 @@
package org.apache.felix.bundlerepository;
import java.net.URL;
-import java.util.*;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
-import org.osgi.framework.*;
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.obr.Repository;
import org.osgi.service.obr.Resource;
-public class LocalRepositoryImpl implements Repository
+public class LocalRepositoryImpl implements Repository, SynchronousBundleListener, AllServiceListener
{
- private BundleContext m_context = null;
+ private final BundleContext m_context;
private final Logger m_logger;
- private long m_currentTimeStamp = 0;
private long m_snapshotTimeStamp = 0;
- private List m_localResourceList = new ArrayList();
- private BundleListener m_bundleListener = null;
+ private Map m_localResourceList = new HashMap();
public LocalRepositoryImpl(BundleContext context, Logger logger)
{
@@ -41,9 +53,77 @@
initialize();
}
+ public void bundleChanged(BundleEvent event)
+ {
+ if (event.getType() == BundleEvent.INSTALLED)
+ {
+ synchronized (this)
+ {
+ addBundle(event.getBundle(), m_logger);
+ m_snapshotTimeStamp = System.currentTimeMillis();
+ }
+ }
+ else if (event.getType() == BundleEvent.UNINSTALLED)
+ {
+ synchronized (this)
+ {
+ removeBundle(event.getBundle(), m_logger);
+ m_snapshotTimeStamp = System.currentTimeMillis();
+ }
+ }
+ }
+
+ public void serviceChanged(ServiceEvent event)
+ {
+ Bundle bundle = event.getServiceReference().getBundle();
+ if (bundle.getState() == Bundle.ACTIVE && event.getType() != ServiceEvent.MODIFIED)
+ {
+ synchronized (this)
+ {
+ removeBundle(bundle, m_logger);
+ addBundle(bundle, m_logger);
+ m_snapshotTimeStamp = System.currentTimeMillis();
+ }
+ }
+ }
+
+ private void addBundle(Bundle bundle, Logger logger)
+ {
+
+ /*
+ * Concurrency note: This method MUST be called in a context which
+ * is synchronized on this instance to prevent data structure
+ * corruption.
+ */
+
+ try
+ {
+ m_localResourceList.put(new Long(bundle.getBundleId()), new LocalResourceImpl(bundle, m_logger));
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // This should never happen since we are generating filters,
+ // but ignore the resource if it does occur.
+ m_logger.log(Logger.LOG_WARNING, ex.getMessage(), ex);
+ }
+ }
+
+ private void removeBundle(Bundle bundle, Logger logger)
+ {
+
+ /*
+ * Concurrency note: This method MUST be called in a context which
+ * is synchronized on this instance to prevent data structure
+ * corruption.
+ */
+
+ m_localResourceList.remove(new Long(bundle.getBundleId()));
+ }
+
public void dispose()
{
- m_context.removeBundleListener(m_bundleListener);
+ m_context.removeBundleListener(this);
+ m_context.removeServiceListener(this);
}
public URL getURL()
@@ -61,30 +141,16 @@
return m_snapshotTimeStamp;
}
- public synchronized long getCurrentTimeStamp()
- {
- return m_currentTimeStamp;
- }
-
public synchronized Resource[] getResources()
{
- return (Resource[]) m_localResourceList.toArray(new Resource[m_localResourceList.size()]);
+ return (Resource[]) m_localResourceList.values().toArray(new Resource[m_localResourceList.size()]);
}
private void initialize()
{
- // Create a bundle listener to list for events that
- // change the state of the framework.
- m_bundleListener = new SynchronousBundleListener() {
- public void bundleChanged(BundleEvent event)
- {
- synchronized (LocalRepositoryImpl.this)
- {
- m_currentTimeStamp = new Date().getTime();
- }
- }
- };
- m_context.addBundleListener(m_bundleListener);
+ // register for bundle and service events now
+ m_context.addBundleListener(this);
+ m_context.addServiceListener(this);
// Generate the resource list from the set of installed bundles.
// Lock so we can ensure that no bundle events arrive before we
@@ -92,24 +158,15 @@
Bundle[] bundles = null;
synchronized (this)
{
- m_snapshotTimeStamp = m_currentTimeStamp = new Date().getTime();
+ // Create a local resource object for each bundle, which will
+ // convert the bundle headers to the appropriate resource metadata.
bundles = m_context.getBundles();
- }
+ for (int i = 0; (bundles != null) && (i < bundles.length); i++)
+ {
+ addBundle(bundles[i], m_logger);
+ }
- // Create a local resource object for each bundle, which will
- // convert the bundle headers to the appropriate resource metadata.
- for (int i = 0; (bundles != null) && (i < bundles.length); i++)
- {
- try
- {
- m_localResourceList.add(new LocalResourceImpl(bundles[i], m_logger));
- }
- catch (InvalidSyntaxException ex)
- {
- // This should never happen since we are generating filters,
- // but ignore the resource if it does occur.
- m_logger.log(Logger.LOG_WARNING, ex.getMessage(), ex);
- }
+ m_snapshotTimeStamp = System.currentTimeMillis();
}
}
@@ -151,8 +208,8 @@
// Convert export package declarations into capabilities.
convertExportPackageToCapability(dict);
- // Convert export service declarations into capabilities.
- convertExportServiceToCapability(dict);
+ // Convert export service declarations and services into capabilities.
+ convertExportServiceToCapability(dict, m_bundle);
// For the system bundle, add a special platform capability.
if (m_bundle.getBundleId() == 0)
@@ -327,20 +384,41 @@
}
}
- private void convertExportServiceToCapability(Dictionary dict)
+ private void convertExportServiceToCapability(Dictionary dict, Bundle bundle)
{
+ Set services = new HashSet();
+
+ // collect Export-Service
String target = (String) dict.get(Constants.EXPORT_SERVICE);
if (target != null)
{
R4Package[] pkgs = R4Package.parseImportOrExportHeader(target);
for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
{
- CapabilityImpl cap = new CapabilityImpl();
- cap.setName("service");
- cap.addP(new PropertyImpl("service", null, pkgs[pkgIdx].getName()));
- addCapability(cap);
+ services.add(pkgs[pkgIdx].getName());
}
}
+
+ // add actual registered services
+ ServiceReference[] refs = bundle.getRegisteredServices();
+ for (int i = 0; refs != null && i < refs.length; i++)
+ {
+ String[] cls = (String[]) refs[i].getProperty(Constants.OBJECTCLASS);
+ for (int j = 0; cls != null && j < cls.length; j++)
+ {
+ services.add(cls[j]);
+ }
+ }
+
+ // register capabilities for combined set
+ for (Iterator si = services.iterator(); si.hasNext();)
+ {
+ CapabilityImpl cap = new CapabilityImpl();
+ cap.setName("service");
+ cap.addP(new PropertyImpl("service", null, (String) si.next()));
+ addCapability(cap);
+ }
}
+
}
}
\ No newline at end of file
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
index e8fd924..4209595 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryAdminImpl.java
@@ -40,6 +40,7 @@
{
static BundleContext m_context = null;
private final Logger m_logger;
+ private final LocalRepositoryImpl m_local;
private List m_urlList = new ArrayList();
private Map m_repoMap = new HashMap();
private boolean m_initialized = false;
@@ -54,6 +55,17 @@
{
m_context = context;
m_logger = logger;
+ m_local = new LocalRepositoryImpl(context, logger);
+ }
+
+ LocalRepositoryImpl getLocalRepository()
+ {
+ return m_local;
+ }
+
+ public void dispose()
+ {
+ m_local.dispose();
}
public Repository addRepository(URL url) throws Exception
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
index ec06639..aacc8eb 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResolverImpl.java
@@ -27,10 +27,10 @@
public class ResolverImpl implements Resolver
{
- private BundleContext m_context = null;
- private RepositoryAdmin m_admin = null;
+ private final BundleContext m_context;
+ private final RepositoryAdmin m_admin;
private final Logger m_logger;
- private LocalRepositoryImpl m_local = null;
+ private final LocalRepositoryImpl m_local;
private Set m_addedSet = new HashSet();
private Set m_resolveSet = new HashSet();
private Set m_requiredSet = new HashSet();
@@ -38,12 +38,14 @@
private Map m_reasonMap = new HashMap();
private Map m_unsatisfiedMap = new HashMap();
private boolean m_resolved = false;
+ private long m_resolveTimeStamp;
- public ResolverImpl(BundleContext context, RepositoryAdmin admin, Logger logger)
+ public ResolverImpl(BundleContext context, RepositoryAdminImpl admin, Logger logger)
{
m_context = context;
m_admin = admin;
m_logger = logger;
+ m_local = admin.getLocalRepository();
}
public synchronized void add(Resource resource)
@@ -110,15 +112,8 @@
public synchronized boolean resolve()
{
- // Get a current local repository.
- // TODO: OBR - We might want to make a smarter local repository
- // that caches installed bundles rather than re-parsing them
- // each time, since this could be costly.
- if (m_local != null)
- {
- m_local.dispose();
- }
- m_local = new LocalRepositoryImpl(m_context, m_logger);
+ // time of the resolution process start
+ m_resolveTimeStamp = m_local.getLastModified();
// Reset instance values.
m_resolveSet.clear();
@@ -434,7 +429,7 @@
// the state can still change during the operation, but we will
// be optimistic. This could also be made smarter so that it checks
// to see if the local state changes overlap with the resolver.
- if (m_local.getLastModified() != m_local.getCurrentTimeStamp())
+ if (m_resolveTimeStamp != m_local.getLastModified())
{
throw new IllegalStateException("Framework state has changed, must resolve again.");
}