Author: rickhall
Date: Tue May 24 17:23:15 2011
New Revision: 1127155
URL: http://svn.apache.org/viewvc?rev=1127155&view=rev
Log:
Implement byte-code weaving hooks. (FELIX-2959)
Added:
felix/trunk/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java?rev=1127155&r1=1127154&r2=1127155&view=diff
==============================================================================
---
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
(original)
+++
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
Tue May 24 17:23:15 2011
@@ -341,7 +341,8 @@ class BundleContextImpl implements Felix
public <S> ServiceRegistration<S> registerService(
Class<S> clazz, S svcObj, Dictionary<String, ? > dict)
{
- throw new UnsupportedOperationException("Not supported yet.");
+ return (ServiceRegistration<S>)
+ registerService(new String[] { clazz.getName() }, svcObj, dict);
}
public ServiceReference<?> getServiceReference(String clazz)
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java?rev=1127155&r1=1127154&r2=1127155&view=diff
==============================================================================
---
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
(original)
+++
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
Tue May 24 17:23:15 2011
@@ -38,7 +38,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
+import java.util.SortedSet;
import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.jar.Manifest;
import org.apache.felix.framework.Felix.StatefulResolver;
import org.apache.felix.framework.cache.JarContent;
import org.apache.felix.framework.cache.Content;
@@ -51,6 +54,7 @@ import org.apache.felix.framework.util.F
import org.apache.felix.framework.util.SecureAction;
import org.apache.felix.framework.util.SecurityManagerEx;
import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.ManifestParser;
import org.apache.felix.framework.util.manifestparser.R4Library;
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.apache.felix.framework.wiring.BundleRequirementImpl;
@@ -58,6 +62,10 @@ import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleReference;
import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.weaving.WeavingException;
+import org.osgi.framework.hooks.weaving.WeavingHook;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
@@ -82,6 +90,8 @@ public class BundleWiringImpl implements
private final List<R4Library> m_resolvedNativeLibs;
private final List<Content> m_fragmentContents;
+ private volatile List<BundleRequirement> m_wovenReqs = null;
+
private BundleClassLoader m_classLoader;
private boolean m_isActivationTriggered = false;
@@ -313,7 +323,7 @@ public class BundleWiringImpl implements
public boolean isCurrent()
{
- throw new UnsupportedOperationException("Not supported yet.");
+ return (((BundleImpl) m_revision.getBundle()).getCurrentRevision() ==
m_revision);
}
public boolean isInUse()
@@ -340,12 +350,21 @@ public class BundleWiringImpl implements
public List<BundleRequirement> getRequirements(String namespace)
{
-
+ List<BundleRequirement> searchReqs = m_resolvedReqs;
+ List<BundleRequirement> wovenReqs = m_wovenReqs;
List<BundleRequirement> result = m_resolvedReqs;
+
+ if (wovenReqs != null)
+ {
+ searchReqs = new ArrayList<BundleRequirement>(m_resolvedReqs);
+ searchReqs.addAll(wovenReqs);
+ result = searchReqs;
+ }
+
if (namespace != null)
{
result = new ArrayList<BundleRequirement>();
- for (BundleRequirement req : m_resolvedReqs)
+ for (BundleRequirement req : searchReqs)
{
if (req.getNamespace().equals(namespace))
{
@@ -1336,104 +1355,261 @@ public class BundleWiringImpl implements
// Get package name.
String pkgName = Util.getClassPackage(name);
+ // Get weaving hooks and invoke them to give them a
+ // chance to weave the class' byte code before we
+ // define it.
+ // NOTE: We don't try to dynamically track hook addition
+ // or removal, we just get a snapshot and leave any changes
+ // as a race condition, doing any necessary clean up in
+ // the error handling.
+ Felix felix = ((BundleImpl)
m_revision.getBundle()).getFramework();
+ SortedSet<ServiceReference<WeavingHook>> hooks =
+ felix.getHooks(WeavingHook.class);
+ WovenClassImpl wci = null;
+ if ((hooks != null) && !hooks.isEmpty())
+ {
+ // Create woven class to be used for hooks.
+ wci = new WovenClassImpl(name, BundleWiringImpl.this,
bytes);
+ // Loop through hooks in service ranking order.
+ for (ServiceReference<WeavingHook> sr : hooks)
+ {
+ // Only use the hook if it is not black listed.
+ if (!felix.isHookBlackListed(sr))
+ {
+ // Get the hook service object.
+ // Note that we don't use the bundle context
+ // to get the service object since that would
+ // perform sercurity checks.
+ WeavingHook wh = felix.getService(felix, sr);
+ if (wh != null)
+ {
+ try
+ {
+ wh.weave(wci);
+ }
+ catch (Throwable th)
+ {
+ if (!(th instanceof WeavingException))
+ {
+ felix.blackListHook(sr);
+ }
+ felix.fireFrameworkEvent(
+ FrameworkEvent.ERROR,
+ sr.getBundle(),
+ th);
+
+ // Mark the woven class as incomplete.
+ wci.complete(null, null, null);
+ // Throw class format exception per
spec.
+ Error error = new
ClassFormatError("Weaving hook failed.");
+ error.initCause(th);
+ throw error;
+ }
+ finally
+ {
+ felix.ungetService(felix, sr);
+ }
+ }
+ }
+ }
+ }
+
// Before we actually attempt to define the class, grab
// the lock for this class loader and make sure than no
// other thread has defined this class in the meantime.
synchronized (this)
{
- clazz = findLoadedClass(name);
-
- if (clazz == null)
+ byte[] wovenBytes = null;
+ Class wovenClass = null;
+ List<String> wovenImports = null;
+ try
{
- int activationPolicy =
- ((BundleImpl)
getBundle()).isDeclaredActivationPolicyUsed()
- ? ((BundleRevisionImpl) ((BundleImpl)
getBundle())
-
.getCurrentRevision()).getDeclaredActivationPolicy()
- : EAGER_ACTIVATION;
-
- // If the revision is using deferred activation,
then if
- // we load this class from this revision we need
to activate
- // the bundle before returning the class. We will
short
- // circuit the trigger matching if the trigger is
already
- // tripped.
- boolean isTriggerClass = m_isActivationTriggered
- ? false :
m_revision.isActivationTrigger(pkgName);
- if (!m_isActivationTriggered
- && isTriggerClass
- && (activationPolicy ==
BundleRevisionImpl.LAZY_ACTIVATION)
- && (getBundle().getState() == Bundle.STARTING))
+ clazz = findLoadedClass(name);
+ if (clazz == null)
{
- List deferredList = (List)
m_deferredActivation.get();
- if (deferredList == null)
+ // If we have a woven class then get the class
bytes from
+ // it since they may have changed.
+ // NOTE: We are taking a snapshot of these
values and
+ // are not preventing a malbehaving weaving
hook from
+ // modifying them after the fact. The price of
preventing
+ // this isn't worth it, since they can already
wreck
+ // havoc via weaving anyway. However, we do
pass the
+ // snapshot values into the woven class when
we mark it
+ // as complete so that it will refect the
actual values
+ // we used to define the class.
+ if (wci != null)
{
- deferredList = new ArrayList();
- m_deferredActivation.set(deferredList);
+ bytes = wovenBytes = wci.getBytes();
+ wovenImports =
wci.getDynamicImportsInternal();
+
+ // Try to add any woven dynamic imports,
since they
+ // could potentially be needed when
defining the class.
+ List<BundleRequirement> allWovenReqs =
+ new ArrayList<BundleRequirement>();
+ for (String s : wovenImports)
+ {
+ try
+ {
+ List<BundleRequirement> wovenReqs =
+
ManifestParser.parseDynamicImportHeader(
+ m_logger, m_revision, s);
+ allWovenReqs.addAll(wovenReqs);
+ }
+ catch (BundleException ex)
+ {
+ // There should be no exception
here
+ // since we checked syntax before
adding
+ // dynamic import strings to list.
+ }
+ }
+ // Add the dynamic requirements.
+ if (!allWovenReqs.isEmpty())
+ {
+ // Check for duplicate woven imports.
+ // First grab existing woven imports,
if any.
+ Set<String> filters = new
HashSet<String>();
+ if (m_wovenReqs != null)
+ {
+ for (BundleRequirement req :
m_wovenReqs)
+ {
+ filters.add(
+ ((BundleRequirementImpl)
req)
+
.getFilter().toString());
+ }
+ }
+ // Then check new woven imports for
duplicates
+ // against existing and self.
+ int idx = allWovenReqs.size();
+ while (idx < allWovenReqs.size())
+ {
+ BundleRequirement wovenReq =
allWovenReqs.get(idx);
+ String filter =
((BundleRequirementImpl)
+
wovenReq).getFilter().toString();
+ if (!filters.contains(filter))
+ {
+ filters.add(filter);
+ idx++;
+ }
+ else
+ {
+ allWovenReqs.remove(idx);
+ }
+ }
+ // Merge existing with new imports, if
any.
+ if (!allWovenReqs.isEmpty())
+ {
+ if (m_wovenReqs != null)
+ {
+ allWovenReqs.addAll(0,
m_wovenReqs);
+ }
+ m_wovenReqs = allWovenReqs;
+ }
+ }
}
- deferredList.add(new Object[] { name,
getBundle() });
- }
- // We need to try to define a Package object for
the class
- // before we call defineClass() if we haven't
already
- // created it.
- if (pkgName.length() > 0)
- {
- if (getPackage(pkgName) == null)
+
+ int activationPolicy =
+ ((BundleImpl)
getBundle()).isDeclaredActivationPolicyUsed()
+ ? ((BundleRevisionImpl) ((BundleImpl)
getBundle())
+
.getCurrentRevision()).getDeclaredActivationPolicy()
+ : EAGER_ACTIVATION;
+
+ // If the revision is using deferred
activation, then if
+ // we load this class from this revision we
need to activate
+ // the bundle before returning the class. We
will short
+ // circuit the trigger matching if the trigger
is already
+ // tripped.
+ boolean isTriggerClass =
m_isActivationTriggered
+ ? false :
m_revision.isActivationTrigger(pkgName);
+ if (!m_isActivationTriggered
+ && isTriggerClass
+ && (activationPolicy ==
BundleRevisionImpl.LAZY_ACTIVATION)
+ && (getBundle().getState() ==
Bundle.STARTING))
{
- Object[] params = definePackage(pkgName);
- if (params != null)
+ List deferredList = (List)
m_deferredActivation.get();
+ if (deferredList == null)
{
- definePackage(
- pkgName,
- (String) params[0],
- (String) params[1],
- (String) params[2],
- (String) params[3],
- (String) params[4],
- (String) params[5],
- null);
+ deferredList = new ArrayList();
+ m_deferredActivation.set(deferredList);
}
- else
+ deferredList.add(new Object[] { name,
getBundle() });
+ }
+ // We need to try to define a Package object
for the class
+ // before we call defineClass() if we haven't
already
+ // created it.
+ if (pkgName.length() > 0)
+ {
+ if (getPackage(pkgName) == null)
{
- definePackage(pkgName, null, null,
- null, null, null, null, null);
+ Object[] params =
definePackage(pkgName);
+ if (params != null)
+ {
+ definePackage(
+ pkgName,
+ (String) params[0],
+ (String) params[1],
+ (String) params[2],
+ (String) params[3],
+ (String) params[4],
+ (String) params[5],
+ null);
+ }
+ else
+ {
+ definePackage(pkgName, null, null,
+ null, null, null, null, null);
+ }
}
}
- }
- // If we can load the class from a dex file do so
- if (content instanceof JarContent)
- {
- try
+ // If we can load the class from a dex file do
so
+ if (content instanceof JarContent)
{
- clazz = getDexFileClass((JarContent)
content, name, this);
- }
- catch (Exception ex)
- {
- // Looks like we can't
+ try
+ {
+ clazz = getDexFileClass((JarContent)
content, name, this);
+ }
+ catch (Exception ex)
+ {
+ // Looks like we can't
+ }
}
- }
- if (clazz == null)
- {
- // If we have a security context, then use it
to
- // define the class with it for security
purposes,
- // otherwise define the class without a
protection domain.
- if (m_revision.getProtectionDomain() != null)
+ if (clazz == null)
{
- clazz = defineClass(name, bytes, 0,
bytes.length,
- m_revision.getProtectionDomain());
+ // If we have a security context, then use
it to
+ // define the class with it for security
purposes,
+ // otherwise define the class without a
protection domain.
+ if (m_revision.getProtectionDomain() !=
null)
+ {
+ clazz = defineClass(name, bytes, 0,
bytes.length,
+ m_revision.getProtectionDomain());
+ }
+ else
+ {
+ clazz = defineClass(name, bytes, 0,
bytes.length);
+ }
+
+ wovenClass = clazz;
}
- else
+
+ // At this point if we have a trigger class,
then the deferred
+ // activation trigger has tripped.
+ if (!m_isActivationTriggered && isTriggerClass
&& (clazz != null))
{
- clazz = defineClass(name, bytes, 0,
bytes.length);
+// TODO: OSGi R4.3 - This isn't protected by the correct lock.
+ m_isActivationTriggered = true;
}
}
-
- // At this point if we have a trigger class, then
the deferred
- // activation trigger has tripped.
- if (!m_isActivationTriggered && isTriggerClass &&
(clazz != null))
+ }
+ finally
+ {
+ // If we have a woven class, mark it as complete.
+ // Not exactly clear how we should deal with the
+ // case where the weaving didn't happen because
+ // someone else beat us in defining the class.
+ if (wci != null)
{
-// TODO: OSGi R4.3 - This isn't protected by the correct lock.
- m_isActivationTriggered = true;
+ wci.complete(wovenClass, wovenBytes,
wovenImports);
}
}
}
@@ -1449,7 +1625,7 @@ public class BundleWiringImpl implements
{
try
{
- ((BundleImpl) ((Object[])
deferredList.get(i))[1]).getFramework().activateBundle(
+ felix.getFramework().activateBundle(
(BundleImpl) ((Object[])
deferredList.get(i))[1], true);
}
catch (BundleException ex)
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL:
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=1127155&r1=1127154&r2=1127155&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
(original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
Tue May 24 17:23:15 2011
@@ -3234,6 +3234,25 @@ public class Felix extends BundleImpl im
}
//
+ // Hook service management methods.
+ //
+
+ boolean isHookBlackListed(ServiceReference sr)
+ {
+ return m_registry.isHookBlackListed(sr);
+ }
+
+ void blackListHook(ServiceReference sr)
+ {
+ m_registry.blackListHook(sr);
+ }
+
+ public <S> SortedSet<ServiceReference<S>> getHooks(Class<S> hookClass)
+ {
+ return m_registry.getHooks(hookClass);
+ }
+
+ //
// PackageAdmin related methods.
//
@@ -3979,7 +3998,7 @@ public class Felix extends BundleImpl im
/**
* Fires bundle events.
**/
- private void fireFrameworkEvent(
+ void fireFrameworkEvent(
int type, Bundle bundle, Throwable throwable)
{
m_dispatcher.fireFrameworkEvent(new FrameworkEvent(type, bundle,
throwable));
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
URL:
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java?rev=1127155&r1=1127154&r2=1127155&view=diff
==============================================================================
---
felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
(original)
+++
felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
Tue May 24 17:23:15 2011
@@ -25,6 +25,7 @@ import org.apache.felix.framework.wiring
import org.osgi.framework.*;
import org.osgi.framework.hooks.service.*;
+import org.osgi.framework.hooks.weaving.WeavingHook;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.wiring.BundleCapability;
@@ -46,9 +47,21 @@ public class ServiceRegistry
private final ServiceRegistryCallbacks m_callbacks;
- private final Set m_eventHooks = new TreeSet(Collections.reverseOrder());
- private final Set m_findHooks = new TreeSet(Collections.reverseOrder());
- private final Set m_listenerHooks = new
TreeSet(Collections.reverseOrder());
+ private final WeakHashMap<ServiceReference, ServiceReference> m_blackList =
+ new WeakHashMap<ServiceReference, ServiceReference>();
+
+ private final Class<?>[] m_hookClasses = {
+ WeavingHook.class
+ };
+ private final Map<Class<?>, Set<ServiceReference<?>>> m_allHooks =
+ new HashMap<Class<?>, Set<ServiceReference<?>>>();
+
+ private final Set<ServiceReference> m_eventHooks =
+ new TreeSet<ServiceReference>(Collections.reverseOrder());
+ private final Set<ServiceReference> m_findHooks =
+ new TreeSet<ServiceReference>(Collections.reverseOrder());
+ private final Set<ServiceReference> m_listenerHooks =
+ new TreeSet<ServiceReference>(Collections.reverseOrder());
public ServiceRegistry(Logger logger, ServiceRegistryCallbacks callbacks)
{
@@ -92,7 +105,7 @@ public class ServiceRegistry
// Create the service registration.
reg = new ServiceRegistrationImpl(
this, bundle, classNames, new Long(m_currentServiceId++),
svcObj, dict);
-
+
// Keep track of registered hooks.
addHooks(classNames, svcObj, reg.getReference());
@@ -445,7 +458,7 @@ public class ServiceRegistry
}
public synchronized Bundle[] getUsingBundles(ServiceReference ref)
- {
+ {
Bundle[] bundles = null;
for (Iterator iter = m_inUseMap.entrySet().iterator(); iter.hasNext();
)
{
@@ -637,8 +650,37 @@ public class ServiceRegistry
}
}
- private void addHooks(String[] classNames, Object svcObj, ServiceReference
ref)
+ //
+ // Hook-related methods.
+ //
+
+ boolean isHookBlackListed(ServiceReference sr)
{
+ return m_blackList.containsKey(sr);
+ }
+
+ void blackListHook(ServiceReference sr)
+ {
+ m_blackList.put(sr, sr);
+ }
+
+ private void addHooks(String[] classNames, Object svcObj,
ServiceReference<?> ref)
+ {
+ Class<?> hookClass = isHook(classNames, m_hookClasses, svcObj);
+ if (hookClass != null)
+ {
+ synchronized (m_allHooks)
+ {
+ Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+ if (hooks == null)
+ {
+ hooks = new HashSet<ServiceReference<?>>();
+ m_allHooks.put(hookClass, hooks);
+ }
+ hooks.add(ref);
+ }
+ }
+
if (isHook(classNames, EventHook.class, svcObj))
{
synchronized (m_eventHooks)
@@ -663,14 +705,47 @@ public class ServiceRegistry
}
}
}
-
+
+ static Class<?> isHook(String[] classNames, Class<?>[] hookClasses, Object
svcObj)
+ {
+ for (Class<?> hookClass : hookClasses)
+ {
+ // For a service factory, we can only match names.
+ if (svcObj instanceof ServiceFactory)
+ {
+ for (String className : classNames)
+ {
+ if (className.equals(hookClass.getName()))
+ {
+ return hookClass;
+ }
+ }
+ }
+
+ // For a service object, check if its class matches.
+ if (hookClass.isAssignableFrom(svcObj.getClass()))
+ {
+ // But still only if it is registered under that interface.
+ String hookName = hookClass.getName();
+ for (String className : classNames)
+ {
+ if (className.equals(hookName))
+ {
+ return hookClass;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
static boolean isHook(String[] classNames, Class hookClass, Object svcObj)
{
- if (svcObj instanceof ServiceFactory)
+ if (svcObj instanceof ServiceFactory)
{
return Arrays.asList(classNames).contains(hookClass.getName());
}
-
+
if (hookClass.isAssignableFrom(svcObj.getClass()))
{
String hookName = hookClass.getName();
@@ -690,16 +765,33 @@ public class ServiceRegistry
Object svcObj = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
.getRegistration().getService();
String [] classNames = (String[])
ref.getProperty(Constants.OBJECTCLASS);
-
- if (isHook(classNames, EventHook.class, svcObj))
+
+ Class hookClass = isHook(classNames, m_hookClasses, svcObj);
+ if (hookClass != null)
{
- synchronized (m_eventHooks)
+ synchronized (m_allHooks)
+ {
+ Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+ if (hooks != null)
+ {
+ hooks.remove(ref);
+ if (hooks.isEmpty())
+ {
+ m_allHooks.remove(hookClass);
+ }
+ }
+ }
+ }
+
+ if (isHook(classNames, EventHook.class, svcObj))
+ {
+ synchronized (m_eventHooks)
{
m_eventHooks.remove(ref);
}
}
-
- if (isHook(classNames, FindHook.class, svcObj))
+
+ if (isHook(classNames, FindHook.class, svcObj))
{
synchronized (m_findHooks)
{
@@ -716,6 +808,27 @@ public class ServiceRegistry
}
}
+ public <S> SortedSet<ServiceReference<S>> getHooks(Class<S> hookClass)
+ {
+ synchronized (m_allHooks)
+ {
+ Set<ServiceReference<?>> hooks = m_allHooks.get(hookClass);
+ if (hooks != null)
+ {
+ SortedSet sorted = new
TreeSet<ServiceReference<?>>(Collections.reverseOrder());
+ sorted.addAll(hooks);
+ return asTypedSortedSet(sorted);
+ }
+ return null;
+ }
+ }
+
+ private static <S> SortedSet<ServiceReference<S>> asTypedSortedSet(
+ SortedSet<ServiceReference<?>> ss)
+ {
+ return (SortedSet<ServiceReference<S>>) (SortedSet) ss;
+ }
+
public List getEventHooks()
{
synchronized (m_eventHooks)
@@ -739,21 +852,21 @@ public class ServiceRegistry
return new ArrayList(m_listenerHooks);
}
}
-
+
/**
* Invokes a Service Registry Hook
* @param ref The ServiceReference associated with the hook to be invoked,
the hook
* service object will be obtained through this object.
* @param framework The framework that is invoking the hook, typically the
Felix object.
- * @param callback This is a callback object that is invoked with the
actual hook object to
+ * @param callback This is a callback object that is invoked with the
actual hook object to
* be used, either the plain hook, or one obtained from the
ServiceFactory.
*/
public void invokeHook(
ServiceReference ref, Framework framework, InvokeHookCallback callback)
{
Object hook = getService(framework, ref);
-
- try
+
+ try
{
callback.invokeHook(hook);
}
@@ -762,12 +875,12 @@ public class ServiceRegistry
m_logger.log(ref, Logger.LOG_WARNING,
"Problem invoking Service Registry Hook", th);
}
- finally
+ finally
{
ungetService(framework, ref);
}
- }
-
+ }
+
private static class UsageCount
{
public int m_count = 0;
Added:
felix/trunk/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java?rev=1127155&view=auto
==============================================================================
---
felix/trunk/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
(added)
+++
felix/trunk/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
Tue May 24 17:23:15 2011
@@ -0,0 +1,311 @@
+/*
+ * 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.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import org.apache.felix.framework.util.manifestparser.ManifestParser;
+import org.apache.felix.framework.util.manifestparser.ParsedHeaderClause;
+import org.osgi.framework.Constants;
+import org.osgi.framework.hooks.weaving.WovenClass;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleWiring;
+
+class WovenClassImpl implements WovenClass, List<String>
+{
+ private final String m_className;
+ private final BundleWiring m_wiring;
+ private byte[] m_bytes;
+ private List<String> m_imports = new ArrayList<String>();
+ private Class m_definedClass = null;
+ private boolean m_isComplete = false;
+
+ /* package */ WovenClassImpl(String className, BundleWiring wiring, byte[]
bytes)
+ {
+ m_className = className;
+ m_wiring = wiring;
+ m_bytes = bytes;
+ }
+
+ synchronized void complete(Class definedClass, byte[] bytes, List<String>
imports)
+ {
+ m_isComplete = true;
+ m_definedClass = definedClass;
+ m_bytes = (bytes == null) ? m_bytes : bytes;
+ m_imports = (imports == null)
+ ? Collections.unmodifiableList(m_imports)
+ : Collections.unmodifiableList(imports);
+ }
+
+ public synchronized byte[] getBytes()
+ {
+ byte[] bytes = m_bytes;
+ if (m_isComplete)
+ {
+ bytes = new byte[m_bytes.length];
+ System.arraycopy(m_bytes, 0, bytes, 0, m_bytes.length);
+ }
+ return bytes;
+ }
+
+ public synchronized void setBytes(byte[] bytes)
+ {
+ if (m_isComplete)
+ {
+ throw new IllegalStateException(
+ "Cannot change bytes after class weaving is completed.");
+ }
+ else
+ {
+ m_bytes = bytes;
+ }
+ }
+
+ synchronized List<String> getDynamicImportsInternal()
+ {
+ return m_imports;
+ }
+
+ public synchronized List<String> getDynamicImports()
+ {
+ return this;
+ }
+
+ public synchronized boolean isWeavingComplete()
+ {
+ return m_isComplete;
+ }
+
+ public String getClassName()
+ {
+ return m_className;
+ }
+
+ public ProtectionDomain getProtectionDomain()
+ {
+ return ((BundleImpl)
m_wiring.getRevision().getBundle()).getProtectionDomain();
+ }
+
+ public synchronized Class<?> getDefinedClass()
+ {
+ return m_definedClass;
+ }
+
+ public BundleWiring getBundleWiring()
+ {
+ return m_wiring;
+ }
+
+ //
+ // List<String> implementation for dynamic imports.
+ //
+ // Design-wise this could be separated out into a separate type,
+ // but since it will only ever be used for this purpose it didn't
+ // appear to make much sense to introduce another type for it.
+
+ public synchronized int size()
+ {
+ return m_imports.size();
+ }
+
+ public synchronized boolean isEmpty()
+ {
+ return m_imports.isEmpty();
+ }
+
+ public synchronized boolean contains(Object o)
+ {
+ return m_imports.contains(o);
+ }
+
+ public synchronized Iterator<String> iterator()
+ {
+ return m_imports.iterator();
+ }
+
+ public synchronized Object[] toArray()
+ {
+ return m_imports.toArray();
+ }
+
+ public synchronized <T> T[] toArray(T[] ts)
+ {
+ return m_imports.toArray(ts);
+ }
+
+ public synchronized boolean add(String s)
+ {
+ if (s != null)
+ {
+ try
+ {
+ List<BundleRequirement> reqs =
+ ManifestParser.parseDynamicImportHeader(null, null, s);
+ }
+ catch (Exception ex)
+ {
+ RuntimeException re =
+ new IllegalArgumentException("Unable to parse dynamic
import.");
+ re.initCause(ex);
+ throw re;
+ }
+ return m_imports.add(s);
+ }
+ return false;
+ }
+
+ public synchronized boolean remove(Object o)
+ {
+ return m_imports.remove(o);
+ }
+
+ public synchronized boolean containsAll(Collection<?> collection)
+ {
+ return m_imports.containsAll(collection);
+ }
+
+ public synchronized boolean addAll(Collection<? extends String> collection)
+ {
+ for (String s : collection)
+ {
+ try
+ {
+ List<BundleRequirement> reqs =
+ ManifestParser.parseDynamicImportHeader(null, null, s);
+ }
+ catch (Exception ex)
+ {
+ RuntimeException re =
+ new IllegalArgumentException("Unable to parse dynamic
import.");
+ re.initCause(ex);
+ throw re;
+ }
+ }
+ return m_imports.addAll(collection);
+ }
+
+ public synchronized boolean addAll(int i, Collection<? extends String>
collection)
+ {
+ for (String s : collection)
+ {
+ try
+ {
+ List<BundleRequirement> reqs =
+ ManifestParser.parseDynamicImportHeader(null, null, s);
+ }
+ catch (Exception ex)
+ {
+ RuntimeException re =
+ new IllegalArgumentException("Unable to parse dynamic
import.");
+ re.initCause(ex);
+ throw re;
+ }
+ }
+ return m_imports.addAll(i, collection);
+ }
+
+ public synchronized boolean removeAll(Collection<?> collection)
+ {
+ return m_imports.removeAll(collection);
+ }
+
+ public synchronized boolean retainAll(Collection<?> collection)
+ {
+ return m_imports.retainAll(collection);
+ }
+
+ public synchronized void clear()
+ {
+ m_imports.clear();
+ }
+
+ public synchronized String get(int i)
+ {
+ return m_imports.get(i);
+ }
+
+ public synchronized String set(int i, String s)
+ {
+ try
+ {
+ List<BundleRequirement> reqs =
+ ManifestParser.parseDynamicImportHeader(null, null, s);
+ }
+ catch (Exception ex)
+ {
+ RuntimeException re =
+ new IllegalArgumentException("Unable to parse dynamic
import.");
+ re.initCause(ex);
+ throw re;
+ }
+ return m_imports.set(i, s);
+ }
+
+ public synchronized void add(int i, String s)
+ {
+ try
+ {
+ List<BundleRequirement> reqs =
+ ManifestParser.parseDynamicImportHeader(null, null, s);
+ }
+ catch (Exception ex)
+ {
+ RuntimeException re =
+ new IllegalArgumentException("Unable to parse dynamic
import.");
+ re.initCause(ex);
+ throw re;
+ }
+ m_imports.add(i, s);
+ }
+
+ public synchronized String remove(int i)
+ {
+ return m_imports.remove(i);
+ }
+
+ public synchronized int indexOf(Object o)
+ {
+ return m_imports.indexOf(o);
+ }
+
+ public synchronized int lastIndexOf(Object o)
+ {
+ return m_imports.lastIndexOf(o);
+ }
+
+ public synchronized ListIterator<String> listIterator()
+ {
+ return m_imports.listIterator();
+ }
+
+ public synchronized ListIterator<String> listIterator(int i)
+ {
+ return m_imports.listIterator(i);
+ }
+
+ public synchronized List<String> subList(int i, int i1)
+ {
+ return m_imports.subList(i, i1);
+ }
+}
\ No newline at end of file
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
URL:
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java?rev=1127155&r1=1127154&r2=1127155&view=diff
==============================================================================
---
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
(original)
+++
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
Tue May 24 17:23:15 2011
@@ -367,6 +367,17 @@ public class ManifestParser
return clauses;
}
+ public static List<BundleRequirement> parseDynamicImportHeader(
+ Logger logger, BundleRevision owner, String header)
+ throws BundleException
+ {
+
+ List<ParsedHeaderClause> importClauses = parseStandardHeader(header);
+ importClauses = normalizeDynamicImportClauses(logger, importClauses,
"2");
+ List<BundleRequirement> reqs = convertImports(importClauses, owner);
+ return reqs;
+ }
+
private static List<BundleRequirement> convertImports(
List<ParsedHeaderClause> clauses, BundleRevision owner)
{