forked from apache/felix
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from TheItivitist/ipojo-1.12.1-ullink
Improve internal event dispatcher
- Loading branch information
Showing
9 changed files
with
814 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,16 +19,23 @@ | |
package org.apache.felix.ipojo; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import org.apache.felix.ipojo.extender.ExtensionDeclaration; | ||
import org.apache.felix.ipojo.extender.InstanceDeclaration; | ||
import org.osgi.framework.AllServiceListener; | ||
import org.osgi.framework.Bundle; | ||
import org.osgi.framework.BundleContext; | ||
import org.osgi.framework.Constants; | ||
import org.osgi.framework.ServiceEvent; | ||
import org.osgi.framework.ServiceListener; | ||
import org.osgi.framework.ServiceReference; | ||
|
||
/** | ||
* iPOJO Internal event dispatcher. | ||
|
@@ -37,24 +44,154 @@ | |
* @author <a href="mailto:[email protected]">Felix Project Team</a> | ||
* @see org.osgi.framework.ServiceListener | ||
*/ | ||
public final class EventDispatcher implements ServiceListener { | ||
|
||
public final class EventDispatcher implements AllServiceListener | ||
{ | ||
static class ListenerKey | ||
{ | ||
private static final Pattern OBJECT_CLASS_FILTER = Pattern.compile("\\(object[cC]lass=(\\S+)\\)"); | ||
private static final Pattern HANDLER_TYPE_FILTER = Pattern.compile("\\(&\\(handler\\.type=primitive\\)\\(factory\\.state=1\\)\\)"); | ||
private static final Pattern EXTENSION_DECLARATION_FILTER = Pattern.compile("\\(&\\(object[cC]lass=org\\.apache\\.felix\\.ipojo\\.extender\\.ExtensionDeclaration\\)\\(ipojo\\.extension\\.name=(\\S+)\\)\\)"); | ||
private static final Pattern INSTANCE_DECLARATION_FILTER = Pattern.compile("\\(&\\(object[cC]lass=org\\.apache\\.felix\\.ipojo\\.extender\\.InstanceDeclaration\\)\\(\\|\\(ipojo\\.component\\.name=(\\S+)\\)\\(ipojo\\.component\\.name=(\\S+)\\)\\)\\(!\\(ipojo\\.component\\.version=\\*\\)\\)\\)"); | ||
private static final String EXTENSION_DECLARATION_CLASSNAME = "org.apache.felix.ipojo.extender.ExtensionDeclaration"; | ||
private static final String INSTANCE_DECLARATION_CLASSNAME = "org.apache.felix.ipojo.extender.InstanceDeclaration"; | ||
private static final String FACTORY_STATE = "factory.state"; | ||
|
||
static List<ListenerKey> build(String filter) { | ||
if (filter == null || filter.isEmpty()) { | ||
return null; | ||
} | ||
Matcher objectClassMatcher = OBJECT_CLASS_FILTER.matcher(filter); | ||
if (objectClassMatcher.matches()) { | ||
String objectClass = objectClassMatcher.group(1); | ||
return Collections.singletonList(new ListenerKey(objectClass, null, null, null, null, null)); | ||
} | ||
Matcher handlerTypeMatcher = HANDLER_TYPE_FILTER.matcher(filter); | ||
if (handlerTypeMatcher.matches()) { | ||
return Collections.singletonList(new ListenerKey(null, null, null, null, PrimitiveHandler.HANDLER_TYPE, Factory.VALID)); | ||
} | ||
Matcher extensionDeclarationMatcher = EXTENSION_DECLARATION_FILTER.matcher(filter); | ||
if (extensionDeclarationMatcher.matches()) { | ||
String extensionName = extensionDeclarationMatcher.group(1); | ||
return Collections.singletonList(new ListenerKey(EXTENSION_DECLARATION_CLASSNAME, extensionName, null, null, null, null)); | ||
} | ||
Matcher instanceDeclarationMatcher = INSTANCE_DECLARATION_FILTER.matcher(filter); | ||
if (instanceDeclarationMatcher.matches()) { | ||
String componentName1 = instanceDeclarationMatcher.group(1); | ||
String componentName2 = instanceDeclarationMatcher.group(2); | ||
return Arrays.asList( | ||
new ListenerKey(INSTANCE_DECLARATION_CLASSNAME, null, componentName1, false, null, null), | ||
new ListenerKey(INSTANCE_DECLARATION_CLASSNAME, null, componentName2, false, null, null) | ||
); | ||
} | ||
return null; | ||
} | ||
|
||
static List<ListenerKey> build(ServiceReference<?> serviceReference) { | ||
String[] objectClasses = (String[]) serviceReference.getProperty(Constants.OBJECTCLASS); | ||
String handlerType = (String) serviceReference.getProperty(Handler.HANDLER_TYPE_PROPERTY); | ||
List<ListenerKey> results = new ArrayList<ListenerKey>(objectClasses.length + (handlerType != null ? 1 : 0)); | ||
if (PrimitiveHandler.HANDLER_TYPE.equals(handlerType)) { | ||
Integer factoryState = (Integer) serviceReference.getProperty(FACTORY_STATE); | ||
if (factoryState != null && factoryState == Factory.VALID) { | ||
results.add(new ListenerKey(null, null, null, null, handlerType, factoryState)); | ||
} | ||
} | ||
for (String objectClass : objectClasses) { | ||
if (EXTENSION_DECLARATION_CLASSNAME.equals(objectClass)) { | ||
String extensionName = (String) serviceReference.getProperty(ExtensionDeclaration.EXTENSION_NAME_PROPERTY); | ||
results.add(new ListenerKey(objectClass, extensionName, null, null, null, null)); | ||
} else if (INSTANCE_DECLARATION_CLASSNAME.equals(objectClass)) { | ||
String componentName = (String) serviceReference.getProperty(InstanceDeclaration.COMPONENT_NAME_PROPERTY); | ||
String componentVersion = (String) serviceReference.getProperty(InstanceDeclaration.COMPONENT_VERSION_PROPERTY); | ||
results.add(new ListenerKey(objectClass, null, componentName, componentVersion != null && !componentVersion.isEmpty(), null, null)); | ||
} else { | ||
results.add(new ListenerKey(objectClass, null, null, null, null, null)); | ||
} | ||
} | ||
return results; | ||
} | ||
|
||
final String objectClass; | ||
final String extensionName; | ||
final String componentName; | ||
final Boolean componentVersion; | ||
final String handleType; | ||
final Integer factoryState; | ||
|
||
ListenerKey(String objectClass, String extensionName, String componentName, Boolean componentVersion, String handleType, Integer factoryState) { | ||
this.objectClass = objectClass; | ||
this.extensionName = extensionName; | ||
this.componentName = componentName; | ||
this.componentVersion = componentVersion; | ||
this.handleType = handleType; | ||
this.factoryState = factoryState; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o instanceof ListenerKey) { | ||
ListenerKey listenerKey = (ListenerKey) o; | ||
return objectClass != null ? objectClass.equals(listenerKey.objectClass) : listenerKey.objectClass == null | ||
&& extensionName != null ? extensionName.equals(listenerKey.extensionName) : listenerKey.extensionName == null | ||
&& componentName != null ? componentName.equals(listenerKey.componentName) : listenerKey.componentName == null | ||
&& (componentVersion == null || componentVersion.equals(listenerKey.componentVersion)) | ||
&& handleType != null ? handleType.equals(listenerKey.handleType) : listenerKey.handleType == null | ||
&& factoryState != null ? factoryState.equals(listenerKey.factoryState) : listenerKey.factoryState == null; | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = objectClass != null ? objectClass.hashCode() : 0; | ||
result = 31 * result + (extensionName != null ? extensionName.hashCode() : 0); | ||
result = 31 * result + (componentName != null ? componentName.hashCode() : 0); | ||
result = 31 * result + (componentVersion != null ? componentVersion.hashCode() : 0); | ||
result = 31 * result + (handleType != null ? handleType.hashCode() : 0); | ||
result = 31 * result + (factoryState != null ? factoryState.hashCode() : 0); | ||
return result; | ||
} | ||
} | ||
|
||
private static class ListenerInfo { | ||
private final Bundle bundle; | ||
private final ServiceListener listener; | ||
|
||
ListenerInfo(Bundle bundle, ServiceListener listener) { | ||
this.bundle = bundle; | ||
this.listener = listener; | ||
} | ||
|
||
Bundle getBundle() { | ||
return bundle; | ||
} | ||
|
||
ServiceListener getListener() { | ||
return listener; | ||
} | ||
} | ||
|
||
/** | ||
* The internal event dispatcher. | ||
* This dispatcher is a singleton. | ||
*/ | ||
private static EventDispatcher DISPATCHER; | ||
|
||
|
||
private static final ListenerInfo[] NO_LISTENERINFO = new ListenerInfo[0]; | ||
|
||
/** | ||
* The list of listeners. | ||
* Service interface -> List of {@link ServiceListener} | ||
*/ | ||
private Map m_listeners; | ||
private final Map<ListenerKey, List<ListenerInfo>> m_listeners; | ||
/** | ||
* The global bundle context. | ||
* This is the bundle context from iPOJO. | ||
*/ | ||
private BundleContext m_context; | ||
private final BundleContext m_context; | ||
|
||
/** | ||
* Creates the EventDispatcher. | ||
|
@@ -63,7 +200,7 @@ public final class EventDispatcher implements ServiceListener { | |
*/ | ||
private EventDispatcher(BundleContext bc) { | ||
m_context = bc; | ||
m_listeners = new HashMap(); | ||
m_listeners = new HashMap<ListenerKey, List<ListenerInfo>>(); | ||
// Only one thread can call the start method. | ||
m_context.addServiceListener(this); | ||
} | ||
|
@@ -122,60 +259,96 @@ private void stop() { | |
* @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent) | ||
*/ | ||
public void serviceChanged(ServiceEvent event) { | ||
String[] itfs = (String[]) event.getServiceReference().getProperty(Constants.OBJECTCLASS); | ||
for (int s = 0; s < itfs.length; s++) { | ||
List list; | ||
List<ListenerKey> listenerKeys = ListenerKey.build(event.getServiceReference()); | ||
for(ListenerKey listenerKey : listenerKeys) { | ||
ListenerInfo[] listenerInfos; | ||
synchronized (this) { | ||
List stored = (List) m_listeners.get(itfs[s]); | ||
if (stored == null) { | ||
return; // Nothing to do | ||
} | ||
// Creates a new list (stack confinement) | ||
list = new ArrayList(stored); | ||
List<ListenerInfo> list = m_listeners.get(listenerKey); | ||
listenerInfos = list == null || list.isEmpty() | ||
? null | ||
: list.toArray(NO_LISTENERINFO); | ||
} | ||
for (int i = 0; i < list.size(); i++) { | ||
((ServiceListener) list.get(i)).serviceChanged(event); | ||
fireServiceEvents(listenerKey.objectClass, listenerInfos, event); | ||
} | ||
} | ||
|
||
private void fireServiceEvents(String specification, ListenerInfo[] listenerInfos, ServiceEvent event) { | ||
if (listenerInfos != null) { | ||
for (ListenerInfo listenerInfo : listenerInfos) { | ||
fireServiceEvent(specification, listenerInfo.getListener(), listenerInfo.getBundle(), event); | ||
} | ||
} | ||
} | ||
|
||
|
||
private void fireServiceEvent(String specification, ServiceListener listener, Bundle bundle, ServiceEvent event) { | ||
if (canFireServiceEvent(specification, listener, bundle, event)) { | ||
listener.serviceChanged(event); | ||
} | ||
} | ||
|
||
private boolean canFireServiceEvent(String specification, ServiceListener listener, Bundle bundle, ServiceEvent event) { | ||
if (bundle == m_context.getBundle()) { | ||
return true; | ||
} | ||
int state = bundle.getState(); | ||
if (state != Bundle.ACTIVE && state != Bundle.STARTING && state != Bundle.STOPPING) { | ||
return false; | ||
} | ||
return listener instanceof AllServiceListener | ||
|| specification == null | ||
|| event.getServiceReference().isAssignableTo(bundle, specification); | ||
} | ||
|
||
/** | ||
* Adds a new service listener to the {@link EventDispatcher#m_listeners} | ||
* map. This method specifies the listen service interface | ||
* @param itf the service interface | ||
* @param filter the filter | ||
* @param bundle the bundle that is registering the listener | ||
* @param listener the service listener | ||
*/ | ||
public void addListener(String itf, ServiceListener listener) { | ||
public boolean addListener(String filter, Bundle bundle, ServiceListener listener) { | ||
List<ListenerKey> listenerKeys = ListenerKey.build(filter); | ||
if (listenerKeys == null) { | ||
return false; | ||
} | ||
ListenerInfo listenerInfo = new ListenerInfo(bundle, listener); | ||
synchronized (this) { | ||
List list = (List) m_listeners.get(itf); | ||
if (list == null) { | ||
list = new ArrayList(1); | ||
list.add(listener); | ||
m_listeners.put(itf, list); | ||
} else { | ||
list.add(listener); | ||
for (ListenerKey listenerKey : listenerKeys) { | ||
List<ListenerInfo> list = m_listeners.get(listenerKey); | ||
if (list == null) { | ||
list = new ArrayList(1); | ||
m_listeners.put(listenerKey, list); | ||
} | ||
list.add(listenerInfo); | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* Removes a service listener. | ||
* @param listener the service listener to remove | ||
* @return <code>true</code> if the listener is | ||
* successfully removed. | ||
*/ | ||
public boolean removeListener(ServiceListener listener) { | ||
boolean removed = false; | ||
synchronized (this) { | ||
Set keys = m_listeners.keySet(); | ||
Iterator it = keys.iterator(); | ||
while (it.hasNext()) { | ||
String itf = (String) it.next(); | ||
List list = (List) m_listeners.get(itf); | ||
removed = removed || list.remove(listener); | ||
boolean removed = false; | ||
for (List<ListenerInfo> listenerInfoList : m_listeners.values()) { | ||
removed = removeListener(listenerInfoList, listener) || removed; | ||
} | ||
return removed; | ||
} | ||
return removed; | ||
} | ||
|
||
private boolean removeListener(List<ListenerInfo> listenerInfoList, ServiceListener listener) { | ||
Iterator<ListenerInfo> iterator = listenerInfoList.iterator(); | ||
while (iterator.hasNext()) { | ||
if (iterator.next().getListener() == listener) { | ||
iterator.remove(); | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} |
Oops, something went wrong.