Add restart-dependents-on-update blueprint extension
[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 java.util.ArrayList;
11 import java.util.Dictionary;
12 import java.util.Hashtable;
13 import java.util.List;
14 import org.apache.aries.blueprint.ComponentDefinitionRegistry;
15 import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
16 import org.apache.aries.blueprint.ext.AbstractPropertyPlaceholder;
17 import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
18 import org.apache.aries.util.AriesFrameworkUtil;
19 import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
20 import org.osgi.framework.Bundle;
21 import org.osgi.framework.Constants;
22 import org.osgi.framework.ServiceRegistration;
23 import org.osgi.service.blueprint.reflect.BeanProperty;
24 import org.osgi.service.blueprint.reflect.ComponentMetadata;
25 import org.osgi.service.blueprint.reflect.ValueMetadata;
26 import org.osgi.service.cm.ManagedService;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * The singleton component processor that is invoked by the blueprint container to perform operations on
32  * various component definitions prior to component creation.
33  *
34  * @author Thomas Pantelis
35  */
36 public class ComponentProcessor implements ComponentDefinitionRegistryProcessor {
37     private static final Logger LOG = LoggerFactory.getLogger(ComponentProcessor.class);
38     private static final String CM_PERSISTENT_ID_PROPERTY = "persistentId";
39
40     private final List<ServiceRegistration<?>> managedServiceRegs = new ArrayList<>();
41     private Bundle bundle;
42     private BlueprintContainerRestartService blueprintContainerRestartService;
43     private boolean restartDependentsOnUpdates;
44
45     public void setBundle(Bundle bundle) {
46         this.bundle = bundle;
47     }
48
49     public void setBlueprintContainerRestartService(BlueprintContainerRestartService restartService) {
50         this.blueprintContainerRestartService = restartService;
51     }
52
53     public void setRestartDependentsOnUpdates(boolean restartDependentsOnUpdates) {
54         this.restartDependentsOnUpdates = restartDependentsOnUpdates;
55     }
56
57     public void destroy() {
58         for(ServiceRegistration<?> reg: managedServiceRegs) {
59             AriesFrameworkUtil.safeUnregisterService(reg);
60         }
61     }
62
63     @Override
64     public void process(ComponentDefinitionRegistry registry) {
65         LOG.debug("{}: In process", bundle.getSymbolicName());
66
67         for(String name : registry.getComponentDefinitionNames()) {
68             ComponentMetadata component = registry.getComponentDefinition(name);
69             if(component instanceof MutableBeanMetadata) {
70                 processMutableBeanMetadata((MutableBeanMetadata)component);
71             }
72         }
73     }
74
75     private void processMutableBeanMetadata(MutableBeanMetadata bean) {
76         if(restartDependentsOnUpdates && bean.getRuntimeClass() != null &&
77                 AbstractPropertyPlaceholder.class.isAssignableFrom(bean.getRuntimeClass())) {
78             LOG.debug("{}: Found PropertyPlaceholder bean: {}, runtime {}", bundle.getSymbolicName(), bean.getId(),
79                     bean.getRuntimeClass());
80
81             for(BeanProperty prop: bean.getProperties()) {
82                 if(CM_PERSISTENT_ID_PROPERTY.equals(prop.getName())) {
83                     if(prop.getValue() instanceof ValueMetadata) {
84                         ValueMetadata persistentId = (ValueMetadata)prop.getValue();
85
86                         LOG.debug("{}: Found {} property, value : {}", bundle.getSymbolicName(),
87                                 CM_PERSISTENT_ID_PROPERTY, persistentId.getStringValue());
88
89                         registerManagedService(persistentId.getStringValue());
90                     } else {
91                         LOG.debug("{}: {} property metadata {} is not instanceof ValueMetadata",
92                                 bundle.getSymbolicName(), CM_PERSISTENT_ID_PROPERTY, prop.getValue());
93                     }
94
95                     break;
96                 }
97             }
98         }
99     }
100
101     private void registerManagedService(final String persistentId) {
102         // Register a ManagedService so we git updates from the ConfigAdmin when the cfg file corresponding
103         // to the persistentId changes.
104         ManagedService managedService = new ManagedService() {
105             private volatile boolean initialUpdate = true;
106
107             @Override
108             public void updated(Dictionary<String, ?> properties) {
109                 LOG.debug("{}: ManagedService updated for persistentId {}, properties: {}, initialUpdate: {}",
110                         bundle.getSymbolicName(), persistentId, properties, initialUpdate);
111
112                 // The first update occurs when the service is registered so ignore it as we want subsequent
113                 // updates when it changes. The ConfigAdmin will send an update even if the cfg file doesn't
114                 // yet exist.
115                 if(initialUpdate) {
116                     initialUpdate = false;
117                 } else {
118                     blueprintContainerRestartService.restartContainerAndDependents(bundle);
119                 }
120             }
121         };
122
123         Dictionary<String, Object> props = new Hashtable<>();
124         props.put(Constants.SERVICE_PID, persistentId);
125         props.put(Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName());
126         props.put(Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION));
127         managedServiceRegs.add(bundle.getBundleContext().registerService(ManagedService.class.getName(),
128                 managedService, props));
129     }
130 }