blob: faf6489cbfb44f95c0365175bb518cc69f603d77 [file] [log] [blame]
Pierre De Rop3e100372010-05-24 12:43:44 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.dm.impl;
20
21import java.lang.reflect.Constructor;
22import java.lang.reflect.InvocationTargetException;
23import java.util.Dictionary;
24import java.util.Enumeration;
25import java.util.Hashtable;
26import java.util.List;
27
Marcel Offermans5be5f142011-04-26 10:47:12 +000028import org.apache.felix.dm.Component;
29import org.apache.felix.dm.ComponentStateListener;
Pierre De Ropb4c58682011-05-24 10:05:44 +000030import org.apache.felix.dm.Dependency;
Pierre De Rop3e100372010-05-24 12:43:44 +000031import org.apache.felix.dm.DependencyManager;
Marcel Offermans706fb272010-11-15 12:52:58 +000032import org.apache.felix.dm.InvocationUtil;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000033import org.apache.felix.dm.PropertyMetaData;
Pierre De Rop3e100372010-05-24 12:43:44 +000034import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
35import org.osgi.framework.BundleContext;
Marcel Offermans5be5f142011-04-26 10:47:12 +000036import org.osgi.framework.Constants;
37import org.osgi.service.cm.ManagedServiceFactory;
Pierre De Rop3e100372010-05-24 12:43:44 +000038import org.osgi.service.metatype.MetaTypeProvider;
39import org.osgi.service.metatype.ObjectClassDefinition;
40
41/**
42 * Factory configuration adapter service implementation. This class extends the FilterService in order to catch
43 * some Service methods for configuring actual adapter service implementation.
Marcel Offermans5be5f142011-04-26 10:47:12 +000044 *
45 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
Pierre De Rop3e100372010-05-24 12:43:44 +000046 */
Marcel Offermans5be5f142011-04-26 10:47:12 +000047public class FactoryConfigurationAdapterServiceImpl extends FilterService {
48 public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate) {
Marcel Offermansfaaed472010-09-08 10:07:32 +000049 super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
Pierre De Rop3e100372010-05-24 12:43:44 +000050 Hashtable props = new Hashtable();
51 props.put(Constants.SERVICE_PID, factoryPid);
Marcel Offermans66df0b82011-04-27 21:48:41 +000052 m_component
Pierre De Rop3e100372010-05-24 12:43:44 +000053 .setInterface(ManagedServiceFactory.class.getName(), props)
Xander Uiterlinden652065a2012-07-23 07:00:27 +000054 .setImplementation(new AdapterImpl(factoryPid, update, propagate))
55 .setCallbacks("init", null, "stop", null);
Pierre De Rop3e100372010-05-24 12:43:44 +000056 }
57
58 public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate,
Marcel Offermans5be5f142011-04-26 10:47:12 +000059 BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData) {
Marcel Offermansfaaed472010-09-08 10:07:32 +000060 super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
Pierre De Rop3e100372010-05-24 12:43:44 +000061 Hashtable props = new Hashtable();
62 props.put(Constants.SERVICE_PID, factoryPid);
Marcel Offermans66df0b82011-04-27 21:48:41 +000063 m_component
Pierre De Ropdf660702010-05-24 12:49:01 +000064 .setInterface(ManagedServiceFactory.class.getName(), props)
Pierre De Rop3e100372010-05-24 12:43:44 +000065 .setImplementation(new MetaTypeAdapterImpl(factoryPid, update, propagate,
Marcel Offermans5be5f142011-04-26 10:47:12 +000066 bctx, logger, heading, description,
Xander Uiterlinden652065a2012-07-23 07:00:27 +000067 localization, properyMetaData))
68 .setCallbacks("init", null, "stop", null);
Pierre De Rop3e100372010-05-24 12:43:44 +000069 }
70
71 /**
72 * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
73 */
Pierre De Rop58f6c392011-05-21 21:30:02 +000074 public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory {
Pierre De Rop3e100372010-05-24 12:43:44 +000075 // Our Managed Service Factory PID
76 protected String m_factoryPid;
77
78 // The adapter "update" method used to provide the configuration
79 protected String m_update;
80
81 // Tells if the CM config must be propagated along with the adapter service properties
82 protected boolean m_propagate;
83
84 /**
85 * Creates a new CM factory configuration adapter.
86 *
87 * @param factoryPid
88 * @param updateMethod
89 * @param adapterInterface
90 * @param adapterImplementation
91 * @param adapterProperties
92 * @param propagate
93 */
Marcel Offermans5be5f142011-04-26 10:47:12 +000094 public AdapterImpl(String factoryPid, String updateMethod, boolean propagate) {
Pierre De Rop3e100372010-05-24 12:43:44 +000095 m_factoryPid = factoryPid;
96 m_update = updateMethod;
97 m_propagate = propagate;
98 }
99
100 /**
101 * Returns the managed service factory name.
102 */
Marcel Offermans5be5f142011-04-26 10:47:12 +0000103 public String getName() {
Pierre De Rop3e100372010-05-24 12:43:44 +0000104 return m_factoryPid;
105 }
106
107 /**
108 * Method called from our superclass, when we need to create a service.
109 */
Marcel Offermansfaaed472010-09-08 10:07:32 +0000110 public Component createService(Object[] properties) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000111 Dictionary settings = (Dictionary) properties[0];
Pierre De Rop58f6c392011-05-21 21:30:02 +0000112 Component newService = m_manager.createComponent();
Pierre De Rop3e100372010-05-24 12:43:44 +0000113 Object impl = null;
114
115 try {
116 if (m_serviceImpl != null) {
Marcel Offermans5be5f142011-04-26 10:47:12 +0000117 impl = (m_serviceImpl instanceof Class) ? ((Class) m_serviceImpl).newInstance() : m_serviceImpl;
118 }
119 else {
Pierre De Rop3e100372010-05-24 12:43:44 +0000120 impl = instantiateFromFactory(m_factory, m_factoryCreateMethod);
121 }
122 InvocationUtil.invokeCallbackMethod(impl, m_update,
123 new Class[][] {{ Dictionary.class }, {}},
124 new Object[][] {{ settings }, {}});
125 }
126
Marcel Offermans5be5f142011-04-26 10:47:12 +0000127 catch (Throwable t) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000128 handleException(t);
129 }
130
131 // Merge adapter service properties, with CM settings
Pierre De Ropb4c58682011-05-24 10:05:44 +0000132 Dictionary serviceProperties = getServiceProperties(settings);
Pierre De Rop3e100372010-05-24 12:43:44 +0000133 newService.setInterface(m_serviceInterfaces, serviceProperties);
134 newService.setImplementation(impl);
Pierre De Rop3e100372010-05-24 12:43:44 +0000135 newService.setComposition(m_compositionInstance, m_compositionMethod); // if not set, no effect
136 newService.setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy); // if not set, no effect
Pierre De Ropb4c58682011-05-24 10:05:44 +0000137 configureAutoConfigState(newService, m_component);
138
139 List dependencies = m_component.getDependencies();
140 for (int i = 0; i < dependencies.size(); i++) {
141 newService.add(((Dependency) dependencies.get(i)).createCopy());
142 }
143
Pierre De Rop3e100372010-05-24 12:43:44 +0000144 for (int i = 0; i < m_stateListeners.size(); i ++) {
Marcel Offermansfaaed472010-09-08 10:07:32 +0000145 newService.addStateListener((ComponentStateListener) m_stateListeners.get(i));
Pierre De Rop3e100372010-05-24 12:43:44 +0000146 }
Pierre De Ropb4c58682011-05-24 10:05:44 +0000147
Pierre De Rop3e100372010-05-24 12:43:44 +0000148 return newService;
149 }
150
151 /**
152 * Method called from our superclass, when we need to update a Service, because
153 * the configuration has changed.
154 */
Marcel Offermans5be5f142011-04-26 10:47:12 +0000155 public void updateService(Object[] properties) {
Pierre De Ropb4c58682011-05-24 10:05:44 +0000156 Dictionary cmSettings = (Dictionary) properties[0];
Marcel Offermansfaaed472010-09-08 10:07:32 +0000157 Component service = (Component) properties[1];
Pierre De Rop3e100372010-05-24 12:43:44 +0000158 Object impl = service.getService();
159
Marcel Offermans5be5f142011-04-26 10:47:12 +0000160 try {
Pierre De Rop3e100372010-05-24 12:43:44 +0000161 InvocationUtil.invokeCallbackMethod(impl, m_update,
162 new Class[][] {{ Dictionary.class }, {}},
Pierre De Ropb4c58682011-05-24 10:05:44 +0000163 new Object[][] {{ cmSettings }, {}});
Pierre De Rop3e100372010-05-24 12:43:44 +0000164 if (m_serviceInterfaces != null && m_propagate == true) {
Pierre De Ropb4c58682011-05-24 10:05:44 +0000165 Dictionary serviceProperties = getServiceProperties(cmSettings);
166 service.setServiceProperties(serviceProperties);
Pierre De Rop3e100372010-05-24 12:43:44 +0000167 }
168 }
169
Marcel Offermans5be5f142011-04-26 10:47:12 +0000170 catch (Throwable t) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000171 handleException(t);
172 }
173 }
174
175 /**
176 * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration
177 * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
178 *
179 * @param adapterProperties
180 * @param settings
181 * @return
182 */
Pierre De Ropb4c58682011-05-24 10:05:44 +0000183 private Dictionary getServiceProperties(Dictionary settings) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000184 Dictionary props = new Hashtable();
185
Pierre De Ropb4c58682011-05-24 10:05:44 +0000186 // Add adapter Service Properties
187 if (m_serviceProperties != null) {
188 Enumeration keys = m_serviceProperties.keys();
Pierre De Rop3e100372010-05-24 12:43:44 +0000189 while (keys.hasMoreElements()) {
190 Object key = keys.nextElement();
Pierre De Ropb4c58682011-05-24 10:05:44 +0000191 Object val = m_serviceProperties.get(key);
Pierre De Rop3e100372010-05-24 12:43:44 +0000192 props.put(key, val);
193 }
194 }
Pierre De Ropb4c58682011-05-24 10:05:44 +0000195
196 if (m_propagate) {
197 // Add CM setting into adapter service properties.
198 // (CM setting will override existing adapter service properties).
199 Enumeration keys = settings.keys();
200 while (keys.hasMoreElements()) {
201 Object key = keys.nextElement();
202 if (! key.toString().startsWith(".")) {
203 // public properties are propagated
204 Object val = settings.get(key);
205 props.put(key, val);
206 }
207 }
208 }
209
Pierre De Rop3e100372010-05-24 12:43:44 +0000210
Pierre De Rop3e100372010-05-24 12:43:44 +0000211 return props;
212 }
213
Marcel Offermans5be5f142011-04-26 10:47:12 +0000214 private Object instantiateFromFactory(Object mFactory, String mFactoryCreateMethod) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000215 Object factory = null;
216 if (m_factory instanceof Class) {
217 try {
218 factory = createInstance((Class) m_factory);
219 }
220 catch (Throwable t) {
221 handleException(t);
222 }
223 }
224 else {
225 factory = m_factory;
226 }
227
228 try {
Marcel Offermans5be5f142011-04-26 10:47:12 +0000229 return InvocationUtil.invokeMethod(factory, factory.getClass(), m_factoryCreateMethod, new Class[][] { {} }, new Object[][] { {} }, false);
Pierre De Rop3e100372010-05-24 12:43:44 +0000230 }
231 catch (Throwable t) {
232 handleException(t);
233 return null;
234 }
235 }
236
237 private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
238 Constructor constructor = clazz.getConstructor(new Class[] {});
239 constructor.setAccessible(true);
240 return clazz.newInstance();
241 }
242
243 private void handleException(Throwable t) {
Marcel Offermans5be5f142011-04-26 10:47:12 +0000244 if (t instanceof InvocationTargetException) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000245 // Our super class will check if the target exception is itself a ConfigurationException.
246 // In this case, it will simply re-thrown.
247 throw new RuntimeException(((InvocationTargetException) t).getTargetException());
Marcel Offermans5be5f142011-04-26 10:47:12 +0000248 }
249 else if (t instanceof RuntimeException) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000250 throw (RuntimeException) t;
Marcel Offermans5be5f142011-04-26 10:47:12 +0000251 }
252 else {
Pierre De Rop3e100372010-05-24 12:43:44 +0000253 throw new RuntimeException(t);
254 }
255 }
256 }
257
258
259 /**
260 * Extends AdapterImpl for MetaType support.
261 */
262 class MetaTypeAdapterImpl extends AdapterImpl implements MetaTypeProvider {
263 // Our MetaType Provider for describing our properties metadata
264 private MetaTypeProviderImpl m_metaType;
265
266 public MetaTypeAdapterImpl(String factoryPid, String updateMethod, boolean propagate,
267 BundleContext bctx, Logger logger, String heading,
268 String description, String localization,
Marcel Offermans5be5f142011-04-26 10:47:12 +0000269 PropertyMetaData[] properyMetaData) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000270 super(factoryPid, updateMethod, propagate);
271 m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
272 m_metaType.setName(heading);
273 m_metaType.setDescription(description);
Marcel Offermans5be5f142011-04-26 10:47:12 +0000274 if (localization != null) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000275 m_metaType.setLocalization(localization);
276 }
Marcel Offermans5be5f142011-04-26 10:47:12 +0000277 for (int i = 0; i < properyMetaData.length; i++) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000278 m_metaType.add(properyMetaData[i]);
279 }
280 }
281
Marcel Offermans5be5f142011-04-26 10:47:12 +0000282 public String[] getLocales() {
Pierre De Rop3e100372010-05-24 12:43:44 +0000283 return m_metaType.getLocales();
284 }
285
Marcel Offermans5be5f142011-04-26 10:47:12 +0000286 public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000287 return m_metaType.getObjectClassDefinition(id, locale);
288 }
289 }
290}