blob: 972aa2502039c4fdf5529300854cb5e06ac3016b [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
28import org.apache.felix.dm.DependencyManager;
Marcel Offermans706fb272010-11-15 12:52:58 +000029import org.apache.felix.dm.InvocationUtil;
Marcel Offermans8b93efa2010-07-02 18:27:21 +000030import org.apache.felix.dm.PropertyMetaData;
Marcel Offermansfaaed472010-09-08 10:07:32 +000031import org.apache.felix.dm.Component;
32import org.apache.felix.dm.ComponentStateListener;
Pierre De Rop3e100372010-05-24 12:43:44 +000033import org.osgi.framework.Constants;
34import org.osgi.service.cm.ManagedServiceFactory;
Pierre De Rop3e100372010-05-24 12:43:44 +000035import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
36import org.osgi.framework.BundleContext;
37import org.osgi.service.metatype.MetaTypeProvider;
38import org.osgi.service.metatype.ObjectClassDefinition;
39
40/**
41 * Factory configuration adapter service implementation. This class extends the FilterService in order to catch
42 * some Service methods for configuring actual adapter service implementation.
43 */
44public class FactoryConfigurationAdapterServiceImpl extends FilterService
45{
46 public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate)
47 {
Marcel Offermansfaaed472010-09-08 10:07:32 +000048 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 +000049 Hashtable props = new Hashtable();
50 props.put(Constants.SERVICE_PID, factoryPid);
51 m_service
52 .setInterface(ManagedServiceFactory.class.getName(), props)
53 .setImplementation(new AdapterImpl(factoryPid, update, propagate));
54 }
55
56 public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate,
57 BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData)
58 {
Marcel Offermansfaaed472010-09-08 10:07:32 +000059 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 +000060 Hashtable props = new Hashtable();
61 props.put(Constants.SERVICE_PID, factoryPid);
Pierre De Rop3e100372010-05-24 12:43:44 +000062 m_service
Pierre De Ropdf660702010-05-24 12:49:01 +000063 .setInterface(ManagedServiceFactory.class.getName(), props)
Pierre De Rop3e100372010-05-24 12:43:44 +000064 .setImplementation(new MetaTypeAdapterImpl(factoryPid, update, propagate,
65 bctx, logger, heading, description,
66 localization, properyMetaData));
67 }
68
69 /**
70 * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
71 */
72 public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory
73 {
74 // Our injected dependency manager
75 protected volatile DependencyManager m_dm;
76
77 // Our Managed Service Factory PID
78 protected String m_factoryPid;
79
80 // The adapter "update" method used to provide the configuration
81 protected String m_update;
82
83 // Tells if the CM config must be propagated along with the adapter service properties
84 protected boolean m_propagate;
85
86 /**
87 * Creates a new CM factory configuration adapter.
88 *
89 * @param factoryPid
90 * @param updateMethod
91 * @param adapterInterface
92 * @param adapterImplementation
93 * @param adapterProperties
94 * @param propagate
95 */
96 public AdapterImpl(String factoryPid, String updateMethod, boolean propagate)
97 {
98 m_factoryPid = factoryPid;
99 m_update = updateMethod;
100 m_propagate = propagate;
101 }
102
103 /**
104 * Returns the managed service factory name.
105 */
106 public String getName()
107 {
108 return m_factoryPid;
109 }
110
111 /**
112 * Method called from our superclass, when we need to create a service.
113 */
Marcel Offermansfaaed472010-09-08 10:07:32 +0000114 public Component createService(Object[] properties) {
Pierre De Rop3e100372010-05-24 12:43:44 +0000115 Dictionary settings = (Dictionary) properties[0];
Marcel Offermansfaaed472010-09-08 10:07:32 +0000116 Component newService = m_dm.createComponent();
Pierre De Rop3e100372010-05-24 12:43:44 +0000117 Object impl = null;
118
119 try {
120 if (m_serviceImpl != null) {
121 impl = (m_serviceImpl instanceof Class) ?
122 ((Class) m_serviceImpl).newInstance() : m_serviceImpl;
123 } else {
124 impl = instantiateFromFactory(m_factory, m_factoryCreateMethod);
125 }
126 InvocationUtil.invokeCallbackMethod(impl, m_update,
127 new Class[][] {{ Dictionary.class }, {}},
128 new Object[][] {{ settings }, {}});
129 }
130
131 catch (Throwable t)
132 {
133 handleException(t);
134 }
135
136 // Merge adapter service properties, with CM settings
137 Dictionary serviceProperties = m_propagate ? mergeSettings(m_serviceProperties, settings) : m_serviceProperties;
138 newService.setInterface(m_serviceInterfaces, serviceProperties);
139 newService.setImplementation(impl);
140 List dependencies = m_service.getDependencies();
141 newService.add(dependencies);
142 newService.setComposition(m_compositionInstance, m_compositionMethod); // if not set, no effect
143 newService.setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy); // if not set, no effect
144 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 }
147
148 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 */
155 public void updateService(Object[] properties)
156 {
157 Dictionary settings = (Dictionary) properties[0];
Marcel Offermansfaaed472010-09-08 10:07:32 +0000158 Component service = (Component) properties[1];
Pierre De Rop3e100372010-05-24 12:43:44 +0000159 Object impl = service.getService();
160
161 try
162 {
163 InvocationUtil.invokeCallbackMethod(impl, m_update,
164 new Class[][] {{ Dictionary.class }, {}},
165 new Object[][] {{ settings }, {}});
166 if (m_serviceInterfaces != null && m_propagate == true) {
167 settings = mergeSettings(m_serviceProperties, settings);
168 service.setServiceProperties(settings);
169 }
170 }
171
172 catch (Throwable t)
173 {
174 handleException(t);
175 }
176 }
177
178 /**
179 * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration
180 * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
181 *
182 * @param adapterProperties
183 * @param settings
184 * @return
185 */
186 private Dictionary mergeSettings(Dictionary adapterProperties, Dictionary settings)
187 {
188 Dictionary props = new Hashtable();
189
190 if (adapterProperties != null) {
191 Enumeration keys = adapterProperties.keys();
192 while (keys.hasMoreElements()) {
193 Object key = keys.nextElement();
194 Object val = adapterProperties.get(key);
195 props.put(key, val);
196 }
197 }
198
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 return props;
209 }
210
211 private Object instantiateFromFactory(Object mFactory, String mFactoryCreateMethod)
212 {
213 Object factory = null;
214 if (m_factory instanceof Class) {
215 try {
216 factory = createInstance((Class) m_factory);
217 }
218 catch (Throwable t) {
219 handleException(t);
220 }
221 }
222 else {
223 factory = m_factory;
224 }
225
226 try {
227 return InvocationUtil.invokeMethod(factory, factory.getClass(), m_factoryCreateMethod,
228 new Class[][] {{}}, new Object[][] {{}}, false);
229 }
230 catch (Throwable t) {
231 handleException(t);
232 return null;
233 }
234 }
235
236 private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
237 Constructor constructor = clazz.getConstructor(new Class[] {});
238 constructor.setAccessible(true);
239 return clazz.newInstance();
240 }
241
242 private void handleException(Throwable t) {
243 if (t instanceof InvocationTargetException)
244 {
245 // 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());
248 } else if (t instanceof RuntimeException) {
249 throw (RuntimeException) t;
250 } else {
251 throw new RuntimeException(t);
252 }
253 }
254 }
255
256
257 /**
258 * Extends AdapterImpl for MetaType support.
259 */
260 class MetaTypeAdapterImpl extends AdapterImpl implements MetaTypeProvider {
261 // Our MetaType Provider for describing our properties metadata
262 private MetaTypeProviderImpl m_metaType;
263
264 public MetaTypeAdapterImpl(String factoryPid, String updateMethod, boolean propagate,
265 BundleContext bctx, Logger logger, String heading,
266 String description, String localization,
267 PropertyMetaData[] properyMetaData)
268 {
269 super(factoryPid, updateMethod, propagate);
270 m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
271 m_metaType.setName(heading);
272 m_metaType.setDescription(description);
273 if (localization != null)
274 {
275 m_metaType.setLocalization(localization);
276 }
277 for (int i = 0; i < properyMetaData.length; i ++)
278 {
279 m_metaType.add(properyMetaData[i]);
280 }
281 }
282
283 public String[] getLocales()
284 {
285 return m_metaType.getLocales();
286 }
287
288 public ObjectClassDefinition getObjectClassDefinition(String id, String locale)
289 {
290 return m_metaType.getObjectClassDefinition(id, locale);
291 }
292 }
293}