| /******************************************************************************* |
| * Copyright (c) 2005, 2018 Cognos Incorporated, 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: |
| * Cognos Incorporated - initial API and implementation |
| * IBM Corporation - bug fixes and enhancements |
| *******************************************************************************/ |
| package org.eclipse.equinox.internal.cm; |
| |
| import java.util.*; |
| import org.osgi.framework.*; |
| import org.osgi.service.cm.*; |
| import org.osgi.service.log.LogService; |
| import org.osgi.util.tracker.ServiceTracker; |
| |
| /** |
| * ManagedServiceTracker tracks... ManagedServices and notifies them about related configuration changes |
| */ |
| class ManagedServiceTracker extends ServiceTracker<ManagedService, ManagedService> { |
| |
| final ConfigurationAdminFactory configurationAdminFactory; |
| private final ConfigurationStore configurationStore; |
| |
| /** @GuardedBy targets*/ |
| private final TargetMap targets = new TargetMap(); |
| |
| private final SerializedTaskQueue queue = new SerializedTaskQueue("ManagedService Update Queue"); //$NON-NLS-1$ |
| |
| public ManagedServiceTracker(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, BundleContext context) { |
| super(context, ManagedService.class.getName(), null); |
| this.configurationAdminFactory = configurationAdminFactory; |
| this.configurationStore = configurationStore; |
| } |
| |
| void notifyDeleted(ConfigurationImpl config) { |
| config.checkLocked(); |
| String configLoc = config.getLocation(); |
| if (configLoc == null) { |
| return; |
| } |
| boolean isMultiple = configLoc.startsWith("?"); //$NON-NLS-1$ |
| String pid = config.getPid(false); |
| List<ServiceReference<ManagedService>> references = getManagedServiceReferences(pid); |
| for (ServiceReference<ManagedService> ref : references) { |
| if (!hasMoreSpecificConfigPids(ref, pid)) { |
| boolean hasLocPermission = configurationAdminFactory.checkTargetPermission(configLoc, ref); |
| ManagedService service = getService(ref); |
| if (hasLocPermission && service != null) { |
| if (isMultiple || ConfigurationAdminImpl.getLocation(ref.getBundle()).equals(configLoc)) { |
| // search for other matches |
| List<List<String>> qualifiedPidLists; |
| synchronized (targets) { |
| qualifiedPidLists = targets.getQualifiedPids(ref); |
| } |
| updateManagedService(qualifiedPidLists, ref, service); |
| } |
| } |
| } |
| } |
| } |
| |
| void notifyUpdated(ConfigurationImpl config) { |
| config.checkLocked(); |
| String configLoc = config.getLocation(); |
| boolean isMultiple = configLoc != null && configLoc.startsWith("?"); //$NON-NLS-1$ |
| String pid = config.getPid(); |
| List<ServiceReference<ManagedService>> references = getManagedServiceReferences(pid); |
| for (ServiceReference<ManagedService> ref : references) { |
| if (!hasMoreSpecificConfigPids(ref, pid)) { |
| boolean hasLocPermission = configurationAdminFactory.checkTargetPermission(configLoc, ref); |
| ManagedService service = getService(ref); |
| if (hasLocPermission && service != null) { |
| if (isMultiple || config.bind(ConfigurationAdminImpl.getLocation(ref.getBundle()))) { |
| Dictionary<String, Object> properties = config.getProperties(); |
| configurationAdminFactory.modifyConfiguration(ref, properties); |
| asynchUpdated(service, properties); |
| } |
| } |
| } |
| } |
| } |
| |
| void notifyUpdateLocation(ConfigurationImpl config, String oldLocation) { |
| config.checkLocked(); |
| String configLoc = config.getLocation(); |
| if (configLoc == null ? oldLocation == null : configLoc.equals(oldLocation)) { |
| // same location do nothing |
| return; |
| } |
| boolean oldIsMultiple = oldLocation != null && oldLocation.startsWith("?"); //$NON-NLS-1$ |
| boolean newIsMultiple = configLoc != null && configLoc.startsWith("?"); //$NON-NLS-1$ |
| String pid = config.getPid(); |
| List<ServiceReference<ManagedService>> references = getManagedServiceReferences(pid); |
| for (ServiceReference<ManagedService> ref : references) { |
| if (!hasMoreSpecificConfigPids(ref, pid)) { |
| boolean hasOldPermission = configurationAdminFactory.checkTargetPermission(oldLocation, ref); |
| boolean hasNewPermission = configurationAdminFactory.checkTargetPermission(configLoc, ref); |
| ManagedService service = getService(ref); |
| if (service != null) { |
| boolean delete = false; |
| boolean update = false; |
| String targetLocation = ConfigurationAdminImpl.getLocation(ref.getBundle()); |
| if (hasOldPermission != hasNewPermission) { |
| if (hasOldPermission) { |
| delete = oldIsMultiple || targetLocation.equals(oldLocation); |
| } else { |
| update = newIsMultiple || config.bind(targetLocation); |
| } |
| } else { |
| // location has changed, this may be a bound configuration |
| if (targetLocation.equals(oldLocation)) { |
| delete = true; |
| } else { |
| update = newIsMultiple || config.bind(targetLocation); |
| } |
| } |
| if (delete) { |
| // search for other matches |
| List<List<String>> qualifiedPidLists; |
| synchronized (targets) { |
| qualifiedPidLists = targets.getQualifiedPids(ref); |
| } |
| updateManagedService(qualifiedPidLists, ref, service); |
| } else if (update) { |
| Dictionary<String, Object> properties = config.getProperties(); |
| configurationAdminFactory.modifyConfiguration(ref, properties); |
| asynchUpdated(service, properties); |
| } |
| // do not break on !isMultiple since we need to check if the other refs apply no matter what |
| } |
| } |
| } |
| } |
| |
| private boolean hasMoreSpecificConfigPids(ServiceReference<ManagedService> ref, String pid) { |
| List<List<String>> qualifiedPidsLists; |
| synchronized (targets) { |
| qualifiedPidsLists = targets.getQualifiedPids(ref); |
| } |
| for (List<String> qualifiedPids : qualifiedPidsLists) { |
| for (String qualifiedPid : qualifiedPids) { |
| if (qualifiedPid.length() <= pid.length() || !qualifiedPid.startsWith(pid)) { |
| break; |
| } |
| ConfigurationImpl config = configurationStore.findConfiguration(qualifiedPid); |
| if (config != null) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public ManagedService addingService(ServiceReference<ManagedService> reference) { |
| ManagedService service = context.getService(reference); |
| if (service == null) |
| return null; |
| |
| addReference(reference, service); |
| return service; |
| } |
| |
| @Override |
| public void modifiedService(ServiceReference<ManagedService> reference, ManagedService service) { |
| List<String> newPids = TargetMap.getPids(reference.getProperty(Constants.SERVICE_PID)); |
| synchronized (targets) { |
| List<List<String>> previousPids = targets.getQualifiedPids(reference); |
| if (newPids.size() == previousPids.size()) { |
| boolean foundAll = false; |
| for (String newPid : newPids) { |
| foundAll = false; |
| for (List<String> pids : previousPids) { |
| if (pids.contains(newPid)) { |
| foundAll = true; |
| break; |
| } |
| } |
| if (!foundAll) { |
| break; |
| } |
| } |
| if (foundAll) { |
| return; |
| } |
| } |
| } |
| |
| untrackManagedService(reference); |
| addingService(reference); |
| } |
| |
| @Override |
| public void removedService(ServiceReference<ManagedService> reference, ManagedService service) { |
| untrackManagedService(reference); |
| |
| context.ungetService(reference); |
| } |
| |
| private void addReference(ServiceReference<ManagedService> reference, ManagedService service) { |
| List<List<String>> qualifiedPidLists = trackManagedService(reference); |
| updateManagedService(qualifiedPidLists, reference, service); |
| } |
| |
| private void updateManagedService(List<List<String>> qualifiedPidLists, ServiceReference<ManagedService> reference, ManagedService service) { |
| for (List<String> qualifiedPids : qualifiedPidLists) { |
| boolean foundConfig = false; |
| qualifiedPids: for (String qualifiedPid : qualifiedPids) { |
| ConfigurationImpl config = configurationStore.findConfiguration(qualifiedPid); |
| if (config != null) { |
| try { |
| config.lock(); |
| if (!config.isDeleted()) { |
| if (config.getFactoryPid() != null) { |
| configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + qualifiedPid + " should only be used by a " + ManagedServiceFactory.class.getName()); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| String location = config.getLocation(); |
| boolean shouldBind = location == null || !location.startsWith("?"); //$NON-NLS-1$ |
| boolean hasLocPermission = configurationAdminFactory.checkTargetPermission(location, reference); |
| if (hasLocPermission) { |
| if ((shouldBind && config.bind(ConfigurationAdminImpl.getLocation(reference.getBundle()))) || !shouldBind) { |
| Dictionary<String, Object> properties = config.getProperties(); |
| configurationAdminFactory.modifyConfiguration(reference, properties); |
| asynchUpdated(service, properties); |
| foundConfig = true; |
| break qualifiedPids; |
| } |
| configurationAdminFactory.log(LogService.LOG_WARNING, "Configuration for " + Constants.SERVICE_PID + "=" + qualifiedPid + " could not be bound to " + ConfigurationAdminImpl.getLocation(reference.getBundle())); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| } |
| } finally { |
| config.unlock(); |
| } |
| } |
| } |
| if (!foundConfig) { |
| // This seems questionable to me, but is required for the spec. |
| // if a ManagedService has multiple pids, watch out!! |
| asynchUpdated(service, null); |
| } |
| } |
| } |
| |
| private List<List<String>> trackManagedService(ServiceReference<ManagedService> reference) { |
| synchronized (targets) { |
| return targets.add(reference); |
| } |
| } |
| |
| private void untrackManagedService(ServiceReference<ManagedService> reference) { |
| synchronized (targets) { |
| targets.remove(reference); |
| } |
| } |
| |
| private List<ServiceReference<ManagedService>> getManagedServiceReferences(String pid) { |
| synchronized (targets) { |
| @SuppressWarnings("rawtypes") |
| List temp = targets.getTargets(pid); |
| @SuppressWarnings("unchecked") |
| List<ServiceReference<ManagedService>> refs = temp; |
| Collections.sort(refs, Collections.reverseOrder()); |
| return refs; |
| } |
| } |
| |
| private void asynchUpdated(final ManagedService service, final Dictionary<String, ?> properties) { |
| queue.put(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| service.updated(properties); |
| } catch (ConfigurationException e) { |
| // we might consider doing more for ConfigurationExceptions |
| Throwable cause = e.getCause(); |
| configurationAdminFactory.log(LogService.LOG_ERROR, e.getMessage(), cause != null ? cause : e); |
| } catch (Throwable t) { |
| configurationAdminFactory.log(LogService.LOG_ERROR, t.getMessage(), t); |
| } |
| } |
| }); |
| } |
| } |