/** * 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.gecko.rsa.discovery; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; import org.gecko.rsa.core.converter.EndpointDescriptionConverter; import org.gecko.rsa.core.helper.FilterHelper; import org.gecko.rsa.model.rsa.EndpointDescription; import org.osgi.framework.ServiceReference; import org.osgi.service.remoteserviceadmin.EndpointEvent; import org.osgi.service.remoteserviceadmin.EndpointEventListener; /** * Manages the EndpointEventListeners and the scopes they are interested in. * Scopes are the {@link EndpointEventListener#ENDPOINT_LISTENER_SCOPE} properties in * service references. The are LDAP filter, that us than executed to match the properties of * service descriptions. * * Establishes a listener with the importing handler, to be called back on all changes in this handler. * Events from importing handler are then forwarded to all interested EndpointEventListeners, which are the topology managers. */ @SuppressWarnings({"rawtypes"}) public class ImportingEndpointEventManager implements EndpointEventListener { private static final Logger logger = Logger.getLogger(ImportingEndpointEventManager.class.getName()); private final EndpointDescriptionConverter converter = new EndpointDescriptionConverter(); private final ImportingEndpointManager importingManager; private final Map topologyManagers = new ConcurrentHashMap(); private final String discoveryId; protected static class Interest { List scopes; EndpointEventListener epListener; } public ImportingEndpointEventManager(ImportingEndpointManager importingHandler, String discoveryId) { this.importingManager = importingHandler; this.discoveryId = discoveryId; } /** * Adds or modifies an topology manager. * But this can also be other discovery providers, like ourself. * So we * @param topologyRef the service reference * @param epListener the listener instance */ public void modifyTopologyManager(ServiceReference topologyRef, EndpointEventListener epListener, int eventType) { if (isOurOwnEndpointEventListener(topologyRef, discoveryId)) { logger.fine(String.format("[%s] Skipping our own EndpointEventListener", discoveryId)); return; } List topologyScopes = getEndpointListenerScopes(topologyRef); // get or create interest for given scope and add listener to it synchronized (topologyManagers) { Interest interest = topologyManagers.get(topologyRef); if (interest == null) { // create interest, add listener and start monitor interest = new Interest(); topologyManagers.put(topologyRef, interest); } interest.epListener = epListener; interest.scopes = topologyScopes; sendExistingEndpoints(topologyScopes, epListener, eventType); } } /** * Removed an end-point event listener * @param topologyManagerRef the service reference */ public synchronized void removeTopologyManager(ServiceReference topologyManagerRef) { logger.finest(String.format("Removing topology manager: %s", topologyManagerRef)); synchronized (topologyManagers) { topologyManagers.remove(topologyManagerRef); } } /** * Closes the manager */ public synchronized void close() { synchronized (topologyManagers) { topologyManagers.clear(); } } /* * (non-Javadoc) * @see org.osgi.service.remoteserviceadmin.EndpointEventListener#endpointChanged(org.osgi.service.remoteserviceadmin.EndpointEvent, java.lang.String) */ @Override public void endpointChanged(EndpointEvent event, String filter) { synchronized (topologyManagers) { for (Interest interest : topologyManagers.values()) { notifyListener(event, interest.scopes, interest.epListener); } } } /** * Returns a list of {@link EndpointEventListener#ENDPOINT_LISTENER_SCOPE} or null * @param serviceReference the service reference to get the scope from * @return a list of {@link EndpointEventListener#ENDPOINT_LISTENER_SCOPE} or null */ protected List getEndpointListenerScopes(ServiceReference serviceReference) { return FilterHelper.normalize(serviceReference.getProperty(EndpointEventListener.ENDPOINT_LISTENER_SCOPE)); } /** * Sends all end-points * @param scopes the scope to be used * @param endpointListener the * @param eventType */ private void sendExistingEndpoints(List scopes, EndpointEventListener endpointListener, int eventType) { for (EndpointDescription endpoint : importingManager.getAllDescriptions()) { org.osgi.service.remoteserviceadmin.EndpointDescription ed = converter.doSwitch(endpoint); EndpointEvent event = new EndpointEvent(eventType, ed); notifyListener(event, scopes, endpointListener); } } /** * Notifies the given end-point listener for end-point changed, if the scope of the {@link org.osgi.service.remoteserviceadmin.EndpointDescription} * matches one of the scopes in the given list. * So we only notify when the end-point descriptions properties match the scope-filter * @param event the {@link EndpointEvent} * @param scopes the list of scopes * @param endpointListener the end-point listener to be notified */ private void notifyListener(EndpointEvent event, List scopes, EndpointEventListener endpointListener) { org.osgi.service.remoteserviceadmin.EndpointDescription endpoint = event.getEndpoint(); String currentScope = getFirstMatch(scopes, endpoint); if (currentScope == null) { logger.fine(String.format("Current scope is null for endpoint event %s", event)); return; } logger.fine(String.format("Calling endpoint changed on end-point listener for scope %s, endpoint %s ", currentScope, endpoint)); endpointListener.endpointChanged(event, currentScope); } /** * Returns the first scope in the given list, that matches to the {@link org.osgi.service.remoteserviceadmin.EndpointDescription} * @param scopes list of scopes * @param endpoint the end-point description * @return the first scope or null */ private String getFirstMatch(List scopes, org.osgi.service.remoteserviceadmin.EndpointDescription endpoint) { if (scopes == null) { return null; } for (String scope : scopes) { if (endpoint.matches(scope)) { return scope; } } return null; } /** * Returns true, if we are the given end-point listener. * @param endpointEventListener the service reference for the end-point listener to be checked * @return */ private static boolean isOurOwnEndpointEventListener(ServiceReference endpointEventListener, String discoveryId) { return Boolean.parseBoolean(String.valueOf( endpointEventListener.getProperty(discoveryId))); } }