/******************************************************************************* * Copyright (c) 2008, 2010 VMware Inc. * 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: * VMware Inc. - initial contribution *******************************************************************************/ package org.eclipse.virgo.shell.internal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; /** * A <code>CommandRegistry</code> maintains a list of {@link CommandDescriptor CommandDescriptors} based on the contents * of the OSGi service registry. Descriptors are created using a {@link CommandResolver}. * <p /> * * <strong>Concurrent Semantics</strong><br /> * * Thread-safe. * */ public final class CommandRegistry { private final CommandResolver commandResolver; private final BundleContext bundleContext; private final List<CommandDescriptor> commandDescriptors = new ArrayList<CommandDescriptor>(); private final Map<ServiceReference<?>, List<CommandDescriptor>> commandDescriptorsByService = new HashMap<ServiceReference<?>, List<CommandDescriptor>>(); private final Object monitor = new Object(); private final CommandRegistryServiceListener commandRegistryServiceListener = new CommandRegistryServiceListener(); /** * @param commandResolver * @param bundleContext */ public CommandRegistry(CommandResolver commandResolver, BundleContext bundleContext) { this.commandResolver = commandResolver; this.bundleContext = bundleContext; } void initialize() { // TODO Limit with a filter this.bundleContext.addServiceListener(this.commandRegistryServiceListener); try { // TODO Limit with a filter ServiceReference<?>[] serviceReferences = this.bundleContext.getServiceReferences((String)null, null); if (serviceReferences != null) { for (ServiceReference<?> serviceReference : serviceReferences) { serviceRegistered(serviceReference); } } } catch (InvalidSyntaxException e) { throw new RuntimeException("Unexpected InvalidSyntaxException", e); } } public List<CommandDescriptor> getCommandDescriptors() { synchronized(this.monitor) { return new ArrayList<CommandDescriptor>(this.commandDescriptors); } } private void serviceRegistered(ServiceReference<?> serviceReference) { Object service = bundleContext.getService(serviceReference); if (service != null) { List<CommandDescriptor> commands = commandResolver.resolveCommands(serviceReference, service); if (!commands.isEmpty()) { synchronized (this.monitor) { this.commandDescriptors.addAll(commands); this.commandDescriptorsByService.put(serviceReference, commands); } } } } private void serviceUnregistering(ServiceReference<?> serviceReference) { synchronized (this.monitor) { List<CommandDescriptor> commandDescriptorsForService = this.commandDescriptorsByService.remove(serviceReference); if (commandDescriptorsForService != null) { this.commandDescriptors.removeAll(commandDescriptorsForService); } } } private final class CommandRegistryServiceListener implements ServiceListener { /** * {@inheritDoc} */ public void serviceChanged(ServiceEvent event) { if (ServiceEvent.REGISTERED == event.getType()) { serviceRegistered(event.getServiceReference()); } else if (ServiceEvent.UNREGISTERING == event.getType()) { serviceUnregistering(event.getServiceReference()); } } } }