blob: 350f189774d71d38a3c2ad87ca8551b681d1d3c8 [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 {
Pierre De Ropad2121c2013-12-14 07:05:38 +000048 // Our Managed Service Factory PID
49 protected final String m_factoryPid;
50
Marcel Offermans5be5f142011-04-26 10:47:12 +000051 public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate) {
Marcel Offermansfaaed472010-09-08 10:07:32 +000052 super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
Pierre De Ropad2121c2013-12-14 07:05:38 +000053 m_factoryPid = factoryPid;
54
Pierre De Rop3e100372010-05-24 12:43:44 +000055 Hashtable props = new Hashtable();
56 props.put(Constants.SERVICE_PID, factoryPid);
Marcel Offermans66df0b82011-04-27 21:48:41 +000057 m_component
Pierre De Rop3e100372010-05-24 12:43:44 +000058 .setInterface(ManagedServiceFactory.class.getName(), props)
Pierre De Ropad2121c2013-12-14 07:05:38 +000059 .setImplementation(new AdapterImpl(update, propagate))
Xander Uiterlinden652065a2012-07-23 07:00:27 +000060 .setCallbacks("init", null, "stop", null);
Pierre De Rop3e100372010-05-24 12:43:44 +000061 }
62
63 public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate,
Marcel Offermans5be5f142011-04-26 10:47:12 +000064 BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData) {
Marcel Offermansfaaed472010-09-08 10:07:32 +000065 super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
Pierre De Ropad2121c2013-12-14 07:05:38 +000066 m_factoryPid = factoryPid;
Pierre De Rop3e100372010-05-24 12:43:44 +000067 Hashtable props = new Hashtable();
68 props.put(Constants.SERVICE_PID, factoryPid);
Marcel Offermans66df0b82011-04-27 21:48:41 +000069 m_component
Pierre De Ropdf660702010-05-24 12:49:01 +000070 .setInterface(ManagedServiceFactory.class.getName(), props)
Pierre De Ropad2121c2013-12-14 07:05:38 +000071 .setImplementation(new MetaTypeAdapterImpl(update, propagate,
Marcel Offermans5be5f142011-04-26 10:47:12 +000072 bctx, logger, heading, description,
Xander Uiterlinden652065a2012-07-23 07:00:27 +000073 localization, properyMetaData))
74 .setCallbacks("init", null, "stop", null);
Pierre De Rop3e100372010-05-24 12:43:44 +000075 }
76
Pierre De Ropad2121c2013-12-14 07:05:38 +000077 public String getName() {
78 return "Adapter for factory pid " + m_factoryPid;
79 }
80
Pierre De Rop3e100372010-05-24 12:43:44 +000081 /**
82 * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
83 */
Pierre De Rop58f6c392011-05-21 21:30:02 +000084 public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory {
Pierre De Rop3e100372010-05-24 12:43:44 +000085 // The adapter "update" method used to provide the configuration
Pierre De Ropad2121c2013-12-14 07:05:38 +000086 protected final String m_update;
Pierre De Rop3e100372010-05-24 12:43:44 +000087
88 // Tells if the CM config must be propagated along with the adapter service properties
Pierre De Ropad2121c2013-12-14 07:05:38 +000089 protected final boolean m_propagate;
Pierre De Rop3e100372010-05-24 12:43:44 +000090
91 /**
92 * Creates a new CM factory configuration adapter.
93 *
94 * @param factoryPid
95 * @param updateMethod
96 * @param adapterInterface
97 * @param adapterImplementation
98 * @param adapterProperties
99 * @param propagate
100 */
Pierre De Ropad2121c2013-12-14 07:05:38 +0000101 public AdapterImpl(String updateMethod, boolean propagate) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000102 m_update = updateMethod;
103 m_propagate = propagate;
104 }
105
106 /**
107 * Returns the managed service factory name.
108 */
Marcel Offermans5be5f142011-04-26 10:47:12 +0000109 public String getName() {
Pierre De Rop3e100372010-05-24 12:43:44 +0000110 return m_factoryPid;
111 }
112
113 /**
114 * Method called from our superclass, when we need to create a service.
115 */
Marcel Offermansfaaed472010-09-08 10:07:32 +0000116 public Component createService(Object[] properties) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000117 Dictionary settings = (Dictionary) properties[0];
Pierre De Rop58f6c392011-05-21 21:30:02 +0000118 Component newService = m_manager.createComponent();
Pierre De Rop3e100372010-05-24 12:43:44 +0000119 Object impl = null;
120
121 try {
122 if (m_serviceImpl != null) {
Marcel Offermans5be5f142011-04-26 10:47:12 +0000123 impl = (m_serviceImpl instanceof Class) ? ((Class) m_serviceImpl).newInstance() : m_serviceImpl;
124 }
125 else {
Pierre De Rop3e100372010-05-24 12:43:44 +0000126 impl = instantiateFromFactory(m_factory, m_factoryCreateMethod);
127 }
128 InvocationUtil.invokeCallbackMethod(impl, m_update,
129 new Class[][] {{ Dictionary.class }, {}},
130 new Object[][] {{ settings }, {}});
131 }
132
Marcel Offermans5be5f142011-04-26 10:47:12 +0000133 catch (Throwable t) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000134 handleException(t);
135 }
136
137 // Merge adapter service properties, with CM settings
Pierre De Ropb4c58682011-05-24 10:05:44 +0000138 Dictionary serviceProperties = getServiceProperties(settings);
Pierre De Rop3e100372010-05-24 12:43:44 +0000139 newService.setInterface(m_serviceInterfaces, serviceProperties);
140 newService.setImplementation(impl);
Pierre De Rop3e100372010-05-24 12:43:44 +0000141 newService.setComposition(m_compositionInstance, m_compositionMethod); // if not set, no effect
142 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 +0000143 configureAutoConfigState(newService, m_component);
144
145 List dependencies = m_component.getDependencies();
146 for (int i = 0; i < dependencies.size(); i++) {
147 newService.add(((Dependency) dependencies.get(i)).createCopy());
148 }
149
Pierre De Rop3e100372010-05-24 12:43:44 +0000150 for (int i = 0; i < m_stateListeners.size(); i ++) {
Marcel Offermansfaaed472010-09-08 10:07:32 +0000151 newService.addStateListener((ComponentStateListener) m_stateListeners.get(i));
Pierre De Rop3e100372010-05-24 12:43:44 +0000152 }
Pierre De Ropb4c58682011-05-24 10:05:44 +0000153
Pierre De Rop3e100372010-05-24 12:43:44 +0000154 return newService;
155 }
156
157 /**
158 * Method called from our superclass, when we need to update a Service, because
159 * the configuration has changed.
160 */
Marcel Offermans5be5f142011-04-26 10:47:12 +0000161 public void updateService(Object[] properties) {
Pierre De Ropb4c58682011-05-24 10:05:44 +0000162 Dictionary cmSettings = (Dictionary) properties[0];
Marcel Offermansfaaed472010-09-08 10:07:32 +0000163 Component service = (Component) properties[1];
Pierre De Rop3e100372010-05-24 12:43:44 +0000164 Object impl = service.getService();
165
Marcel Offermans5be5f142011-04-26 10:47:12 +0000166 try {
Pierre De Rop3e100372010-05-24 12:43:44 +0000167 InvocationUtil.invokeCallbackMethod(impl, m_update,
168 new Class[][] {{ Dictionary.class }, {}},
Pierre De Ropb4c58682011-05-24 10:05:44 +0000169 new Object[][] {{ cmSettings }, {}});
Pierre De Rop3e100372010-05-24 12:43:44 +0000170 if (m_serviceInterfaces != null && m_propagate == true) {
Pierre De Ropb4c58682011-05-24 10:05:44 +0000171 Dictionary serviceProperties = getServiceProperties(cmSettings);
172 service.setServiceProperties(serviceProperties);
Pierre De Rop3e100372010-05-24 12:43:44 +0000173 }
174 }
175
Marcel Offermans5be5f142011-04-26 10:47:12 +0000176 catch (Throwable t) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000177 handleException(t);
178 }
179 }
180
181 /**
182 * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration
183 * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
184 *
185 * @param adapterProperties
186 * @param settings
187 * @return
188 */
Pierre De Ropb4c58682011-05-24 10:05:44 +0000189 private Dictionary getServiceProperties(Dictionary settings) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000190 Dictionary props = new Hashtable();
191
Pierre De Ropb4c58682011-05-24 10:05:44 +0000192 // Add adapter Service Properties
193 if (m_serviceProperties != null) {
194 Enumeration keys = m_serviceProperties.keys();
Pierre De Rop3e100372010-05-24 12:43:44 +0000195 while (keys.hasMoreElements()) {
196 Object key = keys.nextElement();
Pierre De Ropb4c58682011-05-24 10:05:44 +0000197 Object val = m_serviceProperties.get(key);
Pierre De Rop3e100372010-05-24 12:43:44 +0000198 props.put(key, val);
199 }
200 }
Pierre De Ropb4c58682011-05-24 10:05:44 +0000201
202 if (m_propagate) {
203 // Add CM setting into adapter service properties.
204 // (CM setting will override existing adapter service properties).
205 Enumeration keys = settings.keys();
206 while (keys.hasMoreElements()) {
207 Object key = keys.nextElement();
208 if (! key.toString().startsWith(".")) {
209 // public properties are propagated
210 Object val = settings.get(key);
211 props.put(key, val);
212 }
213 }
214 }
215
Pierre De Rop3e100372010-05-24 12:43:44 +0000216
Pierre De Rop3e100372010-05-24 12:43:44 +0000217 return props;
218 }
219
Marcel Offermans5be5f142011-04-26 10:47:12 +0000220 private Object instantiateFromFactory(Object mFactory, String mFactoryCreateMethod) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000221 Object factory = null;
222 if (m_factory instanceof Class) {
223 try {
224 factory = createInstance((Class) m_factory);
225 }
226 catch (Throwable t) {
227 handleException(t);
228 }
229 }
230 else {
231 factory = m_factory;
232 }
233
234 try {
Marcel Offermans5be5f142011-04-26 10:47:12 +0000235 return InvocationUtil.invokeMethod(factory, factory.getClass(), m_factoryCreateMethod, new Class[][] { {} }, new Object[][] { {} }, false);
Pierre De Rop3e100372010-05-24 12:43:44 +0000236 }
237 catch (Throwable t) {
238 handleException(t);
239 return null;
240 }
241 }
242
243 private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
244 Constructor constructor = clazz.getConstructor(new Class[] {});
245 constructor.setAccessible(true);
246 return clazz.newInstance();
247 }
248
249 private void handleException(Throwable t) {
Marcel Offermans5be5f142011-04-26 10:47:12 +0000250 if (t instanceof InvocationTargetException) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000251 // Our super class will check if the target exception is itself a ConfigurationException.
252 // In this case, it will simply re-thrown.
253 throw new RuntimeException(((InvocationTargetException) t).getTargetException());
Marcel Offermans5be5f142011-04-26 10:47:12 +0000254 }
255 else if (t instanceof RuntimeException) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000256 throw (RuntimeException) t;
Marcel Offermans5be5f142011-04-26 10:47:12 +0000257 }
258 else {
Pierre De Rop3e100372010-05-24 12:43:44 +0000259 throw new RuntimeException(t);
260 }
261 }
262 }
263
264
265 /**
266 * Extends AdapterImpl for MetaType support.
267 */
268 class MetaTypeAdapterImpl extends AdapterImpl implements MetaTypeProvider {
269 // Our MetaType Provider for describing our properties metadata
Pierre De Ropad2121c2013-12-14 07:05:38 +0000270 private final MetaTypeProviderImpl m_metaType;
Pierre De Rop3e100372010-05-24 12:43:44 +0000271
Pierre De Ropad2121c2013-12-14 07:05:38 +0000272 public MetaTypeAdapterImpl(String updateMethod, boolean propagate,
Pierre De Rop3e100372010-05-24 12:43:44 +0000273 BundleContext bctx, Logger logger, String heading,
274 String description, String localization,
Marcel Offermans5be5f142011-04-26 10:47:12 +0000275 PropertyMetaData[] properyMetaData) {
Pierre De Ropad2121c2013-12-14 07:05:38 +0000276 super(updateMethod, propagate);
Pierre De Rop3e100372010-05-24 12:43:44 +0000277 m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
278 m_metaType.setName(heading);
279 m_metaType.setDescription(description);
Marcel Offermans5be5f142011-04-26 10:47:12 +0000280 if (localization != null) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000281 m_metaType.setLocalization(localization);
282 }
Marcel Offermans5be5f142011-04-26 10:47:12 +0000283 for (int i = 0; i < properyMetaData.length; i++) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000284 m_metaType.add(properyMetaData[i]);
285 }
286 }
287
Marcel Offermans5be5f142011-04-26 10:47:12 +0000288 public String[] getLocales() {
Pierre De Rop3e100372010-05-24 12:43:44 +0000289 return m_metaType.getLocales();
290 }
291
Marcel Offermans5be5f142011-04-26 10:47:12 +0000292 public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000293 return m_metaType.getObjectClassDefinition(id, locale);
294 }
295 }
296}