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