/******************************************************************************* * 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.kernel.install.artifact.internal; import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import org.eclipse.virgo.kernel.install.artifact.ScopeServiceRepository; import org.eclipse.virgo.util.math.Sets; /** * Tracks the service model for a given named scope. The service model of a named scope defines the set of services that * are statically known to be published by bundles in that named scope. Typically, this reflects the metadata derived * from Spring DM configuration files. * * <p/> * * The service model information is used to determine which service lookups are automatically application scoped. * * <strong>Concurrent Semantics</strong><br /> * * Threadsafe * */ final class StandardScopeServiceRepository implements ScopeServiceRepository { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Map<String, List<Service>> scopeServices = new HashMap<String, List<Service>>(); private final Object monitor = new Object(); /** * {@inheritDoc} */ public void recordService(String scopeName, String[] types, Dictionary<String, Object> properties) { if (logger.isDebugEnabled()) { logger.debug("Adding service to scope '{}' with service types '{}' and properties '{}'", new Object[] { scopeName, StringUtils.arrayToCommaDelimitedString(types), dictionaryToCommaSeparatedString(properties) }); } synchronized (this.monitor) { if (properties == null) { properties = new Hashtable<String, Object>(); } setStandardProperties(types, properties); List<Service> servicesForScope = this.scopeServices.get(scopeName); if (servicesForScope == null) { servicesForScope = new ArrayList<Service>(); this.scopeServices.put(scopeName, servicesForScope); } servicesForScope.add(new Service(types, properties)); } } private static String dictionaryToCommaSeparatedString(Dictionary<String, Object> properties) { StringBuffer propsString = new StringBuffer(); if (properties != null) { Enumeration<String> keys = properties.keys(); for (int i = 0; keys.hasMoreElements(); i++) { if (i > 0) { propsString.append(", "); } String key = keys.nextElement(); propsString.append(key + "=" + properties.get(key).toString()); } } return propsString.toString(); } private void setStandardProperties(String[] types, Dictionary<String, Object> properties) { if (properties.get(Constants.OBJECTCLASS) == null) { properties.put(Constants.OBJECTCLASS, types); } } /** * {@inheritDoc} */ public boolean scopeHasMatchingService(String scopeName, String type, String filter) throws InvalidSyntaxException { synchronized (this.monitor) { List<Service> servicesForScope = this.scopeServices.get(scopeName); boolean matches = false; if (servicesForScope != null) { Filter f = (filter == null ? null : FrameworkUtil.createFilter(filter)); for (Service service : servicesForScope) { if (service.matches(type, f)) { matches = true; break; } } } return matches; } } /** * {@inheritDoc} */ public void clearScope(String scopeName) { synchronized (this.monitor) { this.scopeServices.remove(scopeName); } } /** * {@inheritDoc} */ public Set<String> knownScopes() { Set<String> scopes = new HashSet<String>(); synchronized (this.monitor) { scopes.addAll(this.scopeServices.keySet()); } return scopes; } private static final class Service { private final Set<String> types; private final Dictionary<String, Object> properties; public Service(String[] types, Dictionary<String, Object> properties) { this.types = Sets.asSet(types); this.properties = properties; } public boolean matches(String type, Filter filter) { if (type == null || this.types.contains(type)) { return filter == null || filter.match(this.properties); } else { return false; } } } }