Use FrameworkUtil.asDictionary()
[controller.git] / opendaylight / blueprint / src / main / java / org / opendaylight / controller / blueprint / ext / ComponentProcessor.java
1 /*
2  * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.blueprint.ext;
9
10 import com.google.common.base.Strings;
11 import java.util.ArrayList;
12 import java.util.Dictionary;
13 import java.util.List;
14 import java.util.Map;
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.gaul.modernizer_maven_annotations.SuppressModernizer;
24 import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
25 import org.osgi.framework.Bundle;
26 import org.osgi.framework.Constants;
27 import org.osgi.framework.FrameworkUtil;
28 import org.osgi.framework.ServiceRegistration;
29 import org.osgi.service.blueprint.reflect.BeanProperty;
30 import org.osgi.service.blueprint.reflect.ComponentMetadata;
31 import org.osgi.service.blueprint.reflect.ValueMetadata;
32 import org.osgi.service.cm.ManagedService;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * The singleton component processor that is invoked by the blueprint container to perform operations on
38  * various component definitions prior to component creation.
39  *
40  * @author Thomas Pantelis
41  */
42 public class ComponentProcessor implements ComponentDefinitionRegistryProcessor {
43     static final String DEFAULT_TYPE_FILTER = "(|(type=default)(!(type=*)))";
44
45     private static final Logger LOG = LoggerFactory.getLogger(ComponentProcessor.class);
46     private static final String CM_PERSISTENT_ID_PROPERTY = "persistentId";
47
48     private final List<ServiceRegistration<?>> managedServiceRegs = new ArrayList<>();
49     private Bundle bundle;
50     private BlueprintContainerRestartService blueprintContainerRestartService;
51     private boolean restartDependentsOnUpdates;
52     private boolean useDefaultForReferenceTypes;
53
54     public void setBundle(final Bundle bundle) {
55         this.bundle = bundle;
56     }
57
58     public void setBlueprintContainerRestartService(final BlueprintContainerRestartService restartService) {
59         blueprintContainerRestartService = restartService;
60     }
61
62     public void setRestartDependentsOnUpdates(final boolean restartDependentsOnUpdates) {
63         this.restartDependentsOnUpdates = restartDependentsOnUpdates;
64     }
65
66     public void setUseDefaultForReferenceTypes(final boolean useDefaultForReferenceTypes) {
67         this.useDefaultForReferenceTypes = useDefaultForReferenceTypes;
68     }
69
70     public void destroy() {
71         for (ServiceRegistration<?> reg: managedServiceRegs) {
72             AriesFrameworkUtil.safeUnregisterService(reg);
73         }
74     }
75
76     @Override
77     public void process(final ComponentDefinitionRegistry registry) {
78         LOG.debug("{}: In process",  logName());
79
80         for (String name : registry.getComponentDefinitionNames()) {
81             ComponentMetadata component = registry.getComponentDefinition(name);
82             if (component instanceof MutableBeanMetadata) {
83                 processMutableBeanMetadata((MutableBeanMetadata) component);
84             } else if (component instanceof MutableServiceReferenceMetadata) {
85                 processServiceReferenceMetadata((MutableServiceReferenceMetadata)component);
86             }
87         }
88     }
89
90     private void processServiceReferenceMetadata(final MutableServiceReferenceMetadata serviceRef) {
91         if (!useDefaultForReferenceTypes) {
92             return;
93         }
94
95         String filter = serviceRef.getFilter();
96         String extFilter = serviceRef.getExtendedFilter() == null ? null :
97             serviceRef.getExtendedFilter().getStringValue();
98
99         LOG.debug("{}: processServiceReferenceMetadata for {}, filter: {}, ext filter: {}", logName(),
100                 serviceRef.getId(), filter, extFilter);
101
102         if (Strings.isNullOrEmpty(filter) && Strings.isNullOrEmpty(extFilter)) {
103             serviceRef.setFilter(DEFAULT_TYPE_FILTER);
104
105             LOG.debug("{}: processServiceReferenceMetadata for {} set filter to {}", logName(),
106                     serviceRef.getId(), serviceRef.getFilter());
107         }
108     }
109
110     private void processMutableBeanMetadata(final MutableBeanMetadata bean) {
111         if (restartDependentsOnUpdates && bean.getRuntimeClass() != null
112                 && AbstractPropertyPlaceholder.class.isAssignableFrom(bean.getRuntimeClass())) {
113             LOG.debug("{}: Found PropertyPlaceholder bean: {}, runtime {}", logName(), bean.getId(),
114                     bean.getRuntimeClass());
115
116             for (BeanProperty prop : bean.getProperties()) {
117                 if (CM_PERSISTENT_ID_PROPERTY.equals(prop.getName())) {
118                     if (prop.getValue() instanceof ValueMetadata) {
119                         ValueMetadata persistentId = (ValueMetadata)prop.getValue();
120
121                         LOG.debug("{}: Found {} property, value : {}", logName(),
122                                 CM_PERSISTENT_ID_PROPERTY, persistentId.getStringValue());
123
124                         registerManagedService(persistentId.getStringValue());
125                     } else {
126                         LOG.debug("{}: {} property metadata {} is not instanceof ValueMetadata",
127                                 logName(), CM_PERSISTENT_ID_PROPERTY, prop.getValue());
128                     }
129
130                     break;
131                 }
132             }
133         }
134     }
135
136     @SuppressModernizer
137     private void registerManagedService(final String persistentId) {
138         // Register a ManagedService so we get updates from the ConfigAdmin when the cfg file corresponding
139         // to the persistentId changes.
140         final ManagedService managedService = new ManagedService() {
141             private final AtomicBoolean initialUpdate = new AtomicBoolean(true);
142             private volatile Dictionary<String, ?> previousProperties;
143
144             @Override
145             public void updated(final Dictionary<String, ?> properties) {
146                 LOG.debug("{}: ManagedService updated for persistentId {}, properties: {}, initialUpdate: {}",
147                         logName(), persistentId, properties, initialUpdate);
148
149                 // The first update occurs when the service is registered so ignore it as we want subsequent
150                 // updates when it changes. The ConfigAdmin will send an update even if the cfg file doesn't
151                 // yet exist.
152                 if (!initialUpdate.compareAndSet(true, false) && !Objects.equals(previousProperties, properties)) {
153                     blueprintContainerRestartService.restartContainerAndDependents(bundle);
154                 }
155
156                 previousProperties = properties;
157             }
158         };
159
160         managedServiceRegs.add(bundle.getBundleContext().registerService(ManagedService.class, managedService,
161             FrameworkUtil.asDictionary(Map.of(
162                 Constants.SERVICE_PID, persistentId,
163                 Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName(),
164                 Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION)))));
165     }
166
167     private String logName() {
168         return bundle.getSymbolicName();
169     }
170 }