/**
* 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.metadata.Builder;
import org.apache.aries.blueprint.metadata.MutableBeanMetadata;
import org.apache.aries.blueprint.metadata.MutableComponentMetadata;
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.MapEntry;
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: 1071628 $, $Date: 2011-02-17 14:44:49 +0000 (Thu, 17 Feb 2011) $
*/
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<Class> getManagedClasses() {
return new HashSet<Class>(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) {
Builder builder = context.getMetadataBuilder();
MutableBeanMetadata<BeanMetadata> metadata = builder.newBean()
.id(getId(context, element))
.scope(BeanMetadata.SCOPE_SINGLETON)
.initMethod("init")
.destroyMethod("destroy")
.addProperty(builder.newBeanProperty().name("blueprintContainer").value(createRef(context, "blueprintContainer")))
.addProperty(builder.newBeanProperty().name("configAdmin").value(createConfigAdminProxy(context)))
.addProperty(builder.newBeanProperty().name("persistentId").value(createValue(context, element.getAttribute(PERSISTENT_ID_ATTRIBUTE))));
metadata.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.PROCESSOR_KEY, true);
metadata.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.RUNTIME_CLASS_KEY, CmPropertyPlaceholder.class);
String prefix = element.hasAttribute(PLACEHOLDER_PREFIX_ATTRIBUTE)
? element.getAttribute(PLACEHOLDER_PREFIX_ATTRIBUTE)
: "${";
metadata.addProperty(builder.newBeanProperty().name("placeholderPrefix").value(createValue(context, prefix)));
String suffix = element.hasAttribute(PLACEHOLDER_SUFFIX_ATTRIBUTE)
? element.getAttribute(PLACEHOLDER_SUFFIX_ATTRIBUTE)
: "}";
metadata.addProperty(builder.newBeanProperty().name("placeholderSuffix").value(createValue(context, suffix)));
String defaultsRef = element.hasAttribute(DEFAULTS_REF_ATTRIBUTE) ? element.getAttribute(DEFAULTS_REF_ATTRIBUTE) : null;
if (defaultsRef != null) {
metadata.addProperty(builder.newBeanProperty().name("defaultProperties").value(createRef(context, defaultsRef)));
}
String ignoreMissingLocations = extractIgnoreMissingLocations(element);
if (ignoreMissingLocations != null) {
metadata.addProperty(builder.newBeanProperty().name("ignoreMissingLocations").value(createValue(context, ignoreMissingLocations)));
}
String systemProperties = extractSystemPropertiesAttribute(element);
if (systemProperties == null) {
systemProperties = ExtNamespaceHandler.SYSTEM_PROPERTIES_NEVER;
}
metadata.addProperty(builder.newBeanProperty().name("systemProperties").value(createValue(context, systemProperties)));
String updateStrategy = element.getAttribute(UPDATE_STRATEGY_ATTRIBUTE);
if (updateStrategy != null) {
metadata.addProperty(builder.newBeanProperty().name("updateStrategy").value(createValue(context, updateStrategy)));
}
metadata.addProperty(builder.newBeanProperty().name("managedObjectManager").value(createRef(context, MANAGED_OBJECT_MANAGER_NAME)));
// Parse elements
List<String> locations = new ArrayList<String>();
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(builder.newBeanProperty().name("defaultProperties").value(props));
}
} else if (ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_0.equals(e.getNamespaceURI())) {
if (nodeNameEquals(e, ExtNamespaceHandler.LOCATION_ELEMENT)) {
locations.add(getTextValue(e));
}
} else if (ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_1.equals(e.getNamespaceURI())) {
if (nodeNameEquals(e, ExtNamespaceHandler.LOCATION_ELEMENT)) {
locations.add(getTextValue(e));
}
}
}
}
if (!locations.isEmpty()) {
metadata.addProperty(builder.newBeanProperty().name("locations").value(createList(context, locations)));
}
PlaceholdersUtils.validatePlaceholder(metadata, context.getComponentDefinitionRegistry());
return metadata;
}
private String extractSystemPropertiesAttribute(Element element) {
String systemProperties = null;
if (element.hasAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_0, ExtNamespaceHandler.SYSTEM_PROPERTIES_ATTRIBUTE)) {
systemProperties = element.getAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_0, ExtNamespaceHandler.SYSTEM_PROPERTIES_ATTRIBUTE);
} else if (element.hasAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_1, ExtNamespaceHandler.SYSTEM_PROPERTIES_ATTRIBUTE)) {
systemProperties = element.getAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_1, ExtNamespaceHandler.SYSTEM_PROPERTIES_ATTRIBUTE);
}
return systemProperties;
}
private String extractIgnoreMissingLocations(Element element) {
String ignoreMissingLocations = null;
if (element.hasAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_0, ExtNamespaceHandler.IGNORE_MISSING_LOCATIONS_ATTRIBUTE)) {
ignoreMissingLocations = element.getAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_0, ExtNamespaceHandler.IGNORE_MISSING_LOCATIONS_ATTRIBUTE);
} else if (element.hasAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_1, ExtNamespaceHandler.IGNORE_MISSING_LOCATIONS_ATTRIBUTE)) {
ignoreMissingLocations = element.getAttributeNS(ExtNamespaceHandler.BLUEPRINT_EXT_NAMESPACE_V1_1, ExtNamespaceHandler.IGNORE_MISSING_LOCATIONS_ATTRIBUTE);
}
return ignoreMissingLocations;
}
private Metadata parseDefaultProperties(ParserContext context, MutableBeanMetadata<?> enclosingComponent, Element element) {
Builder builder = context.getMetadataBuilder();
List<MapEntry> entries = new ArrayList<MapEntry>();
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);
entries.add(builder.newMapEntry().key(createValue(context, prop.getName(), String.class.getName())).value(prop.getValue()));
}
}
}
}
return builder.newMap().entries(entries);
}
private ComponentMetadata parseManagedServiceFactory(ParserContext context, Element element) {
String id = getId(context, element);
Builder builder = context.getMetadataBuilder();
MutableBeanMetadata<BeanMetadata> factoryMetadata = builder.newBean();
generateIdIfNeeded(context, factoryMetadata);
factoryMetadata
.scope(BeanMetadata.SCOPE_SINGLETON)
.initMethod("init")
.destroyMethod("destroy")
.addProperty("id", createValue(context, factoryMetadata.getId()))
.addProperty("configAdmin", createConfigAdminProxy(context))
.addProperty("blueprintContainer", createRef(context, "blueprintContainer"))
.addProperty("factoryPid", createValue(context, element.getAttribute(FACTORY_PID_ATTRIBUTE)));
factoryMetadata.addCustomData(ExtNamespaceHandler.class,
ExtNamespaceHandler.RUNTIME_CLASS_KEY,
CmManagedServiceFactory.class);
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<String> 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<RegistrationListener> listeners = new ArrayList<RegistrationListener>();
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<BeanMetadata> managedComponent = context.parseElement(MutableBeanMetadata.class, null, e);
generateIdIfNeeded(context, managedComponent);
managedComponent.scope(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.destroyMethod(null);
}
context.getComponentDefinitionRegistry().registerComponentDefinition(managedComponent);
factoryMetadata.addProperty("managedComponentName", createIdRef(context, managedComponent.getId()));
}
}
}
}
List<BeanMetadata> values = new ArrayList<BeanMetadata>();
for (RegistrationListener listener : listeners) {
MutableBeanMetadata<BeanMetadata> bean = builder.newBean()
.addProperty("listener", listener.getListenerComponent())
.addProperty("registerMethod", createValue(context, listener.getRegistrationMethod()))
.addProperty("unregisterMethod", createValue(context, listener.getUnregistrationMethod()));
bean.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.RUNTIME_CLASS_KEY, ServiceListener.class);
values.add(bean);
}
factoryMetadata.addProperty("listeners", builder.newCollection().collectionClass(List.class).values(values));
context.getComponentDefinitionRegistry().registerComponentDefinition(factoryMetadata);
return builder.newBean().scope(BeanMetadata.SCOPE_SINGLETON).id(id).factoryComponent(createRef(context, factoryMetadata.getId())).factoryMethod("getServiceMap");
}
private ComponentMetadata decorateCmProperties(ParserContext context, Element element, ComponentMetadata component) {
generateIdIfNeeded(context, ((MutableComponentMetadata<?,?>) component));
MutableBeanMetadata<BeanMetadata> metadata = context.getMetadataBuilder().newBean()
.id(getId(context, element));
metadata.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.PROCESSOR_KEY, true);
metadata.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.RUNTIME_CLASS_KEY, 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.initMethod("init").destroyMethod("destroy");
}
metadata.addProperty("blueprintContainer", createRef(context, "blueprintContainer"))
.addProperty("configAdmin", createConfigAdminProxy(context))
.addProperty("managedObjectManager", createRef(context, MANAGED_OBJECT_MANAGER_NAME))
.addProperty("persistentId", createValue(context, persistentId))
.addProperty("serviceId", createIdRef(context, component.getId()));
if (element.hasAttribute(UPDATE_ATTRIBUTE)) {
metadata.addProperty("update", createValue(context, element.getAttribute(UPDATE_ATTRIBUTE)));
}
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 <bp:bean> element");
}
generateIdIfNeeded(context, ((MutableBeanMetadata<?>) component));
MutableBeanMetadata<BeanMetadata> metadata = context.getMetadataBuilder().newBean()
.id(getId(context, element));
metadata.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.PROCESSOR_KEY, true);
metadata.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.RUNTIME_CLASS_KEY, 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.initMethod("init").destroyMethod("destroy");
}
metadata.addProperty("blueprintContainer", createRef(context, "blueprintContainer"))
.addProperty("configAdmin", createConfigAdminProxy(context))
.addProperty("managedObjectManager", createRef(context, MANAGED_OBJECT_MANAGER_NAME))
.addProperty("persistentId", createValue(context, persistentId))
.addProperty("beanName", createIdRef(context, component.getId()));
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'");
}
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<BeanMetadata> meta = context.getMetadataBuilder().newBean()
.factoryMethod("getConfigAdmin")
.activation(BeanMetadata.ACTIVATION_LAZY)
.scope(BeanMetadata.SCOPE_PROTOTYPE);
meta.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.RUNTIME_CLASS_KEY, CmNamespaceHandler.class);
return meta;
}
private void registerManagedObjectManager(ParserContext context, ComponentDefinitionRegistry registry) {
if (registry.getComponentDefinition(MANAGED_OBJECT_MANAGER_NAME) == null) {
MutableBeanMetadata<BeanMetadata> meta = context.getMetadataBuilder()
.newBean()
.scope(BeanMetadata.SCOPE_SINGLETON)
.id(MANAGED_OBJECT_MANAGER_NAME);
meta.addCustomData(ExtNamespaceHandler.class, ExtNamespaceHandler.RUNTIME_CLASS_KEY, ManagedObjectManager.class);
registry.registerComponentDefinition(meta);
}
}
private static ValueMetadata createValue(ParserContext context, String value) {
return createValue(context, value, null);
}
private static ValueMetadata createValue(ParserContext context, String value, String type) {
return context.getMetadataBuilder().newValue().stringValue(value).type(type);
}
private static RefMetadata createRef(ParserContext context, String value) {
return context.getMetadataBuilder().newRef().componentId(value);
}
private static IdRefMetadata createIdRef(ParserContext context, String value) {
return context.getMetadataBuilder().newIdRef().componentId(value);
}
private static CollectionMetadata createList(ParserContext context, List<String> list) {
Builder builder = context.getMetadataBuilder();
List<ValueMetadata> values = new ArrayList<ValueMetadata>();
for (String v : list) {
values.add(createValue(context, v, String.class.getName()));
}
return builder.newCollection().collectionClass(List.class).valueType(String.class.getName()).values(values);
}
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.id(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<String> parseInterfaceNames(Element element) {
List<String> interfaceNames = new ArrayList<String>();
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;
}
}