]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java
Improve SDK
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.osgi / src / main / java / org / argeo / slc / osgi / OsgiExecutionModulesManager.java
1 package org.argeo.slc.osgi;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Properties;
11 import java.util.Set;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.argeo.slc.SlcException;
16 import org.argeo.slc.build.BasicNameVersion;
17 import org.argeo.slc.build.NameVersion;
18 import org.argeo.slc.core.execution.AbstractExecutionModulesManager;
19 import org.argeo.slc.core.execution.DefaultExecutionFlowDescriptorConverter;
20 import org.argeo.slc.deploy.ModuleDescriptor;
21 import org.argeo.slc.execution.ExecutionContext;
22 import org.argeo.slc.execution.ExecutionFlow;
23 import org.argeo.slc.execution.ExecutionFlowDescriptor;
24 import org.argeo.slc.execution.ExecutionFlowDescriptorConverter;
25 import org.argeo.slc.execution.ExecutionModuleDescriptor;
26 import org.argeo.slc.execution.ExecutionModulesListener;
27 import org.argeo.slc.process.RealizedFlow;
28 import org.osgi.framework.Bundle;
29 import org.osgi.framework.Constants;
30 import org.osgi.framework.InvalidSyntaxException;
31 import org.osgi.framework.ServiceReference;
32 import org.osgi.util.tracker.ServiceTracker;
33 import org.springframework.beans.factory.DisposableBean;
34 import org.springframework.beans.factory.InitializingBean;
35 import org.springframework.osgi.service.importer.OsgiServiceLifecycleListener;
36
37 public class OsgiExecutionModulesManager extends
38 AbstractExecutionModulesManager implements InitializingBean,
39 DisposableBean, OsgiServiceLifecycleListener {
40
41 // static {
42 // // Force usage of vanilla Xalan when in OSGi
43 // // We would like to do it in a cleaner way
44 // // but the integration of Xalan and Xerces in the JRE
45 // // makes it very difficult
46 // // Suggestions welcome!
47 // Properties systemProperties = System.getProperties();
48 // // if (!systemProperties
49 // // .containsKey("javax.xml.parsers.DocumentBuilderFactory"))
50 // // System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
51 // // "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
52 // // if
53 // // (!systemProperties.containsKey("javax.xml.parsers.SAXParserFactory"))
54 // // System.setProperty("javax.xml.parsers.SAXParserFactory",
55 // // "org.apache.xerces.jaxp.SAXParserFactoryImpl");
56 // if (!systemProperties
57 // .containsKey("javax.xml.transform.TransformerFactory"))
58 // System.setProperty("javax.xml.transform.TransformerFactory",
59 // "org.apache.xalan.processor.TransformerFactoryImpl");
60 // }
61
62 private final static String PROPERTY_CACHE_SERVICES = "slc.osgi.execution.cacheServices";
63
64 private final static Log log = LogFactory
65 .getLog(OsgiExecutionModulesManager.class);
66
67 private BundlesManager bundlesManager;
68 private ServiceTracker executionContextsTracker;
69 private Map<OsgiBundle, ExecutionContext> executionContexts = new HashMap<OsgiBundle, ExecutionContext>();
70 private Map<OsgiBundle, ExecutionFlowDescriptorConverter> executionFlowDescriptorConverters = new HashMap<OsgiBundle, ExecutionFlowDescriptorConverter>();
71 private Map<OsgiBundle, Set<ExecutionFlow>> executionFlows = new HashMap<OsgiBundle, Set<ExecutionFlow>>();
72 private ExecutionFlowDescriptorConverter defaultDescriptorConverter = new DefaultExecutionFlowDescriptorConverter();
73
74 private Boolean useCachedServices = Boolean.parseBoolean(System
75 .getProperty(PROPERTY_CACHE_SERVICES, "true"));
76
77 public synchronized ExecutionModuleDescriptor getExecutionModuleDescriptor(
78 String moduleName, String version) {
79 ExecutionModuleDescriptor md = new ExecutionModuleDescriptor();
80 if (useCachedServices) {
81 OsgiBundle osgiBundle = null;
82 BasicNameVersion nameVersion = new BasicNameVersion(moduleName,
83 version);
84 bundles: for (Iterator<OsgiBundle> iterator = executionContexts
85 .keySet().iterator(); iterator.hasNext();) {
86 OsgiBundle ob = iterator.next();
87 if (ob.equals(nameVersion)) {
88 osgiBundle = ob;
89 break bundles;
90 }
91 }
92 if (osgiBundle == null)
93 throw new SlcException("No execution module registered for "
94 + nameVersion);
95 md.setName(osgiBundle.getName());
96 md.setVersion(osgiBundle.getVersion());
97 md.setLabel(osgiBundle.getLabel());
98 md.setDescription(osgiBundle.getDescription());
99 } else {
100 md.setName(moduleName);
101 md.setVersion(version);
102 setMetadataFromBundle(md, null);
103 }
104 ExecutionFlowDescriptorConverter executionFlowDescriptorConverter = getExecutionFlowDescriptorConverter(
105 moduleName, version);
106 if (executionFlowDescriptorConverter == null)
107 throw new SlcException("No flow converter found.");
108 executionFlowDescriptorConverter.addFlowsToDescriptor(md, listFlows(
109 moduleName, version));
110 return md;
111 }
112
113 public synchronized List<ExecutionModuleDescriptor> listExecutionModules() {
114 List<ExecutionModuleDescriptor> descriptors = new ArrayList<ExecutionModuleDescriptor>();
115
116 if (useCachedServices) {
117 for (Iterator<OsgiBundle> iterator = executionContexts.keySet()
118 .iterator(); iterator.hasNext();) {
119 OsgiBundle osgiBundle = iterator.next();
120 ExecutionModuleDescriptor md = new ExecutionModuleDescriptor();
121 setMetadataFromBundle(md, bundlesManager
122 .findRelatedBundle(osgiBundle));
123 descriptors.add(md);
124 }
125 } else {
126 ServiceReference[] arr = executionContextsTracker
127 .getServiceReferences();
128 if (arr == null) {
129 log.error("Tracker returned null.");
130 return descriptors;
131 }
132
133 List<ServiceReference> srs = Arrays.asList(arr);
134 // ServiceReference[] srs =
135 // executionContexts.getServiceReferences();
136 for (ServiceReference sr : srs) {
137 ExecutionModuleDescriptor md = new ExecutionModuleDescriptor();
138 setMetadataFromBundle(md, sr.getBundle());
139 descriptors.add(md);
140 }
141 }
142 return descriptors;
143 }
144
145 protected synchronized Map<String, ExecutionFlow> listFlows(
146 String moduleName, String moduleVersion) {
147
148 Map<String, ExecutionFlow> flows = new HashMap<String, ExecutionFlow>();
149 if (useCachedServices) {
150 OsgiBundle key = new OsgiBundle(
151 moduleName, moduleVersion);
152 if(!executionFlows.containsKey(key))
153 return flows;
154 Set<ExecutionFlow> flowsT = executionFlows.get(key);
155 for (ExecutionFlow flow : flowsT)
156 flows.put(flow.getName(), flow);
157 } else {
158
159 // TODO: use service trackers?
160 // String filter = OsgiFilterUtils.unifyFilter(ExecutionFlow.class,
161 // null);
162
163 String filter = "(Bundle-SymbolicName=" + moduleName + ")";
164 ServiceReference[] sfs;
165 try {
166 sfs = bundlesManager.getBundleContext().getServiceReferences(
167 ExecutionFlow.class.getName(), filter);
168 } catch (InvalidSyntaxException e) {
169 throw new SlcException(
170 "Cannot retrieve service reference for flow " + filter,
171 e);
172 }
173
174 for (ServiceReference sf : sfs) {
175 ExecutionFlow flow = (ExecutionFlow) bundlesManager
176 .getBundleContext().getService(sf);
177 flows.put(flow.getName(), flow);
178 }
179 }
180 return flows;
181 }
182
183 protected ExecutionFlow findExecutionFlow(String moduleName,
184 String moduleVersion, String flowName) {
185 String filter = "(&(Bundle-SymbolicName=" + moduleName
186 + ")(org.springframework.osgi.bean.name=" + flowName + "))";
187 return bundlesManager.getSingleServiceStrict(ExecutionFlow.class,
188 filter);
189 }
190
191 protected ExecutionContext findExecutionContext(String moduleName,
192 String moduleVersion) {
193 String filter = "(&(Bundle-SymbolicName=" + moduleName
194 + ")(Bundle-Version=" + moduleVersion + "))";
195 return bundlesManager.getSingleServiceStrict(ExecutionContext.class,
196 filter);
197 }
198
199 protected ExecutionFlowDescriptorConverter findExecutionFlowDescriptorConverter(
200 String moduleName, String moduleVersion) {
201
202 String filter = "(&(Bundle-SymbolicName=" + moduleName
203 + ")(Bundle-Version=" + moduleVersion + "))";
204 return bundlesManager.getSingleService(
205 ExecutionFlowDescriptorConverter.class, filter);
206 }
207
208 public void setBundlesManager(BundlesManager bundlesManager) {
209 this.bundlesManager = bundlesManager;
210 }
211
212 public void afterPropertiesSet() throws Exception {
213 if (!useCachedServices)
214 executionContextsTracker = bundlesManager
215 .newTracker(ExecutionContext.class);
216 }
217
218 public void destroy() throws Exception {
219 if (executionContextsTracker != null)
220 executionContextsTracker.close();
221 }
222
223 /**
224 * Builds a minimal realized flow, based on the provided information
225 * (typically from the command line).
226 *
227 * @param module
228 * a bundle id, or a pattern contained in a bundle symbolic name
229 * @param module
230 * the execution flow name
231 * @return a minimal realized flow, to be used in an execution
232 */
233 public RealizedFlow findRealizedFlow(String module, String executionName) {
234 // First check whether we have a bundleId
235 Long bundleId = null;
236 try {
237 bundleId = Long.parseLong(module);
238 } catch (NumberFormatException e) {
239 // silent
240 }
241
242 // Look for bundle names containing pattern
243 OsgiBundle bundle = null;
244 if (bundleId != null) {
245 bundle = bundlesManager.getBundle(bundleId);
246 } else {
247 bundle = bundlesManager.findFromPattern(module);
248 }
249
250 if (bundle != null) {
251 RealizedFlow launch = new RealizedFlow();
252 launch.setModuleName(bundle.getName());
253 launch.setModuleVersion(bundle.getVersion());
254 ExecutionFlowDescriptor descriptor = new ExecutionFlowDescriptor();
255 descriptor.setName(executionName);
256 launch.setFlowDescriptor(descriptor);
257 return launch;
258 } else {
259 log
260 .warn("Could not find any execution module matching these requirements.");
261 return null;
262 }
263 }
264
265 public void upgrade(NameVersion nameVersion) {
266 OsgiBundle osgiBundle = new OsgiBundle(nameVersion);
267 bundlesManager.upgradeSynchronous(osgiBundle);
268 }
269
270 protected synchronized ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter(
271 String moduleName, String moduleVersion) {
272 if (useCachedServices) {
273 OsgiBundle osgiBundle = new OsgiBundle(moduleName, moduleVersion);
274 if (executionFlowDescriptorConverters.containsKey(osgiBundle))
275 return executionFlowDescriptorConverters.get(osgiBundle);
276 else
277 return defaultDescriptorConverter;
278 } else {
279 // Check whether a descriptor converter is published by this module
280 ExecutionFlowDescriptorConverter descriptorConverter = findExecutionFlowDescriptorConverter(
281 moduleName, moduleVersion);
282 if (descriptorConverter == null)
283 return defaultDescriptorConverter;
284 else
285 return descriptorConverter;
286 }
287 }
288
289 public ModuleDescriptor getModuleDescriptor(String moduleName,
290 String version) {
291 return getExecutionModuleDescriptor(moduleName, version);
292 }
293
294 public List<ModuleDescriptor> listModules() {
295 Bundle[] bundles = bundlesManager.getBundleContext().getBundles();
296 List<ModuleDescriptor> lst = new ArrayList<ModuleDescriptor>();
297 for (Bundle bundle : bundles) {
298 ModuleDescriptor moduleDescriptor = new ModuleDescriptor();
299 setMetadataFromBundle(moduleDescriptor, bundle);
300 lst.add(moduleDescriptor);
301 }
302 return lst;
303 }
304
305 protected void setMetadataFromBundle(ModuleDescriptor md, Bundle bundle) {
306 Bundle bdl = bundle;
307 if (bdl == null) {
308 if (md.getName() == null || md.getVersion() == null)
309 throw new SlcException("Name and version not available.");
310
311 Bundle[] bundles = bundlesManager.getBundleContext().getBundles();
312 for (Bundle b : bundles) {
313 if (b.getSymbolicName().equals(md.getName())
314 && md.getVersion().equals(
315 getHeaderSafe(b, Constants.BUNDLE_VERSION))) {
316 bdl = b;
317 break;
318 }
319 }
320
321 }
322
323 if (bdl == null)
324 throw new SlcException("Cannot find bundle.");
325
326 md.setName(bdl.getSymbolicName());
327 md.setVersion(getHeaderSafe(bdl, Constants.BUNDLE_VERSION));
328 md.setLabel(getHeaderSafe(bdl, Constants.BUNDLE_NAME));
329 md.setDescription(getHeaderSafe(bdl, Constants.BUNDLE_DESCRIPTION));
330 }
331
332 private String getHeaderSafe(Bundle bundle, Object key) {
333 Object obj = bundle.getHeaders().get(key);
334 if (obj == null)
335 return null;
336 else
337 return obj.toString();
338 }
339
340 @SuppressWarnings("unchecked")
341 public synchronized void bind(Object service, Map properties)
342 throws Exception {
343 if (service instanceof ExecutionContext) {
344 ExecutionContext executionContext = (ExecutionContext) service;
345 OsgiBundle osgiBundle = asOsgiBundle(properties);
346 Bundle bundle = bundlesManager.findRelatedBundle(osgiBundle);
347 osgiBundle.setLabel(getHeaderSafe(bundle, Constants.BUNDLE_NAME));
348 osgiBundle.setDescription(getHeaderSafe(bundle,
349 Constants.BUNDLE_DESCRIPTION));
350 executionContexts.put(osgiBundle, executionContext);
351 if (log.isTraceEnabled())
352 log.debug("Registered execution context from " + osgiBundle);
353 // Notify
354 for (ExecutionModulesListener listener : getExecutionModulesListeners())
355 listener.executionModuleAdded(osgiBundle, executionContext);
356
357 } else if (service instanceof ExecutionFlow) {
358 ExecutionFlow executionFlow = (ExecutionFlow) service;
359 OsgiBundle osgiBundle = asOsgiBundle(properties);
360 if (!executionFlows.containsKey(osgiBundle)) {
361 executionFlows.put(osgiBundle, new HashSet());
362 }
363 executionFlows.get(osgiBundle).add(executionFlow);
364 if (log.isTraceEnabled())
365 log
366 .debug("Registered " + executionFlow + " from "
367 + osgiBundle);
368 for (ExecutionModulesListener listener : getExecutionModulesListeners())
369 listener.executionFlowAdded(osgiBundle, executionFlow);
370
371 } else if (service instanceof ExecutionFlowDescriptorConverter) {
372 ExecutionFlowDescriptorConverter executionFlowDescriptorConverter = (ExecutionFlowDescriptorConverter) service;
373 OsgiBundle osgiBundle = asOsgiBundle(properties);
374 executionFlowDescriptorConverters.put(osgiBundle,
375 executionFlowDescriptorConverter);
376 if (log.isTraceEnabled())
377 log
378 .debug("Registered execution flow descriptor converter from "
379 + osgiBundle);
380 } else {
381 // ignore
382 }
383 }
384
385 @SuppressWarnings("unchecked")
386 public synchronized void unbind(Object service, Map properties)
387 throws Exception {
388 if (service instanceof ExecutionContext) {
389 OsgiBundle osgiBundle = asOsgiBundle(properties);
390 if (executionContexts.containsKey(osgiBundle)) {
391 ExecutionContext executionContext = executionContexts
392 .remove(osgiBundle);
393 if (log.isTraceEnabled())
394 log.debug("Removed execution context from " + osgiBundle);
395 // Notify
396 for (ExecutionModulesListener listener : getExecutionModulesListeners())
397 listener.executionModuleRemoved(osgiBundle,
398 executionContext);
399 }
400 } else if (service instanceof ExecutionFlow) {
401 ExecutionFlow executionFlow = (ExecutionFlow) service;
402 OsgiBundle osgiBundle = asOsgiBundle(properties);
403 if (executionFlows.containsKey(osgiBundle)) {
404 Set flows = executionFlows.get(osgiBundle);
405 flows.remove(executionFlow);
406 if (log.isTraceEnabled())
407 log.debug("Removed " + executionFlow + " from "
408 + osgiBundle);
409 if (flows.size() == 0) {
410 executionFlows.remove(osgiBundle);
411 if (log.isTraceEnabled())
412 log.debug("Removed flows set from " + osgiBundle);
413 }
414 for (ExecutionModulesListener listener : getExecutionModulesListeners())
415 listener.executionFlowRemoved(osgiBundle, executionFlow);
416 }
417 } else if (service instanceof ExecutionFlowDescriptorConverter) {
418 OsgiBundle osgiBundle = asOsgiBundle(properties);
419 if (executionFlowDescriptorConverters.containsKey(osgiBundle)) {
420 executionFlowDescriptorConverters.remove(osgiBundle);
421 if (log.isTraceEnabled())
422 log
423 .debug("Removed execution flow descriptor converter from "
424 + osgiBundle);
425 }
426 } else {
427 // ignore
428 }
429 }
430
431 @SuppressWarnings("unchecked")
432 private OsgiBundle asOsgiBundle(Map properties) {
433 String bundleSymbolicName = checkAndGet(Constants.BUNDLE_SYMBOLICNAME,
434 properties);
435 String bundleVersion = checkAndGet(Constants.BUNDLE_VERSION, properties);
436 return new OsgiBundle(bundleSymbolicName, bundleVersion);
437 }
438
439 @SuppressWarnings("unchecked")
440 private String checkAndGet(Object key, Map properties) {
441 if (!properties.containsKey(key) || properties.get(key) == null)
442 throw new SlcException(key + " not set in " + properties);
443 else
444 return properties.get(key).toString();
445 }
446
447 public void setDefaultDescriptorConverter(
448 ExecutionFlowDescriptorConverter defaultDescriptorConverter) {
449 this.defaultDescriptorConverter = defaultDescriptorConverter;
450 }
451 }