Return-Path: Delivered-To: apmail-aries-commits-archive@www.apache.org Received: (qmail 89050 invoked from network); 27 Feb 2011 21:22:21 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 27 Feb 2011 21:22:21 -0000 Received: (qmail 31076 invoked by uid 500); 27 Feb 2011 21:22:21 -0000 Delivered-To: apmail-aries-commits-archive@aries.apache.org Received: (qmail 30910 invoked by uid 500); 27 Feb 2011 21:22:21 -0000 Mailing-List: contact commits-help@aries.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@aries.apache.org Delivered-To: mailing list commits@aries.apache.org Received: (qmail 30897 invoked by uid 99); 27 Feb 2011 21:22:20 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 27 Feb 2011 21:22:20 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 27 Feb 2011 21:22:13 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 1EDF62388C18; Sun, 27 Feb 2011 21:21:27 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1075149 [8/23] - in /aries/tags/blueprint-0.3.1: ./ blueprint-annotation-api/ blueprint-annotation-api/src/ blueprint-annotation-api/src/main/ blueprint-annotation-api/src/main/java/ blueprint-annotation-api/src/main/java/org/ blueprint-an... Date: Sun, 27 Feb 2011 21:21:22 -0000 To: commits@aries.apache.org From: zoe@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110227212127.1EDF62388C18@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedServiceFactory.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedServiceFactory.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedServiceFactory.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedServiceFactory.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,351 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Dictionary; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.aries.blueprint.BeanProcessor; +import org.apache.aries.blueprint.ExtendedBlueprintContainer; +import org.apache.aries.blueprint.ServiceProcessor; +import org.apache.aries.blueprint.container.ServiceListener; +import org.apache.aries.blueprint.utils.JavaUtils; +import org.apache.aries.blueprint.utils.ReflectionUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.blueprint.reflect.ServiceMetadata; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedServiceFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TODO: if we need to make those exported services tied to their references as for other elements + * TODO: it becomes a problem as currently we would have to create a specific recipe or something like that + * + * @version $Rev: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $ + */ +public class CmManagedServiceFactory { + + static final int CONFIGURATION_ADMIN_OBJECT_DELETED = 1; + + static final int BUNDLE_STOPPING = 2; + + private static final Logger LOGGER = LoggerFactory.getLogger(CmManagedServiceFactory.class); + + private ExtendedBlueprintContainer blueprintContainer; + private ConfigurationAdmin configAdmin; + private String id; + private String factoryPid; + private List interfaces; + private int autoExport; + private int ranking; + private Map serviceProperties; + private String managedComponentName; + private String componentDestroyMethod; + private List listeners; + private final Object lock = new Object(); + + private ServiceRegistration registration; + private Map pids = new ConcurrentHashMap(); + private Map services = new ConcurrentHashMap(); + + public void init() throws Exception { + LOGGER.debug("Initializing CmManagedServiceFactory for factoryPid={}", factoryPid); + Properties props = new Properties(); + props.put(Constants.SERVICE_PID, factoryPid); + Bundle bundle = blueprintContainer.getBundleContext().getBundle(); + props.put(Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName()); + props.put(Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION)); + + synchronized(lock) { + registration = blueprintContainer.getBundleContext().registerService(ManagedServiceFactory.class.getName(), new ConfigurationWatcher(), props); + + String filter = '(' + ConfigurationAdmin.SERVICE_FACTORYPID + '=' + this.factoryPid + ')'; + Configuration[] configs = configAdmin.listConfigurations(filter); + if (configs != null) { + for (Configuration config : configs) { + updated(config.getPid(), config.getProperties()); + } + } + } + } + + public void destroy() { + if (registration != null) { + registration.unregister(); + } + for (Map.Entry entry : services.entrySet()) { + destroy(entry.getValue(), entry.getKey(), BUNDLE_STOPPING); + } + services.clear(); + pids.clear(); + } + + private void destroy(Object component, ServiceRegistration registration, int code) { + if (listeners != null) { + ServiceReference ref = registration.getReference(); + for (ServiceListener listener : listeners) { + Hashtable props = JavaUtils.getProperties(ref); + listener.unregister(component, props); + } + } + destroyComponent(component, code); + registration.unregister(); + } + + public Map getServiceMap() { + return Collections.unmodifiableMap(services); + } + + public void setBlueprintContainer(ExtendedBlueprintContainer blueprintContainer) { + this.blueprintContainer = blueprintContainer; + } + + public void setConfigAdmin(ConfigurationAdmin configAdmin) { + this.configAdmin = configAdmin; + } + + public void setListeners(List listeners) { + this.listeners = listeners; + } + + public void setId(String id) { + this.id = id; + } + + public void setFactoryPid(String factoryPid) { + this.factoryPid = factoryPid; + } + + public void setInterfaces(List interfaces) { + this.interfaces = interfaces; + } + + public void setAutoExport(int autoExport) { + this.autoExport = autoExport; + } + + public void setRanking(int ranking) { + this.ranking = ranking; + } + + public void setServiceProperties(Map serviceProperties) { + this.serviceProperties = serviceProperties; + } + + public void setManagedComponentName(String managedComponentName) { + this.managedComponentName = managedComponentName; + } + + public void setComponentDestroyMethod(String componentDestroyMethod) { + this.componentDestroyMethod = componentDestroyMethod; + } + + protected void updated(String pid, Dictionary props) { + LOGGER.debug("Updated configuration {} with props {}", pid, props); + ServiceRegistration reg = pids.get(pid); + if (reg == null) { + updateComponentProperties(props); + + Object component = blueprintContainer.getComponentInstance(managedComponentName); + + // TODO: call listeners, etc... + + Hashtable regProps = getRegistrationProperties(pid); + CmProperties cm = findServiceProcessor(); + if (cm != null) { + if ("".equals(cm.getPersistentId())) { + JavaUtils.copy(regProps, props); + } + cm.updateProperties(new PropertiesUpdater(pid), regProps); + } + + Set classes = getClasses(component); + String[] classArray = classes.toArray(new String[classes.size()]); + reg = blueprintContainer.getBundleContext().registerService(classArray, component, regProps); + + LOGGER.debug("Service {} registered with interfaces {} and properties {}", new Object [] { component, classes, regProps }); + + services.put(reg, component); + pids.put(pid, reg); + + if (listeners != null) { + for (ServiceListener listener : listeners) { + listener.register(component, regProps); + } + } + } else { + updateComponentProperties(props); + + CmProperties cm = findServiceProcessor(); + if (cm != null && "".equals(cm.getPersistentId())) { + Dictionary regProps = getRegistrationProperties(pid); + JavaUtils.copy(regProps, props); + cm.updated(regProps); + } + } + } + + private Hashtable getRegistrationProperties(String pid) { + Hashtable regProps = new Hashtable(); + if (serviceProperties != null) { + regProps.putAll(serviceProperties); + } + regProps.put(Constants.SERVICE_PID, pid); + regProps.put(Constants.SERVICE_RANKING, ranking); + return regProps; + } + + private void updateComponentProperties(Dictionary props) { + CmManagedProperties cm = findBeanProcessor(); + if (cm != null) { + cm.updated(props); + } + } + + private CmManagedProperties findBeanProcessor() { + for (BeanProcessor beanProcessor : blueprintContainer.getProcessors(BeanProcessor.class)) { + if (beanProcessor instanceof CmManagedProperties) { + CmManagedProperties cm = (CmManagedProperties) beanProcessor; + if (managedComponentName.equals(cm.getBeanName()) && "".equals(cm.getPersistentId())) { + return cm; + } + } + } + return null; + } + + private CmProperties findServiceProcessor() { + for (ServiceProcessor processor : blueprintContainer.getProcessors(ServiceProcessor.class)) { + if (processor instanceof CmProperties) { + CmProperties cm = (CmProperties) processor; + if (id.equals(cm.getServiceId())) { + return cm; + } + } + } + return null; + } + + private void destroyComponent(Object instance, int reason) { + Method method = findDestroyMethod(instance.getClass()); + if (method != null) { + try { + method.invoke(instance, new Object [] { reason }); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private Method findDestroyMethod(Class clazz) { + Method method = null; + if (componentDestroyMethod != null && componentDestroyMethod.length() > 0) { + List methods = ReflectionUtils.findCompatibleMethods(clazz, componentDestroyMethod, new Class [] { int.class }); + if (methods != null && !methods.isEmpty()) { + method = methods.get(0); + } + } + return method; + } + + protected void deleted(String pid) { + LOGGER.debug("Deleted configuration {}", pid); + ServiceRegistration reg = pids.remove(pid); + if (reg != null) { + Object component = services.remove(reg); + destroy(component, reg, CONFIGURATION_ADMIN_OBJECT_DELETED); + } + } + + private Set getClasses(Object service) { + Class serviceClass = service.getClass(); + Set classes; + switch (autoExport) { + case ServiceMetadata.AUTO_EXPORT_INTERFACES: + classes = ReflectionUtils.getImplementedInterfaces(new HashSet(), serviceClass); + break; + case ServiceMetadata.AUTO_EXPORT_CLASS_HIERARCHY: + classes = ReflectionUtils.getSuperClasses(new HashSet(), serviceClass); + break; + case ServiceMetadata.AUTO_EXPORT_ALL_CLASSES: + classes = ReflectionUtils.getSuperClasses(new HashSet(), serviceClass); + classes = ReflectionUtils.getImplementedInterfaces(classes, serviceClass); + break; + default: + classes = new HashSet(interfaces); + break; + } + return classes; + } + + private class ConfigurationWatcher implements ManagedServiceFactory { + + public String getName() { + return null; + } + + public void updated(String pid, Dictionary props) throws ConfigurationException { + CmManagedServiceFactory.this.updated(pid, props); + } + + public void deleted(String pid) { + CmManagedServiceFactory.this.deleted(pid); + } + } + + private class PropertiesUpdater implements ServiceProcessor.ServicePropertiesUpdater { + + private String pid; + + public PropertiesUpdater(String pid) { + this.pid = pid; + } + + public String getId() { + return id; + } + + public void updateProperties(Dictionary properties) { + ServiceRegistration reg = pids.get(pid); + if (reg != null) { + ServiceReference ref = reg.getReference(); + if (ref != null) { + Hashtable table = JavaUtils.getProperties(ref); + JavaUtils.copy(table, properties); + reg.setProperties(table); + } + } + } + } + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,569 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.Comment; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.apache.aries.blueprint.ComponentDefinitionRegistry; +import org.apache.aries.blueprint.NamespaceHandler; +import org.apache.aries.blueprint.ParserContext; +import org.apache.aries.blueprint.container.Parser; +import org.apache.aries.blueprint.container.ParserContextImpl; +import org.apache.aries.blueprint.container.ServiceListener; +import org.apache.aries.blueprint.ext.ExtNamespaceHandler; +import org.apache.aries.blueprint.ext.PlaceholdersUtils; +import org.apache.aries.blueprint.mutable.MutableBeanMetadata; +import org.apache.aries.blueprint.mutable.MutableCollectionMetadata; +import org.apache.aries.blueprint.mutable.MutableComponentMetadata; +import org.apache.aries.blueprint.mutable.MutableIdRefMetadata; +import org.apache.aries.blueprint.mutable.MutableMapMetadata; +import org.apache.aries.blueprint.mutable.MutableRefMetadata; +import org.apache.aries.blueprint.mutable.MutableValueMetadata; +import org.osgi.service.blueprint.container.ComponentDefinitionException; +import org.osgi.service.blueprint.reflect.BeanMetadata; +import org.osgi.service.blueprint.reflect.BeanProperty; +import org.osgi.service.blueprint.reflect.CollectionMetadata; +import org.osgi.service.blueprint.reflect.ComponentMetadata; +import org.osgi.service.blueprint.reflect.IdRefMetadata; +import org.osgi.service.blueprint.reflect.MapMetadata; +import org.osgi.service.blueprint.reflect.Metadata; +import org.osgi.service.blueprint.reflect.RefMetadata; +import org.osgi.service.blueprint.reflect.RegistrationListener; +import org.osgi.service.blueprint.reflect.ServiceMetadata; +import org.osgi.service.blueprint.reflect.ValueMetadata; +import org.osgi.service.cm.ConfigurationAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Namespace handler for the Config Admin service. + * This handler will parse the various elements defined and populate / modify the registry + * accordingly. + * + * @see CmManagedProperties + * @see CmManagedServiceFactory + * @see CmProperties + * @see CmPropertyPlaceholder + * + * @version $Rev: 1002327 $, $Date: 2010-09-28 20:06:56 +0100 (Tue, 28 Sep 2010) $ + */ +public class CmNamespaceHandler implements NamespaceHandler { + + public static final String BLUEPRINT_NAMESPACE = "http://www.osgi.org/xmlns/blueprint/v1.0.0"; + public static final String BLUEPRINT_CM_NAMESPACE_1_0 = "http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"; + public static final String BLUEPRINT_CM_NAMESPACE_1_1 = "http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"; + + public static final String PROPERTY_PLACEHOLDER_ELEMENT = "property-placeholder"; + public static final String MANAGED_PROPERTIES_ELEMENT = "managed-properties"; + public static final String MANAGED_SERVICE_FACTORY_ELEMENT = "managed-service-factory"; + public static final String CM_PROPERTIES_ELEMENT = "cm-properties"; + public static final String DEFAULT_PROPERTIES_ELEMENT = "default-properties"; + public static final String PROPERTY_ELEMENT = "property"; + public static final String INTERFACES_ELEMENT = "interfaces"; + public static final String VALUE_ELEMENT = "value"; + public static final String MANAGED_COMPONENT_ELEMENT = "managed-component"; + + public static final String ID_ATTRIBUTE = "id"; + public static final String PERSISTENT_ID_ATTRIBUTE = "persistent-id"; + public static final String PLACEHOLDER_PREFIX_ATTRIBUTE = "placeholder-prefix"; + public static final String PLACEHOLDER_SUFFIX_ATTRIBUTE = "placeholder-suffix"; + public static final String DEFAULTS_REF_ATTRIBUTE = "defaults-ref"; + public static final String UPDATE_STRATEGY_ATTRIBUTE = "update-strategy"; + public static final String UPDATE_METHOD_ATTRIBUTE = "update-method"; + public static final String FACTORY_PID_ATTRIBUTE = "factory-pid"; + public static final String AUTO_EXPORT_ATTRIBUTE = "auto-export"; + public static final String RANKING_ATTRIBUTE = "ranking"; + public static final String INTERFACE_ATTRIBUTE = "interface"; + public static final String UPDATE_ATTRIBUTE = "update"; + + public static final String AUTO_EXPORT_DISABLED = "disabled"; + public static final String AUTO_EXPORT_INTERFACES = "interfaces"; + public static final String AUTO_EXPORT_CLASS_HIERARCHY = "class-hierarchy"; + public static final String AUTO_EXPORT_ALL = "all-classes"; + public static final String AUTO_EXPORT_DEFAULT = AUTO_EXPORT_DISABLED; + public static final String RANKING_DEFAULT = "0"; + + private static final String MANAGED_OBJECT_MANAGER_NAME = "org.apache.aries.managedObjectManager"; + + private static final Logger LOGGER = LoggerFactory.getLogger(CmNamespaceHandler.class); + + // This property is static but it should be ok since there will be only a single instance + // of this class for the bundle + private static ConfigurationAdmin configAdmin; + + private int idCounter; + + public int getIdCounter() { + return idCounter; + } + + public void setIdCounter(int idCounter) { + this.idCounter = idCounter; + } + + public static ConfigurationAdmin getConfigAdmin() { + return configAdmin; + } + + public void setConfigAdmin(ConfigurationAdmin configAdmin) { + this.configAdmin = configAdmin; + } + + public URL getSchemaLocation(String namespace) { + if (BLUEPRINT_CM_NAMESPACE_1_1.equals(namespace)) { + return getClass().getResource("blueprint-cm-1.1.0.xsd"); + } else if (BLUEPRINT_CM_NAMESPACE_1_0.equals(namespace)) { + return getClass().getResource("blueprint-cm-1.0.0.xsd"); + } else { + return null; + } + } + + public Set getManagedClasses() { + return new HashSet(Arrays.asList( + CmPropertyPlaceholder.class, + CmManagedServiceFactory.class, + CmManagedProperties.class, + CmProperties.class + )); + } + + public Metadata parse(Element element, ParserContext context) { + LOGGER.debug("Parsing element {{}}{}", element.getNamespaceURI(), element.getLocalName()); + ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry(); + registerManagedObjectManager(context, registry); + if (nodeNameEquals(element, PROPERTY_PLACEHOLDER_ELEMENT)) { + return parsePropertyPlaceholder(context, element); + } else if (nodeNameEquals(element, MANAGED_SERVICE_FACTORY_ELEMENT)) { + return parseManagedServiceFactory(context, element); + } else { + throw new ComponentDefinitionException("Unsupported element: " + element.getNodeName()); + } + } + + public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) { + LOGGER.debug("Decorating node {{}}{}", node.getNamespaceURI(), node.getLocalName()); + ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry(); + registerManagedObjectManager(context, registry); + if (node instanceof Element) { + if (nodeNameEquals(node, MANAGED_PROPERTIES_ELEMENT)) { + return decorateManagedProperties(context, (Element) node, component); + } else if (nodeNameEquals(node, CM_PROPERTIES_ELEMENT)) { + return decorateCmProperties(context, (Element) node, component); + } else { + throw new ComponentDefinitionException("Unsupported element: " + node.getNodeName()); + } + } else { + throw new ComponentDefinitionException("Illegal use of blueprint cm namespace"); + } + } + + private ComponentMetadata parsePropertyPlaceholder(ParserContext context, Element element) { + MutableBeanMetadata metadata = context.createMetadata(MutableBeanMetadata.class); + metadata.setProcessor(true); + metadata.setId(getId(context, element)); + metadata.setScope(BeanMetadata.SCOPE_SINGLETON); + metadata.setRuntimeClass(CmPropertyPlaceholder.class); + metadata.setInitMethod("init"); + metadata.setDestroyMethod("destroy"); + metadata.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); + metadata.addProperty("configAdmin", createConfigAdminProxy(context)); + metadata.addProperty("persistentId", createValue(context, element.getAttribute(PERSISTENT_ID_ATTRIBUTE))); + String prefix = element.hasAttribute(PLACEHOLDER_PREFIX_ATTRIBUTE) + ? element.getAttribute(PLACEHOLDER_PREFIX_ATTRIBUTE) + : "${"; + metadata.addProperty("placeholderPrefix", createValue(context, prefix)); + String suffix = element.hasAttribute(PLACEHOLDER_SUFFIX_ATTRIBUTE) + ? element.getAttribute(PLACEHOLDER_SUFFIX_ATTRIBUTE) + : "}"; + metadata.addProperty("placeholderSuffix", createValue(context, suffix)); + String defaultsRef = element.hasAttribute(DEFAULTS_REF_ATTRIBUTE) ? element.getAttribute(DEFAULTS_REF_ATTRIBUTE) : null; + if (defaultsRef != null) { + metadata.addProperty("defaultProperties", createRef(context, defaultsRef)); + } + String ignoreMissingLocations = element.hasAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE, ExtNamespaceHandler.IGNORE_MISSING_LOCATIONS_ATTRIBUTE) + ? element.getAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE, ExtNamespaceHandler.IGNORE_MISSING_LOCATIONS_ATTRIBUTE) : null; + if (ignoreMissingLocations != null) { + metadata.addProperty("ignoreMissingLocations", createValue(context, ignoreMissingLocations)); + } + String systemProperties = element.hasAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE, ExtNamespaceHandler.SYSTEM_PROPERTIES_ATTRIBUTE) + ? element.getAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE, ExtNamespaceHandler.SYSTEM_PROPERTIES_ATTRIBUTE) : null; + if (systemProperties == null) { + systemProperties = ExtNamespaceHandler.SYSTEM_PROPERTIES_NEVER; + } + metadata.addProperty("systemProperties", createValue(context, systemProperties)); + String updateStrategy = element.getAttribute(UPDATE_STRATEGY_ATTRIBUTE); + if (updateStrategy != null) { + metadata.addProperty("updateStrategy", createValue(context, updateStrategy)); + } + metadata.addProperty("managedObjectManager", createRef(context, MANAGED_OBJECT_MANAGER_NAME)); + // Parse elements + List locations = new ArrayList(); + NodeList nl = element.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element) { + Element e = (Element) node; + if (BLUEPRINT_CM_NAMESPACE_1_0.equals(e.getNamespaceURI()) + || BLUEPRINT_CM_NAMESPACE_1_1.equals(e.getNamespaceURI())) { + if (nodeNameEquals(e, DEFAULT_PROPERTIES_ELEMENT)) { + if (defaultsRef != null) { + throw new ComponentDefinitionException("Only one of " + DEFAULTS_REF_ATTRIBUTE + " attribute or " + DEFAULT_PROPERTIES_ELEMENT + " element is allowed"); + } + Metadata props = parseDefaultProperties(context, metadata, e); + metadata.addProperty("defaultProperties", props); + } + } else if (ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE.equals(e.getNamespaceURI())) { + if (nodeNameEquals(e, ExtNamespaceHandler.LOCATION_ELEMENT)) { + locations.add(getTextValue(e)); + } + } + } + } + if (!locations.isEmpty()) { + metadata.addProperty("locations", createList(context, locations)); + } + + PlaceholdersUtils.validatePlaceholder(metadata, context.getComponentDefinitionRegistry()); + + return metadata; + } + + private Metadata parseDefaultProperties(ParserContext context, MutableBeanMetadata enclosingComponent, Element element) { + MutableMapMetadata props = context.createMetadata(MutableMapMetadata.class); + NodeList nl = element.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element) { + Element e = (Element) node; + if (BLUEPRINT_CM_NAMESPACE_1_0.equals(e.getNamespaceURI()) + || BLUEPRINT_CM_NAMESPACE_1_1.equals(e.getNamespaceURI())) { + if (nodeNameEquals(e, PROPERTY_ELEMENT)) { + BeanProperty prop = context.parseElement(BeanProperty.class, enclosingComponent, e); + props.addEntry(createValue(context, prop.getName(), String.class.getName()), prop.getValue()); + } + } + } + } + return props; + } + + private ComponentMetadata parseManagedServiceFactory(ParserContext context, Element element) { + String id = getId(context, element); + + MutableBeanMetadata factoryMetadata = context.createMetadata(MutableBeanMetadata.class); + generateIdIfNeeded(context, factoryMetadata); + factoryMetadata.addProperty("id", createValue(context, factoryMetadata.getId())); + factoryMetadata.setScope(BeanMetadata.SCOPE_SINGLETON); + factoryMetadata.setRuntimeClass(CmManagedServiceFactory.class); + factoryMetadata.setInitMethod("init"); + factoryMetadata.setDestroyMethod("destroy"); + factoryMetadata.addProperty("configAdmin", createConfigAdminProxy(context)); + factoryMetadata.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); + factoryMetadata.addProperty("factoryPid", createValue(context, element.getAttribute(FACTORY_PID_ATTRIBUTE))); + String autoExport = element.hasAttribute(AUTO_EXPORT_ATTRIBUTE) ? element.getAttribute(AUTO_EXPORT_ATTRIBUTE) : AUTO_EXPORT_DEFAULT; + if (AUTO_EXPORT_DISABLED.equals(autoExport)) { + autoExport = Integer.toString(ServiceMetadata.AUTO_EXPORT_DISABLED); + } else if (AUTO_EXPORT_INTERFACES.equals(autoExport)) { + autoExport = Integer.toString(ServiceMetadata.AUTO_EXPORT_INTERFACES); + } else if (AUTO_EXPORT_CLASS_HIERARCHY.equals(autoExport)) { + autoExport = Integer.toString(ServiceMetadata.AUTO_EXPORT_CLASS_HIERARCHY); + } else if (AUTO_EXPORT_ALL.equals(autoExport)) { + autoExport = Integer.toString(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES); + } else { + throw new ComponentDefinitionException("Illegal value (" + autoExport + ") for " + AUTO_EXPORT_ATTRIBUTE + " attribute"); + } + factoryMetadata.addProperty("autoExport", createValue(context, autoExport)); + String ranking = element.hasAttribute(RANKING_ATTRIBUTE) ? element.getAttribute(RANKING_ATTRIBUTE) : RANKING_DEFAULT; + factoryMetadata.addProperty("ranking", createValue(context, ranking)); + + List interfaces = null; + if (element.hasAttribute(INTERFACE_ATTRIBUTE)) { + interfaces = Collections.singletonList(element.getAttribute(INTERFACE_ATTRIBUTE)); + factoryMetadata.addProperty("interfaces", createList(context, interfaces)); + } + + Parser parser = getParser(context); + + // Parse elements + List listeners = new ArrayList(); + NodeList nl = element.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element) { + Element e = (Element) node; + if (isBlueprintNamespace(e.getNamespaceURI())) { + if (nodeNameEquals(e, INTERFACES_ELEMENT)) { + if (interfaces != null) { + throw new ComponentDefinitionException("Only one of " + Parser.INTERFACE_ATTRIBUTE + " attribute or " + INTERFACES_ELEMENT + " element must be used"); + } + interfaces = parseInterfaceNames(e); + factoryMetadata.addProperty("interfaces", createList(context, interfaces)); + } else if (nodeNameEquals(e, Parser.SERVICE_PROPERTIES_ELEMENT)) { + MapMetadata map = parser.parseServiceProperties(e, factoryMetadata); + factoryMetadata.addProperty("serviceProperties", map); + } else if (nodeNameEquals(e, Parser.REGISTRATION_LISTENER_ELEMENT)) { + listeners.add(parser.parseRegistrationListener(e, factoryMetadata)); + } + } else if (BLUEPRINT_CM_NAMESPACE_1_0.equals(e.getNamespaceURI()) + || BLUEPRINT_CM_NAMESPACE_1_1.equals(e.getNamespaceURI())) { + if (nodeNameEquals(e, MANAGED_COMPONENT_ELEMENT)) { + MutableBeanMetadata managedComponent = context.parseElement(MutableBeanMetadata.class, null, e); + generateIdIfNeeded(context, managedComponent); + managedComponent.setScope(BeanMetadata.SCOPE_PROTOTYPE); + // destroy-method on managed-component has different signature than on regular beans + // so we'll handle it differently + String destroyMethod = managedComponent.getDestroyMethod(); + if (destroyMethod != null) { + factoryMetadata.addProperty("componentDestroyMethod", createValue(context, destroyMethod)); + managedComponent.setDestroyMethod(null); + } + context.getComponentDefinitionRegistry().registerComponentDefinition(managedComponent); + factoryMetadata.addProperty("managedComponentName", createIdRef(context, managedComponent.getId())); + } + } + } + } + + MutableCollectionMetadata listenerCollection = context.createMetadata(MutableCollectionMetadata.class); + listenerCollection.setCollectionClass(List.class); + for (RegistrationListener listener : listeners) { + MutableBeanMetadata bean = context.createMetadata(MutableBeanMetadata.class); + bean.setRuntimeClass(ServiceListener.class); + bean.addProperty("listener", listener.getListenerComponent()); + bean.addProperty("registerMethod", createValue(context, listener.getRegistrationMethod())); + bean.addProperty("unregisterMethod", createValue(context, listener.getUnregistrationMethod())); + listenerCollection.addValue(bean); + } + factoryMetadata.addProperty("listeners", listenerCollection); + + context.getComponentDefinitionRegistry().registerComponentDefinition(factoryMetadata); + + MutableBeanMetadata mapMetadata = context.createMetadata(MutableBeanMetadata.class); + mapMetadata.setScope(BeanMetadata.SCOPE_SINGLETON); + mapMetadata.setId(id); + mapMetadata.setFactoryComponent(createRef(context, factoryMetadata.getId())); + mapMetadata.setFactoryMethod("getServiceMap"); + return mapMetadata; + } + + private ComponentMetadata decorateCmProperties(ParserContext context, Element element, ComponentMetadata component) { + generateIdIfNeeded(context, ((MutableComponentMetadata) component)); + MutableBeanMetadata metadata = context.createMetadata(MutableBeanMetadata.class); + metadata.setProcessor(true); + metadata.setId(getId(context, element)); + metadata.setRuntimeClass(CmProperties.class); + String persistentId = element.getAttribute(PERSISTENT_ID_ATTRIBUTE); + // if persistentId is "" the cm-properties element in nested in managed-service-factory + // and the configuration object will come from the factory. So we only really need to register + // ManagedService if the persistentId is not an empty string. + if (persistentId.length() > 0) { + metadata.setInitMethod("init"); + metadata.setDestroyMethod("destroy"); + } + metadata.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); + metadata.addProperty("configAdmin", createConfigAdminProxy(context)); + metadata.addProperty("managedObjectManager", createRef(context, MANAGED_OBJECT_MANAGER_NAME)); + metadata.addProperty("persistentId", createValue(context, persistentId)); + if (element.hasAttribute(UPDATE_ATTRIBUTE)) { + metadata.addProperty("update", createValue(context, element.getAttribute(UPDATE_ATTRIBUTE))); + } + metadata.addProperty("serviceId", createIdRef(context, component.getId())); + context.getComponentDefinitionRegistry().registerComponentDefinition(metadata); + return component; + } + + private ComponentMetadata decorateManagedProperties(ParserContext context, Element element, ComponentMetadata component) { + if (!(component instanceof MutableBeanMetadata)) { + throw new ComponentDefinitionException("Element " + MANAGED_PROPERTIES_ELEMENT + " must be used inside a element"); + } + generateIdIfNeeded(context, ((MutableBeanMetadata) component)); + MutableBeanMetadata metadata = context.createMetadata(MutableBeanMetadata.class); + metadata.setProcessor(true); + metadata.setId(getId(context, element)); + metadata.setRuntimeClass(CmManagedProperties.class); + String persistentId = element.getAttribute(PERSISTENT_ID_ATTRIBUTE); + // if persistentId is "" the managed properties element in nested in managed-service-factory + // and the configuration object will come from the factory. So we only really need to register + // ManagedService if the persistentId is not an empty string. + if (persistentId.length() > 0) { + metadata.setInitMethod("init"); + metadata.setDestroyMethod("destroy"); + } + metadata.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); + metadata.addProperty("configAdmin", createConfigAdminProxy(context)); + metadata.addProperty("managedObjectManager", createRef(context, MANAGED_OBJECT_MANAGER_NAME)); + metadata.addProperty("persistentId", createValue(context, persistentId)); + String updateStrategy = element.getAttribute(UPDATE_STRATEGY_ATTRIBUTE); + if (updateStrategy != null) { + metadata.addProperty("updateStrategy", createValue(context, updateStrategy)); + } + if (element.hasAttribute(UPDATE_METHOD_ATTRIBUTE)) { + metadata.addProperty("updateMethod", createValue(context, element.getAttribute(UPDATE_METHOD_ATTRIBUTE))); + } else if ("component-managed".equals(updateStrategy)) { + throw new ComponentDefinitionException(UPDATE_METHOD_ATTRIBUTE + " attribute must be set when " + UPDATE_STRATEGY_ATTRIBUTE + " is set to 'component-managed'"); + } + metadata.addProperty("beanName", createIdRef(context, component.getId())); + context.getComponentDefinitionRegistry().registerComponentDefinition(metadata); + return component; + } + + /** + * Create a reference to the ConfigurationAdmin service if not already done + * and add it to the registry. + * + * @param context the parser context + * @return a metadata pointing to the config admin + */ + private Metadata createConfigAdminProxy(ParserContext context) { + MutableBeanMetadata bean = context.createMetadata(MutableBeanMetadata.class); + bean.setRuntimeClass(CmNamespaceHandler.class); + bean.setFactoryMethod("getConfigAdmin"); + bean.setActivation(MutableBeanMetadata.ACTIVATION_LAZY); + bean.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE); + return bean; + } + + private void registerManagedObjectManager(ParserContext context, ComponentDefinitionRegistry registry) { + if (registry.getComponentDefinition(MANAGED_OBJECT_MANAGER_NAME) == null) { + MutableBeanMetadata beanMetadata = context.createMetadata(MutableBeanMetadata.class); + beanMetadata.setScope(BeanMetadata.SCOPE_SINGLETON); + beanMetadata.setId(MANAGED_OBJECT_MANAGER_NAME); + beanMetadata.setRuntimeClass(ManagedObjectManager.class); + registry.registerComponentDefinition(beanMetadata); + } + } + + private static ValueMetadata createValue(ParserContext context, String value) { + return createValue(context, value, null); + } + + private static ValueMetadata createValue(ParserContext context, String value, String type) { + MutableValueMetadata m = context.createMetadata(MutableValueMetadata.class); + m.setStringValue(value); + m.setType(type); + return m; + } + + private static RefMetadata createRef(ParserContext context, String value) { + MutableRefMetadata m = context.createMetadata(MutableRefMetadata.class); + m.setComponentId(value); + return m; + } + + private static IdRefMetadata createIdRef(ParserContext context, String value) { + MutableIdRefMetadata m = context.createMetadata(MutableIdRefMetadata.class); + m.setComponentId(value); + return m; + } + + private static CollectionMetadata createList(ParserContext context, List list) { + MutableCollectionMetadata m = context.createMetadata(MutableCollectionMetadata.class); + m.setCollectionClass(List.class); + m.setValueType(String.class.getName()); + for (String v : list) { + m.addValue(createValue(context, v, String.class.getName())); + } + return m; + } + + private static String getTextValue(Element element) { + StringBuffer value = new StringBuffer(); + NodeList nl = element.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node item = nl.item(i); + if ((item instanceof CharacterData && !(item instanceof Comment)) || item instanceof EntityReference) { + value.append(item.getNodeValue()); + } + } + return value.toString(); + } + + private static boolean nodeNameEquals(Node node, String name) { + return (name.equals(node.getNodeName()) || name.equals(node.getLocalName())); + } + + public static boolean isBlueprintNamespace(String ns) { + return BLUEPRINT_NAMESPACE.equals(ns); + } + + public String getId(ParserContext context, Element element) { + if (element.hasAttribute(ID_ATTRIBUTE)) { + return element.getAttribute(ID_ATTRIBUTE); + } else { + return generateId(context); + } + } + + public void generateIdIfNeeded(ParserContext context, MutableComponentMetadata metadata) { + if (metadata.getId() == null) { + metadata.setId(generateId(context)); + } + } + + private String generateId(ParserContext context) { + String id; + do { + id = ".cm-" + ++idCounter; + } while (context.getComponentDefinitionRegistry().containsComponentDefinition(id)); + return id; + } + + private Parser getParser(ParserContext ctx) { + if (ctx instanceof ParserContextImpl) { + return ((ParserContextImpl) ctx).getParser(); + } + throw new RuntimeException("Unable to get parser"); + } + + public List parseInterfaceNames(Element element) { + List interfaceNames = new ArrayList(); + NodeList nl = element.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element) { + Element e = (Element) node; + if (nodeNameEquals(e, VALUE_ELEMENT)) { + String v = getTextValue(e).trim(); + if (interfaceNames.contains(v)) { + throw new ComponentDefinitionException("The element " + INTERFACES_ELEMENT + " should not contain the same interface twice"); + } + interfaceNames.add(getTextValue(e)); + } else { + throw new ComponentDefinitionException("Unsupported element " + e.getNodeName() + " inside an " + INTERFACES_ELEMENT + " element"); + } + } + } + return interfaceNames; + } + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmProperties.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,156 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.util.Dictionary; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import org.apache.aries.blueprint.ExtendedBlueprintContainer; +import org.apache.aries.blueprint.ServiceProcessor; +import org.apache.aries.blueprint.utils.JavaUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @version $Rev: 820286 $, $Date: 2009-09-30 15:45:55 +0100 (Wed, 30 Sep 2009) $ + */ +public class CmProperties implements ManagedObject, ServiceProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(CmProperties.class); + + private ExtendedBlueprintContainer blueprintContainer; + private ConfigurationAdmin configAdmin; + private ManagedObjectManager managedObjectManager; + private String persistentId; + private boolean update; + private String serviceId; + + private final Object lock = new Object(); + private final Set services = new HashSet(); + private Dictionary properties; + + public ExtendedBlueprintContainer getBlueprintContainer() { + return blueprintContainer; + } + + public void setBlueprintContainer(ExtendedBlueprintContainer blueprintContainer) { + this.blueprintContainer = blueprintContainer; + } + + public ConfigurationAdmin getConfigAdmin() { + return configAdmin; + } + + public void setConfigAdmin(ConfigurationAdmin configAdmin) { + this.configAdmin = configAdmin; + } + + public void setManagedObjectManager(ManagedObjectManager managedObjectManager) { + this.managedObjectManager = managedObjectManager; + } + + public ManagedObjectManager getManagedObjectManager() { + return managedObjectManager; + } + + public Bundle getBundle() { + return blueprintContainer.getBundleContext().getBundle(); + } + + public String getPersistentId() { + return persistentId; + } + + public void setPersistentId(String persistentId) { + this.persistentId = persistentId; + } + + public boolean getUpdate() { + return update; + } + + public void setUpdate(boolean update) { + this.update = update; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public void init() throws Exception { + LOGGER.debug("Initializing CmProperties for service={} / pid={}", serviceId, persistentId); + + Properties props = new Properties(); + props.put(Constants.SERVICE_PID, persistentId); + Bundle bundle = blueprintContainer.getBundleContext().getBundle(); + props.put(Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName()); + props.put(Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION)); + + synchronized (lock) { + managedObjectManager.register(this, props); + Configuration config = CmUtils.getConfiguration(configAdmin, persistentId); + if (config != null) { + properties = config.getProperties(); + } + } + } + + public void destroy() { + managedObjectManager.unregister(this); + } + + public void updated(Dictionary props) { + LOGGER.debug("Service properties updated for service={} / pid={}, {}", new Object[] {serviceId, persistentId, props}); + + synchronized (lock) { + this.properties = props; + if (update) { + for (ServicePropertiesUpdater service : services) { + service.updateProperties(props); + } + } + } + } + + public void updateProperties(ServicePropertiesUpdater service, Dictionary props) { + if (!this.serviceId.equals(service.getId())) { + return; + } + + LOGGER.debug("Service properties initialized for service={} / pid={}, {}", new Object[] {serviceId, persistentId, props}); + + synchronized (lock) { + services.add(service); + if (properties != null) { + JavaUtils.copy(props, properties); + } + } + } + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmPropertyPlaceholder.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,168 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.io.IOException; +import java.util.*; + +import org.apache.aries.blueprint.ExtendedBlueprintContainer; +import org.apache.aries.blueprint.ext.AbstractPropertyPlaceholder; +import org.apache.aries.blueprint.ext.PropertyPlaceholder; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.service.blueprint.container.BlueprintContainer; +import org.osgi.service.blueprint.container.ComponentDefinitionException; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TODO: javadoc + * + * @version $Rev: 1002318 $, $Date: 2010-09-28 19:47:49 +0100 (Tue, 28 Sep 2010) $ + */ +public class CmPropertyPlaceholder extends PropertyPlaceholder implements ManagedObject { + + private static final Logger LOGGER = LoggerFactory.getLogger(CmPropertyPlaceholder.class); + + private ExtendedBlueprintContainer blueprintContainer; + private ConfigurationAdmin configAdmin; + private String persistentId; + private String updateStrategy; + private ManagedObjectManager managedObjectManager; + private Dictionary properties; + + public ExtendedBlueprintContainer getBlueprintContainer() { + return blueprintContainer; + } + + public void setBlueprintContainer(ExtendedBlueprintContainer blueprintContainer) { + this.blueprintContainer = blueprintContainer; + } + + public ConfigurationAdmin getConfigAdmin() { + return configAdmin; + } + + public void setConfigAdmin(ConfigurationAdmin configAdmin) { + this.configAdmin = configAdmin; + } + + public String getPersistentId() { + return persistentId; + } + + public void setPersistentId(String persistentId) { + this.persistentId = persistentId; + } + + public String getUpdateStrategy() { + return updateStrategy; + } + + public void setUpdateStrategy(String updateStrategy) { + this.updateStrategy = updateStrategy; + } + + public ManagedObjectManager getManagedObjectManager() { + return managedObjectManager; + } + + public void setManagedObjectManager(ManagedObjectManager managedObjectManager) { + this.managedObjectManager = managedObjectManager; + } + + public void init() throws Exception { + LOGGER.debug("Initializing CmPropertyPlaceholder"); + Configuration config = CmUtils.getConfiguration(configAdmin, persistentId); + if (config != null) { + properties = config.getProperties(); + } + Properties props = new Properties(); + props.put(Constants.SERVICE_PID, persistentId); + Bundle bundle = blueprintContainer.getBundleContext().getBundle(); + props.put(Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName()); + props.put(Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION)); + managedObjectManager.register(this, props); + } + + public void destroy() { + LOGGER.debug("Destroying CmPropertyPlaceholder"); + managedObjectManager.unregister(this); + } + + protected String getProperty(String val) { + LOGGER.debug("Retrieving property value {} from configuration with pid {}", val, persistentId); + Object v = null; + if (properties != null) { + v = properties.get(val); + if (v != null) { + LOGGER.debug("Found property value {}", v); + } else { + LOGGER.debug("Property not found in configuration"); + } + } + if (v == null) { + v = super.getProperty(val); + } + return v != null ? v.toString() : null; + } + + public Bundle getBundle() { + return blueprintContainer.getBundleContext().getBundle(); + } + + public void updated(Dictionary props) { + if ("reload".equalsIgnoreCase(updateStrategy) && !equals(properties, props)) { + LOGGER.debug("Configuration updated for pid={}", persistentId); + // Run in a separate thread to avoid re-entrance + new Thread() { + public void run() { + blueprintContainer.reload(); + } + }.start(); + } + } + + private boolean equals(Dictionary d1, Dictionary d2) { + if (d1 == null || d1.isEmpty()) { + return d2 == null || d2.isEmpty(); + } else if (d2 == null || d1.size() != d2.size()) { + return false; + } else { + for (Enumeration e = d1.keys(); e.hasMoreElements();) { + T k = e.nextElement(); + U v1 = d1.get(k); + U v2 = d2.get(k); + if (v1 == null) { + if (v2 != null) { + return false; + } + } else { + if (!v1.equals(v2)) { + return false; + } + } + } + return true; + } + } + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmUtils.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,51 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.io.IOException; + +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; + +public class CmUtils { + + private CmUtils() { + } + + public static Configuration getConfiguration(ConfigurationAdmin configAdmin, String persistentId) throws IOException { + String filter = '(' + Constants.SERVICE_PID + '=' + persistentId + ')'; + Configuration[] configs; + try { + configs = configAdmin.listConfigurations(filter); + } catch (InvalidSyntaxException e) { + // this should not happen + throw new RuntimeException("Invalid filter: " + filter); + } + if (configs != null && configs.length > 0) { + return configs[0]; + } else { + // TODO: what should we do? + // throw new RuntimeException("No configuration object for pid=" + persistentId); + return null; + } + } + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObject.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObject.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObject.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObject.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,32 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.util.Dictionary; + +import org.osgi.framework.Bundle; + +public interface ManagedObject { + + Bundle getBundle(); + String getPersistentId(); + + void updated(Dictionary props); + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java Sun Feb 27 21:21:05 2011 @@ -0,0 +1,105 @@ +/** + * 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.apache.aries.blueprint.compendium.cm; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; + +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Since persistence id can only be associated with one ManagedService in a bundle + * this class ensures only one ManagedService is registered per persistence id. + */ +public class ManagedObjectManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ManagedObjectManager.class); + + private HashMap map = new HashMap(); + + public synchronized void register(ManagedObject cm, Properties props) { + String key = cm.getPersistentId(); + ConfigurationWatcher reg = map.get(key); + if (reg == null) { + reg = new ConfigurationWatcher(); + ServiceRegistration registration = cm.getBundle().getBundleContext().registerService(ManagedService.class.getName(), reg, props); + reg.setRegistration(registration); + map.put(key, reg); + } + reg.add(cm); + } + + public synchronized void unregister(ManagedObject cm) { + String key = cm.getPersistentId(); + ConfigurationWatcher reg = map.get(key); + if (reg != null) { + reg.remove(cm); + if (reg.isEmpty()) { + map.remove(key); + reg.getRegistration().unregister(); + } + } + } + + private static class ConfigurationWatcher implements ManagedService { + + private ServiceRegistration registration; + private List list = Collections.synchronizedList(new ArrayList()); + + public ConfigurationWatcher() { + } + + public void updated(Dictionary props) throws ConfigurationException { + synchronized (list) { + for (ManagedObject cm : list) { + cm.updated(props); + } + } + } + + private void setRegistration(ServiceRegistration registration) { + this.registration = registration; + } + + private ServiceRegistration getRegistration() { + return registration; + } + + private void add(ManagedObject cm) { + list.add(cm); + } + + private void remove(ManagedObject cm) { + list.remove(cm); + } + + private boolean isEmpty() { + return list.isEmpty(); + } + } + +} Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/OSGI-INF/blueprint/blueprint-cm.xml URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/OSGI-INF/blueprint/blueprint-cm.xml?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/OSGI-INF/blueprint/blueprint-cm.xml (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/OSGI-INF/blueprint/blueprint-cm.xml Sun Feb 27 21:21:05 2011 @@ -0,0 +1,38 @@ + + + + + + + + + http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0 + http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 + + + + + + + + + + + Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.0.0.xsd URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.0.0.xsd?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.0.0.xsd (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.0.0.xsd Sun Feb 27 21:21:05 2011 @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Added: aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd (added) +++ aries/tags/blueprint-0.3.1/blueprint-cm/src/main/resources/org/apache/aries/blueprint/compendium/cm/blueprint-cm-1.1.0.xsd Sun Feb 27 21:21:05 2011 @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Added: aries/tags/blueprint-0.3.1/blueprint-core/pom.xml URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-core/pom.xml?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-core/pom.xml (added) +++ aries/tags/blueprint-0.3.1/blueprint-core/pom.xml Sun Feb 27 21:21:05 2011 @@ -0,0 +1,131 @@ + + + 4.0.0 + + org.apache.aries.blueprint + blueprint + 0.3.1 + + + org.apache.aries.blueprint.core + bundle + Apache Aries Blueprint Core + + This bundle contains the core implementation of Blueprint + along with the "ext" namespace handler. + + + + + org.apache.aries.blueprint.container.BlueprintExtender + + + !org.apache.aries.blueprint.annotation*, + org.apache.aries.blueprint* + + + !org.apache.aries.blueprint*, + org.apache.aries.util.tracker;resolution:=optional, + org.osgi.service.event*;resolution:=optional, + org.osgi.service.framework;resolution:=optional, + org.apache.aries.blueprint.annotation.service;resolution:=optional, + org.apache.aries.quiesce.manager;version="[0.2,1.0)";resolution:=optional, + org.apache.aries.quiesce.participant;version="[0.2,1.0)";resolution:=optional, + * + + + org.apache.aries.blueprint.ParserService + + + + + + org.apache.aries.blueprint + org.apache.aries.blueprint.api + + + org.apache.aries.blueprint + org.apache.aries.blueprint.annotation.api + true + + + org.apache.aries + org.apache.aries.util + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + org.eclipse + osgi + provided + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-simple + test + + + asm + asm-all + true + + + org.apache.aries.quiesce + org.apache.aries.quiesce.api + provided + + + org.apache.aries.testsupport + org.apache.aries.testsupport.unit + + + org.apache.aries.proxy + org.apache.aries.proxy.api + + + + + + + src/main/resources + + + ../blueprint-api/src/main/resources/org/osgi/service/blueprint + org/apache/aries/blueprint + + blueprint.xsd + + + + + + Added: aries/tags/blueprint-0.3.1/blueprint-core/src/main/appended-resources/META-INF/NOTICE.vm URL: http://svn.apache.org/viewvc/aries/tags/blueprint-0.3.1/blueprint-core/src/main/appended-resources/META-INF/NOTICE.vm?rev=1075149&view=auto ============================================================================== --- aries/tags/blueprint-0.3.1/blueprint-core/src/main/appended-resources/META-INF/NOTICE.vm (added) +++ aries/tags/blueprint-0.3.1/blueprint-core/src/main/appended-resources/META-INF/NOTICE.vm Sun Feb 27 21:21:05 2011 @@ -0,0 +1,2 @@ +This product includes software developed at +the OSGi Alliance (http://www.osgi.org/). \ No newline at end of file