2 * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.blueprint.ext;
10 import com.google.common.base.Strings;
11 import java.util.ArrayList;
12 import java.util.Dictionary;
13 import java.util.List;
15 import java.util.Objects;
16 import java.util.concurrent.atomic.AtomicBoolean;
17 import org.apache.aries.blueprint.ComponentDefinitionRegistry;
18 import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
19 import org.apache.aries.blueprint.ext.AbstractPropertyPlaceholder;
20 import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
21 import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata;
22 import org.apache.aries.util.AriesFrameworkUtil;
23 import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
24 import org.osgi.framework.Bundle;
25 import org.osgi.framework.Constants;
26 import org.osgi.framework.FrameworkUtil;
27 import org.osgi.framework.ServiceRegistration;
28 import org.osgi.service.blueprint.reflect.BeanProperty;
29 import org.osgi.service.blueprint.reflect.ComponentMetadata;
30 import org.osgi.service.blueprint.reflect.ValueMetadata;
31 import org.osgi.service.cm.ManagedService;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * The singleton component processor that is invoked by the blueprint container to perform operations on
37 * various component definitions prior to component creation.
39 * @author Thomas Pantelis
41 public class ComponentProcessor implements ComponentDefinitionRegistryProcessor {
42 static final String DEFAULT_TYPE_FILTER = "(|(type=default)(!(type=*)))";
44 private static final Logger LOG = LoggerFactory.getLogger(ComponentProcessor.class);
45 private static final String CM_PERSISTENT_ID_PROPERTY = "persistentId";
47 private final List<ServiceRegistration<?>> managedServiceRegs = new ArrayList<>();
48 private Bundle bundle;
49 private BlueprintContainerRestartService blueprintContainerRestartService;
50 private boolean restartDependentsOnUpdates;
51 private boolean useDefaultForReferenceTypes;
53 public void setBundle(final Bundle bundle) {
57 public void setBlueprintContainerRestartService(final BlueprintContainerRestartService restartService) {
58 blueprintContainerRestartService = restartService;
61 public void setRestartDependentsOnUpdates(final boolean restartDependentsOnUpdates) {
62 this.restartDependentsOnUpdates = restartDependentsOnUpdates;
65 public void setUseDefaultForReferenceTypes(final boolean useDefaultForReferenceTypes) {
66 this.useDefaultForReferenceTypes = useDefaultForReferenceTypes;
69 public void destroy() {
70 for (ServiceRegistration<?> reg: managedServiceRegs) {
71 AriesFrameworkUtil.safeUnregisterService(reg);
76 public void process(final ComponentDefinitionRegistry registry) {
77 LOG.debug("{}: In process", logName());
79 for (String name : registry.getComponentDefinitionNames()) {
80 ComponentMetadata component = registry.getComponentDefinition(name);
81 if (component instanceof MutableBeanMetadata) {
82 processMutableBeanMetadata((MutableBeanMetadata) component);
83 } else if (component instanceof MutableServiceReferenceMetadata) {
84 processServiceReferenceMetadata((MutableServiceReferenceMetadata)component);
89 private void processServiceReferenceMetadata(final MutableServiceReferenceMetadata serviceRef) {
90 if (!useDefaultForReferenceTypes) {
94 String filter = serviceRef.getFilter();
95 String extFilter = serviceRef.getExtendedFilter() == null ? null :
96 serviceRef.getExtendedFilter().getStringValue();
98 LOG.debug("{}: processServiceReferenceMetadata for {}, filter: {}, ext filter: {}", logName(),
99 serviceRef.getId(), filter, extFilter);
101 if (Strings.isNullOrEmpty(filter) && Strings.isNullOrEmpty(extFilter)) {
102 serviceRef.setFilter(DEFAULT_TYPE_FILTER);
104 LOG.debug("{}: processServiceReferenceMetadata for {} set filter to {}", logName(),
105 serviceRef.getId(), serviceRef.getFilter());
109 private void processMutableBeanMetadata(final MutableBeanMetadata bean) {
110 if (restartDependentsOnUpdates && bean.getRuntimeClass() != null
111 && AbstractPropertyPlaceholder.class.isAssignableFrom(bean.getRuntimeClass())) {
112 LOG.debug("{}: Found PropertyPlaceholder bean: {}, runtime {}", logName(), bean.getId(),
113 bean.getRuntimeClass());
115 for (BeanProperty prop : bean.getProperties()) {
116 if (CM_PERSISTENT_ID_PROPERTY.equals(prop.getName())) {
117 if (prop.getValue() instanceof ValueMetadata) {
118 ValueMetadata persistentId = (ValueMetadata)prop.getValue();
120 LOG.debug("{}: Found {} property, value : {}", logName(),
121 CM_PERSISTENT_ID_PROPERTY, persistentId.getStringValue());
123 registerManagedService(persistentId.getStringValue());
125 LOG.debug("{}: {} property metadata {} is not instanceof ValueMetadata",
126 logName(), CM_PERSISTENT_ID_PROPERTY, prop.getValue());
135 private void registerManagedService(final String persistentId) {
136 // Register a ManagedService so we get updates from the ConfigAdmin when the cfg file corresponding
137 // to the persistentId changes.
138 final ManagedService managedService = new ManagedService() {
139 private final AtomicBoolean initialUpdate = new AtomicBoolean(true);
140 private volatile Dictionary<String, ?> previousProperties;
143 public void updated(final Dictionary<String, ?> properties) {
144 LOG.debug("{}: ManagedService updated for persistentId {}, properties: {}, initialUpdate: {}",
145 logName(), persistentId, properties, initialUpdate);
147 // The first update occurs when the service is registered so ignore it as we want subsequent
148 // updates when it changes. The ConfigAdmin will send an update even if the cfg file doesn't
150 if (!initialUpdate.compareAndSet(true, false) && !Objects.equals(previousProperties, properties)) {
151 blueprintContainerRestartService.restartContainerAndDependents(bundle);
154 previousProperties = properties;
158 managedServiceRegs.add(bundle.getBundleContext().registerService(ManagedService.class, managedService,
159 FrameworkUtil.asDictionary(Map.of(
160 Constants.SERVICE_PID, persistentId,
161 Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName(),
162 Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION)))));
165 private String logName() {
166 return bundle.getSymbolicName();