*/
package org.opendaylight.controller.blueprint.ext;
+import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
import org.apache.aries.blueprint.ext.AbstractPropertyPlaceholder;
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
+import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata;
import org.apache.aries.util.AriesFrameworkUtil;
import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
import org.osgi.framework.Bundle;
private Bundle bundle;
private BlueprintContainerRestartService blueprintContainerRestartService;
private boolean restartDependentsOnUpdates;
+ private boolean useDefaultForReferenceTypes;
public void setBundle(Bundle bundle) {
this.bundle = bundle;
this.restartDependentsOnUpdates = restartDependentsOnUpdates;
}
+ public void setUseDefaultForReferenceTypes(boolean useDefaultForReferenceTypes) {
+ this.useDefaultForReferenceTypes = useDefaultForReferenceTypes;
+ }
+
public void destroy() {
for(ServiceRegistration<?> reg: managedServiceRegs) {
AriesFrameworkUtil.safeUnregisterService(reg);
@Override
public void process(ComponentDefinitionRegistry registry) {
- LOG.debug("{}: In process", bundle.getSymbolicName());
+ LOG.debug("{}: In process", logName());
for(String name : registry.getComponentDefinitionNames()) {
ComponentMetadata component = registry.getComponentDefinition(name);
if(component instanceof MutableBeanMetadata) {
processMutableBeanMetadata((MutableBeanMetadata)component);
+ } else if(component instanceof MutableServiceReferenceMetadata) {
+ processServiceReferenceMetadata((MutableServiceReferenceMetadata)component);
}
}
}
+ private void processServiceReferenceMetadata(MutableServiceReferenceMetadata serviceRef) {
+ if(!useDefaultForReferenceTypes) {
+ return;
+ }
+
+ String filter = serviceRef.getFilter();
+ String extFilter = serviceRef.getExtendedFilter() == null ? null :
+ serviceRef.getExtendedFilter().getStringValue();
+
+ LOG.debug("{}: processServiceReferenceMetadata for {}, filter: {}, ext filter: {}", logName(),
+ serviceRef.getId(), filter, extFilter);
+
+ if(Strings.isNullOrEmpty(filter) && Strings.isNullOrEmpty(extFilter)) {
+ serviceRef.setFilter("(|(type=default)(!(type=*)))");
+
+ LOG.debug("{}: processServiceReferenceMetadata for {} set filter to {}", logName(),
+ serviceRef.getId(), serviceRef.getFilter());
+ }
+ }
+
private void processMutableBeanMetadata(MutableBeanMetadata bean) {
if(restartDependentsOnUpdates && bean.getRuntimeClass() != null &&
AbstractPropertyPlaceholder.class.isAssignableFrom(bean.getRuntimeClass())) {
- LOG.debug("{}: Found PropertyPlaceholder bean: {}, runtime {}", bundle.getSymbolicName(), bean.getId(),
+ LOG.debug("{}: Found PropertyPlaceholder bean: {}, runtime {}", logName(), bean.getId(),
bean.getRuntimeClass());
for(BeanProperty prop: bean.getProperties()) {
if(prop.getValue() instanceof ValueMetadata) {
ValueMetadata persistentId = (ValueMetadata)prop.getValue();
- LOG.debug("{}: Found {} property, value : {}", bundle.getSymbolicName(),
+ LOG.debug("{}: Found {} property, value : {}", logName(),
CM_PERSISTENT_ID_PROPERTY, persistentId.getStringValue());
registerManagedService(persistentId.getStringValue());
} else {
LOG.debug("{}: {} property metadata {} is not instanceof ValueMetadata",
- bundle.getSymbolicName(), CM_PERSISTENT_ID_PROPERTY, prop.getValue());
+ logName(), CM_PERSISTENT_ID_PROPERTY, prop.getValue());
}
break;
@Override
public void updated(Dictionary<String, ?> properties) {
LOG.debug("{}: ManagedService updated for persistentId {}, properties: {}, initialUpdate: {}",
- bundle.getSymbolicName(), persistentId, properties, initialUpdate);
+ logName(), persistentId, properties, initialUpdate);
// The first update occurs when the service is registered so ignore it as we want subsequent
// updates when it changes. The ConfigAdmin will send an update even if the cfg file doesn't
managedServiceRegs.add(bundle.getBundleContext().registerService(ManagedService.class.getName(),
managedService, props));
}
+
+ private String logName() {
+ return bundle.getSymbolicName();
+ }
}
*/
package org.opendaylight.controller.blueprint.ext;
+import com.google.common.base.Strings;
import java.net.URL;
import java.util.Collections;
import java.util.Set;
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
import org.apache.aries.blueprint.mutable.MutableRefMetadata;
import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
+import org.apache.aries.blueprint.mutable.MutableServiceMetadata;
+import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata;
import org.apache.aries.blueprint.mutable.MutableValueMetadata;
import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
import org.osgi.service.blueprint.reflect.Metadata;
import org.osgi.service.blueprint.reflect.RefMetadata;
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
+import org.osgi.service.blueprint.reflect.ServiceMetadata;
+import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
import org.osgi.service.blueprint.reflect.ValueMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(OpendaylightNamespaceHandler.class);
private static final String COMPONENT_PROCESSOR_NAME = ComponentProcessor.class.getName();
private static final String RESTART_DEPENDENTS_ON_UPDATES = "restart-dependents-on-updates";
+ private static final String USE_DEFAULT_FOR_REFERENCE_TYPES = "use-default-for-reference-types";
+ private static final String TYPE_ATTR = "type";
@SuppressWarnings("rawtypes")
@Override
if(node instanceof Attr) {
if (nodeNameEquals(node, RESTART_DEPENDENTS_ON_UPDATES)) {
return decorateRestartDependentsOnUpdates((Attr)node, component, context);
+ } else if (nodeNameEquals(node, USE_DEFAULT_FOR_REFERENCE_TYPES)) {
+ return decorateUseDefaultForReferenceTypes((Attr)node, component, context);
+ } else if (nodeNameEquals(node, TYPE_ATTR)) {
+ if(component instanceof ServiceReferenceMetadata) {
+ return decorateServiceReferenceType((Attr)node, component, context);
+ } else if(component instanceof ServiceMetadata) {
+ return decorateServiceType((Attr)node, component, context);
+ }
+
+ throw new ComponentDefinitionException("Attribute " + node.getNodeName() +
+ " can only be used on a <reference>, <reference-list> or <service> element");
}
throw new ComponentDefinitionException("Unsupported attribute: " + node.getNodeName());
}
}
+ private ComponentMetadata decorateServiceType(Attr attr, ComponentMetadata component, ParserContext context) {
+ if (!(component instanceof MutableServiceMetadata)) {
+ throw new ComponentDefinitionException("Expected an instanceof MutableServiceMetadata");
+ }
+
+ MutableServiceMetadata service = (MutableServiceMetadata)component;
+
+ LOG.debug("decorateServiceType for {} - adding type property {}", service.getId(), attr.getValue());
+
+ service.addServiceProperty(createValue(context, TYPE_ATTR), createValue(context, attr.getValue()));
+ return component;
+ }
+
+ private ComponentMetadata decorateServiceReferenceType(Attr attr, ComponentMetadata component, ParserContext context) {
+ if (!(component instanceof MutableServiceReferenceMetadata)) {
+ throw new ComponentDefinitionException("Expected an instanceof MutableServiceReferenceMetadata");
+ }
+
+ // We don't actually need the ComponentProcessor for augmenting the OSGi filter here but we create it
+ // to workaround an issue in Aries where it doesn't use the extended filter unless there's a
+ // Processor or ComponentDefinitionRegistryProcessor registered. This may actually be working as
+ // designed in Aries b/c the extended filter was really added to allow the OSGi filter to be
+ // substituted by a variable via the "cm:property-placeholder" processor. If so, it's a bit funky
+ // but as long as there's at least one processor registered, it correctly uses the extended filter.
+ registerComponentProcessor(context);
+
+ MutableServiceReferenceMetadata serviceRef = (MutableServiceReferenceMetadata)component;
+ String oldFilter = serviceRef.getExtendedFilter() == null ? null :
+ serviceRef.getExtendedFilter().getStringValue();
+
+ String filter;
+ if(Strings.isNullOrEmpty(oldFilter)) {
+ filter = String.format("(type=%s)", attr.getValue());
+ } else {
+ filter = String.format("(&(%s)(type=%s))", oldFilter, attr.getValue());
+ }
+
+ LOG.debug("decorateServiceReferenceType for {} with type {}, old filter: {}, new filter: {}",
+ serviceRef.getId(), attr.getValue(), oldFilter, filter);
+
+ serviceRef.setExtendedFilter(createValue(context, filter));
+ return component;
+ }
+
private static ComponentMetadata decorateRestartDependentsOnUpdates(Attr attr, ComponentMetadata component,
ParserContext context) {
+ return enableComponentProcessorProperty(attr, component, context, "restartDependentsOnUpdates");
+ }
+
+ private static ComponentMetadata decorateUseDefaultForReferenceTypes(Attr attr, ComponentMetadata component,
+ ParserContext context) {
+ return enableComponentProcessorProperty(attr, component, context, "useDefaultForReferenceTypes");
+ }
+
+ private static ComponentMetadata enableComponentProcessorProperty(Attr attr, ComponentMetadata component,
+ ParserContext context, String propertyName) {
if(component != null) {
throw new ComponentDefinitionException("Attribute " + attr.getNodeName() +
" can only be used on the root <blueprint> element");
}
- LOG.debug("decorateRestartDependentsOnUpdates: {}", attr.getValue());
+ LOG.debug("{}: {}", propertyName, attr.getValue());
if(!Boolean.TRUE.equals(Boolean.valueOf(attr.getValue()))) {
return component;
}
MutableBeanMetadata metadata = registerComponentProcessor(context);
- metadata.addProperty("restartDependentsOnUpdates", createValue(context, "true"));
+ metadata.addProperty(propertyName, createValue(context, "true"));
return component;
}