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