diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java
index 81c1a7ce3e..0e22a72471 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -18,24 +18,19 @@
*/
package org.apache.felix.ipojo.context;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.*;
+
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
-
-import org.apache.felix.ipojo.ComponentInstance;
-import org.apache.felix.ipojo.util.Logger;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Internal Service Registry. This class is used for in the composition.
- *
+ *
* @author Felix Project Team
*/
public class ServiceRegistry {
@@ -43,73 +38,51 @@ public class ServiceRegistry {
/**
* Service Id index.
*/
- private long m_serviceId = 1L;
-
- /**
- * List of service listeners.
- */
- private List m_listeners = new ArrayList(); // ListenerInfo List
-
- /**
- * List of service registration.
- */
- private List m_regs = new ArrayList();
-
+ private final AtomicLong mServiceId = new AtomicLong(1L);
/**
* A "real" bundle context to create LDAP filter.
*/
- private BundleContext m_context; // BundleContext to create Filter
-
+ private final BundleContext mContext; // BundleContext to create Filter
/**
* Registry logger.
*/
- private Logger m_logger;
-
+ private final Logger mLogger;
/**
- * Listener info structure.
+ * List of service listeners. It is enough to use nonblocking thread-safe collection
*/
- private static class ListenerInfo {
- /**
- * Listener object.
- */
- private ServiceListener m_listener;
- /**
- * Filter associated with the filter.
- */
- private Filter m_filter;
- }
+ private List mListeners = new CopyOnWriteArrayList<>(); // ListenerInfo List
+ /**
+ * List of service registration. It is enough to use nonblocking thread-safe collection
+ */
+ private List mRegs = new CopyOnWriteArrayList<>();
/**
* Constructor.
- *
+ *
* @param context : bundle context.
*/
public ServiceRegistry(BundleContext context) {
- m_context = context;
- m_logger = new Logger(m_context, "Registry logger " + m_context.getBundle().getBundleId());
+ mContext = context;
+ mLogger = new Logger(mContext, "Registry logger " + mContext.getBundle().getBundleId());
}
/**
* Add a given service listener with no filter.
- *
+ *
* @param arg0 : the service listener to add
*/
public void addServiceListener(ServiceListener arg0) {
- ListenerInfo info = new ListenerInfo();
- info.m_listener = arg0;
- info.m_filter = null;
- m_listeners.add(info);
+ mListeners.add(new ListenerInfo(arg0, null));
}
/**
* Unget a service.
- *
+ *
* @param instance : instance releasing the service.
- * @param ref : released reference.
+ * @param ref : released reference.
* @return true if the unget success
*/
public boolean ungetService(ComponentInstance instance, ServiceReference ref) {
-
ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
if (reg.isValid()) {
reg.ungetService(instance, reg.getService());
@@ -121,184 +94,171 @@ public boolean ungetService(ComponentInstance instance, ServiceReference ref) {
/**
* Unregister a service listener.
- *
+ *
* @param arg0 : the service listener to remove
*/
public void removeServiceListener(ServiceListener arg0) {
- m_listeners.remove(arg0);
+ mListeners.removeIf(listenerInfo -> listenerInfo.mListener == arg0);
}
/**
* Register a service.
- *
+ *
* @param instance : provider instance.
- * @param clazz : provided interface.
- * @param svcObj : service object of service factory object.
- * @param dict : service properties.
+ * @param clazz : provided interface.
+ * @param svcObj : service object of service factory object.
+ * @param dict : service properties.
* @return the created service registration.
*/
public ServiceRegistration registerService(ComponentInstance instance, String clazz, Object svcObj, Dictionary dict) {
- synchronized (m_regs) {
- ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, instance, new String[] { clazz }, new Long(m_serviceId++), svcObj, dict);
- m_regs.add(reg);
- fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
- return reg;
- }
+ final ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, instance, new String[]{clazz}, mServiceId.getAndIncrement(), svcObj, dict);
+ mRegs.add(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+ return reg;
}
/**
* Register a service.
- *
+ *
* @param instance : provider instance.
- * @param clazzes : provided interfaces.
- * @param svcObj : service object of service factory object.
- * @param dict : service properties.
+ * @param clazzes : provided interfaces.
+ * @param svcObj : service object of service factory object.
+ * @param dict : service properties.
* @return the created service registration.
*/
public ServiceRegistration registerService(ComponentInstance instance, String[] clazzes, Object svcObj, Dictionary dict) {
- synchronized (m_regs) {
- ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, instance, clazzes, new Long(m_serviceId++), svcObj, dict);
- m_regs.add(reg);
- fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
- return reg;
- }
+ final ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, instance, clazzes, mServiceId.getAndIncrement(), svcObj, dict);
+ mRegs.add(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+ return reg;
}
/**
* Dispatch a service event.
+ *
* @param event : the service to dispatch
*/
private void fireServiceChanged(ServiceEvent event) {
- synchronized (m_listeners) {
- // Iterate on the service listener list to notify service listener
- for (int i = 0; i < m_listeners.size(); i++) {
- ListenerInfo info = (ListenerInfo) m_listeners.get(i);
- ServiceReference ref = event.getServiceReference();
- if (info.m_filter == null) {
- info.m_listener.serviceChanged(event);
- }
- Dictionary props = ((ServiceReferenceImpl) ref).getProperties();
- if (info.m_filter != null && info.m_filter.match(props)) {
- info.m_listener.serviceChanged(event);
- }
+ for (ListenerInfo listenerInfo : mListeners) {
+ final ServiceReference ref = event.getServiceReference();
+ if (listenerInfo.mFilter == null) {
+ listenerInfo.mListener.serviceChanged(event);
+ }
+ Dictionary props = ((ServiceReferenceImpl) ref).getProperties();
+ if (listenerInfo.mFilter != null && listenerInfo.mFilter.match(props)) {
+ listenerInfo.mListener.serviceChanged(event);
}
}
+
}
/**
* Get available (and accessible) service references.
- *
+ *
* @param className : required interface
- * @param expr : LDAP filter
+ * @param expr : LDAP filter
* @return : the list of available service references.
- * @throws InvalidSyntaxException
- * occurs when the LDAP filter is malformed.
+ * @throws InvalidSyntaxException occurs when the LDAP filter is malformed.
*/
public ServiceReference[] getServiceReferences(String className, String expr) throws InvalidSyntaxException {
- synchronized (m_regs) {
- // Define filter if expression is not null.
- Filter filter = null;
- if (expr != null) {
- filter = m_context.createFilter(expr);
- }
-
- List refs = new ArrayList();
-
- for (int i = 0; i < m_regs.size(); i++) {
- ServiceRegistrationImpl reg = (ServiceRegistrationImpl) m_regs.get(i);
- // Determine if the registered services matches the search
- // criteria.
- boolean matched = false;
+ // Define filter if expression is not null.
+ Filter filter = null;
+ if (expr != null) {
+ filter = mContext.createFilter(expr);
+ }
+ final List> refs = new ArrayList<>();
+ for (ServiceRegistration m_reg : mRegs) {
+ ServiceRegistrationImpl reg = (ServiceRegistrationImpl) m_reg;
+ // Determine if the registered services matches the search
+ // criteria.
+ boolean matched = false;
- // If className is null, then look at filter only.
- if ((className == null) && ((filter == null) || filter.match(reg.getProperties()))) {
- matched = true;
- } else if (className != null) {
- // If className is not null, then first match the
- // objectClass property before looking at the
- // filter.
- Dictionary props = ((ServiceRegistrationImpl) reg).getProperties();
- String[] objectClass = (String[]) props.get(Constants.OBJECTCLASS);
- for (int classIdx = 0; classIdx < objectClass.length; classIdx++) {
- if (objectClass[classIdx].equals(className) && ((filter == null) || filter.match(props))) {
- matched = true;
- break;
- }
+ // If className is null, then look at filter only.
+ if ((className == null) && ((filter == null) || filter.match(reg.getProperties()))) {
+ matched = true;
+ } else if (className != null) {
+ // If className is not null, then first match the
+ // objectClass property before looking at the
+ // filter.
+ Dictionary props = reg.getProperties();
+ String[] objectClass = (String[]) props.get(Constants.OBJECTCLASS);
+ for (String aClass : objectClass) {
+ if (aClass.equals(className) && ((filter == null) || filter.match(props))) {
+ matched = true;
+ break;
}
}
-
- // Add reference if it was a match.
- if (matched) {
- refs.add(reg.getReference());
- }
}
- if (! refs.isEmpty()) {
- return (ServiceReference[]) refs.toArray(new ServiceReference[refs.size()]);
+ // Add reference if it was a match.
+ if (matched) {
+ refs.add(reg.getReference());
}
- return null;
}
+
+ if (!refs.isEmpty()) {
+ return refs.toArray(new ServiceReference[refs.size()]);
+ }
+ // To be honest it is not good. But it is stayed for compatibility
+ return null;
}
/**
* Look for a service reference.
- *
+ *
* @param clazz : required interface.
* @return the first available provider or null if none available.
*/
public ServiceReference getServiceReference(String clazz) {
- synchronized (m_regs) {
- try {
- ServiceReference[] refs = getServiceReferences(clazz, null);
- if (refs != null) {
- return refs[0];
- } // If the refs != null we are sure that it exists one reference or more.
- } catch (InvalidSyntaxException ex) {
- // Cannot happen : null filter.
- }
- return null;
+ try {
+ ServiceReference[] refs = getServiceReferences(clazz, null);
+ if (refs != null) {
+ return refs[0];
+ } // If the refs != null we are sure that it exists one reference or more.
+ } catch (InvalidSyntaxException ex) {
+ // Cannot happen : null filter.
}
+ return null;
}
/**
* Get a service object.
+ *
* @param instance : component instance requiring the service.
- * @param ref : the required reference.
+ * @param ref : the required reference.
* @return the service object.
*/
public Object getService(ComponentInstance instance, ServiceReference ref) {
- synchronized (m_regs) {
- // Look for the service registration for this ref
- ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
- if (reg.isValid()) {
- // Delegate the service providing to the service registration
- return reg.getService();
- } else {
- return null;
- }
+ // Look for the service registration for this ref
+ ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+ if (reg.isValid()) {
+ // Delegate the service providing to the service registration
+ return reg.getService();
+ } else {
+ return null;
}
}
/**
* Get all service references consistent with the given interface and
* filter.
- * @param clazz : the required interface.
+ *
+ * @param clazz : the required interface.
* @param filter : the LDAP filter.
* @return the list of all service reference or null if none available.
* @throws InvalidSyntaxException occurs when the LDAP filter is malformed.
*/
public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
- synchronized (m_regs) {
- // Can delegate on getServiceReference, indeed their is no test on
- // the "modularity" conflict.
- return getServiceReferences(clazz, filter);
- }
+ // Can delegate on getServiceReference, indeed their is no test on
+ // the "modularity" conflict.
+ return getServiceReferences(clazz, filter);
}
/**
* Add a service listener with a filter.
+ *
* @param listener : the service listener to add
- * @param filter : LDAP filter
+ * @param filter : LDAP filter
*/
public void addServiceListener(ServiceListener listener, String filter) {
// If the filter is null, subscribe with no filter.
@@ -306,20 +266,19 @@ public void addServiceListener(ServiceListener listener, String filter) {
addServiceListener(listener);
return;
}
-
+
try {
- ListenerInfo info = new ListenerInfo();
- info.m_listener = listener;
- info.m_filter = m_context.createFilter(filter);
- m_listeners.add(info);
+ final ListenerInfo info = new ListenerInfo(listener, mContext.createFilter(filter));
+ mListeners.add(info);
} catch (InvalidSyntaxException ex) {
- m_logger.log(Logger.ERROR, ex.getMessage(), ex);
+ mLogger.log(Logger.ERROR, ex.getMessage(), ex);
}
-
+
}
/**
* Dispatch a service properties modified event.
+ *
* @param reg : the implicated service registration.
*/
public void servicePropertiesModified(ServiceRegistrationImpl reg) {
@@ -328,19 +287,41 @@ public void servicePropertiesModified(ServiceRegistrationImpl reg) {
/**
* Unregister a service.
+ *
* @param reg : the service registration to unregister
*/
public void unregisterService(ServiceRegistrationImpl reg) {
- m_regs.remove(reg);
- fireServiceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()));
+ // We should fire event only if registration is removed
+ if (mRegs.remove(reg)) {
+ fireServiceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()));
+ }
}
/**
* Reset the service registry.
*/
public void reset() {
- m_serviceId = 1L;
- m_listeners = new ArrayList();
- m_regs = new ArrayList();
+ mServiceId.set(1L);
+ mListeners = new CopyOnWriteArrayList<>();
+ mRegs = new CopyOnWriteArrayList<>();
+ }
+
+ /**
+ * Listener info structure.
+ */
+ private static class ListenerInfo {
+ /**
+ * Listener object.
+ */
+ private final ServiceListener mListener;
+ /**
+ * Filter associated with the filter.
+ */
+ private final Filter mFilter;
+
+ private ListenerInfo(ServiceListener mListener, Filter mFilter) {
+ this.mListener = mListener;
+ this.mFilter = mFilter;
+ }
}
}