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