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; + } } }