Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/FilteredServiceListener.java')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/FilteredServiceListener.java205
1 files changed, 205 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/FilteredServiceListener.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/FilteredServiceListener.java
new file mode 100644
index 000000000..528d8d2e6
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/FilteredServiceListener.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.internal.serviceregistry;
+
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.internal.core.BundleContextImpl;
+import org.eclipse.osgi.framework.internal.core.FilterImpl;
+import org.osgi.framework.*;
+import org.osgi.framework.hooks.service.ListenerHook;
+
+/**
+ * Service Listener delegate.
+ */
+class FilteredServiceListener implements ServiceListener, ListenerHook.ListenerInfo {
+ /** Filter for listener. */
+ private final FilterImpl filter;
+ /** Real listener. */
+ private final ServiceListener listener;
+ /** The bundle context */
+ private final BundleContextImpl context;
+ /** is this an AllServiceListener */
+ private final boolean allservices;
+ /** is this an UnfilteredServiceListener */
+ private final boolean unfiltered;
+ /** an objectClass required by the filter */
+ private final String objectClass;
+ /** indicates whether the listener has been removed */
+ private volatile boolean removed;
+
+ /**
+ * Constructor.
+ *
+ * @param context The bundle context of the bundle which added the specified service listener.
+ * @param filterstring The filter string specified when this service listener was added.
+ * @param listener The service listener object.
+ * @exception InvalidSyntaxException if the filter is invalid.
+ */
+ FilteredServiceListener(final BundleContextImpl context, final ServiceListener listener, final String filterstring) throws InvalidSyntaxException {
+ this.unfiltered = (listener instanceof UnfilteredServiceListener);
+ if (filterstring == null) {
+ this.filter = null;
+ this.objectClass = null;
+ } else {
+ FilterImpl filterImpl = FilterImpl.newInstance(filterstring);
+ String clazz = filterImpl.getRequiredObjectClass();
+ if (unfiltered || (clazz == null)) {
+ this.objectClass = null;
+ this.filter = filterImpl;
+ } else {
+ this.objectClass = clazz.intern(); /*intern the name for future identity comparison */
+ this.filter = filterstring.equals(getObjectClassFilterString(this.objectClass)) ? null : filterImpl;
+ }
+ }
+ this.removed = false;
+ this.listener = listener;
+ this.context = context;
+ this.allservices = (listener instanceof AllServiceListener);
+ }
+
+ /**
+ * Receives notification that a service has had a lifecycle change.
+ *
+ * @param event The <code>ServiceEvent</code> object.
+ */
+ public void serviceChanged(ServiceEvent event) {
+ ServiceReferenceImpl<?> reference = (ServiceReferenceImpl<?>) event.getServiceReference();
+
+ // first check if we can short circuit the filter match if the required objectClass does not match the event
+ objectClassCheck: if (objectClass != null) {
+ String[] classes = reference.getClasses();
+ int size = classes.length;
+ for (int i = 0; i < size; i++) {
+ if (classes[i] == objectClass) // objectClass strings have previously been interned for identity comparison
+ break objectClassCheck;
+ }
+ return; // no class in this event matches a required part of the filter; we do not need to deliver this event
+ }
+ // TODO could short circuit service.id filters as well since the id is constant for a registration.
+
+ if (!ServiceRegistry.hasListenServicePermission(event, context))
+ return;
+
+ if (Debug.DEBUG_EVENTS) {
+ String listenerName = this.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(this)); //$NON-NLS-1$
+ Debug.println("filterServiceEvent(" + listenerName + ", \"" + getFilter() + "\", " + reference.getRegistration().getProperties() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ event = filterMatch(event);
+ if (event == null) {
+ return;
+ }
+ if (allservices || ServiceRegistry.isAssignableTo(context, reference)) {
+ if (Debug.DEBUG_EVENTS) {
+ String listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
+ Debug.println("dispatchFilteredServiceEvent(" + listenerName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ listener.serviceChanged(event);
+ }
+ }
+
+ /**
+ * Returns a service event that should be delivered to the listener based on the filter evaluation.
+ * This may result in a service event of type MODIFIED_ENDMATCH.
+ *
+ * @param delivered The service event delivered by the framework.
+ * @return The event to be delivered or null if no event is to be delivered to the listener.
+ */
+ private ServiceEvent filterMatch(ServiceEvent delivered) {
+ boolean modified = delivered.getType() == ServiceEvent.MODIFIED;
+ ServiceEvent event = modified ? ((ModifiedServiceEvent) delivered).getModifiedEvent() : delivered;
+ if (unfiltered || (filter == null)) {
+ return event;
+ }
+ ServiceReference<?> reference = event.getServiceReference();
+ if (filter.match(reference)) {
+ return event;
+ }
+ if (modified) {
+ ModifiedServiceEvent modifiedServiceEvent = (ModifiedServiceEvent) delivered;
+ if (modifiedServiceEvent.matchPreviousProperties(filter)) {
+ return modifiedServiceEvent.getModifiedEndMatchEvent();
+ }
+ }
+ // does not match and did not match previous properties; do not send event
+ return null;
+ }
+
+ /**
+ * The string representation of this Filtered listener.
+ *
+ * @return The string representation of this listener.
+ */
+ public String toString() {
+ String filterString = getFilter();
+ if (filterString == null) {
+ filterString = ""; //$NON-NLS-1$
+ }
+ return listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)) + filterString; //$NON-NLS-1$
+ }
+
+ /**
+ * Return the bundle context for the ListenerHook.
+ * @return The context of the bundle which added the service listener.
+ * @see org.osgi.framework.hooks.service.ListenerHook.ListenerInfo#getBundleContext()
+ */
+ public BundleContext getBundleContext() {
+ return context;
+ }
+
+ /**
+ * Return the filter string for the ListenerHook.
+ * @return The filter string with which the listener was added. This may
+ * be <code>null</code> if the listener was added without a filter.
+ * @see org.osgi.framework.hooks.service.ListenerHook.ListenerInfo#getFilter()
+ */
+ public String getFilter() {
+ if (filter != null) {
+ return filter.toString();
+ }
+ return getObjectClassFilterString(objectClass);
+ }
+
+ /**
+ * Return the state of the listener for this addition and removal life
+ * cycle. Initially this method will return <code>false</code>
+ * indicating the listener has been added but has not been removed.
+ * After the listener has been removed, this method must always return
+ * <code>true</code>.
+ *
+ * @return <code>false</code> if the listener has not been been removed,
+ * <code>true</code> otherwise.
+ */
+ public boolean isRemoved() {
+ return removed;
+ }
+
+ /**
+ * Mark the service listener registration as removed.
+ */
+ void markRemoved() {
+ removed = true;
+ }
+
+ /**
+ * Returns an objectClass filter string for the specified class name.
+ * @return A filter string for the specified class name or <code>null</code> if the
+ * specified class name is <code>null</code>.
+ */
+ private static String getObjectClassFilterString(String className) {
+ if (className == null) {
+ return null;
+ }
+ return "(" + Constants.OBJECTCLASS + "=" + className + ")"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+}

Back to the top