1 package org
.argeo
.slc
.osgi
;
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
;
10 import java
.util
.Properties
;
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
;
37 public class OsgiExecutionModulesManager
extends
38 AbstractExecutionModulesManager
implements InitializingBean
,
39 DisposableBean
, OsgiServiceLifecycleListener
{
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");
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");
62 private final static String PROPERTY_CACHE_SERVICES
= "slc.osgi.execution.cacheServices";
64 private final static Log log
= LogFactory
65 .getLog(OsgiExecutionModulesManager
.class);
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();
74 private Boolean useCachedServices
= Boolean
.parseBoolean(System
75 .getProperty(PROPERTY_CACHE_SERVICES
, "true"));
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
,
84 bundles
: for (Iterator
<OsgiBundle
> iterator
= executionContexts
85 .keySet().iterator(); iterator
.hasNext();) {
86 OsgiBundle ob
= iterator
.next();
87 if (ob
.equals(nameVersion
)) {
92 if (osgiBundle
== null)
93 throw new SlcException("No execution module registered for "
95 md
.setName(osgiBundle
.getName());
96 md
.setVersion(osgiBundle
.getVersion());
97 md
.setLabel(osgiBundle
.getLabel());
98 md
.setDescription(osgiBundle
.getDescription());
100 md
.setName(moduleName
);
101 md
.setVersion(version
);
102 setMetadataFromBundle(md
, null);
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
));
113 public synchronized List
<ExecutionModuleDescriptor
> listExecutionModules() {
114 List
<ExecutionModuleDescriptor
> descriptors
= new ArrayList
<ExecutionModuleDescriptor
>();
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
));
126 ServiceReference
[] arr
= executionContextsTracker
127 .getServiceReferences();
129 log
.error("Tracker returned null.");
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());
145 protected synchronized Map
<String
, ExecutionFlow
> listFlows(
146 String moduleName
, String moduleVersion
) {
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
))
154 Set
<ExecutionFlow
> flowsT
= executionFlows
.get(key
);
155 for (ExecutionFlow flow
: flowsT
)
156 flows
.put(flow
.getName(), flow
);
159 // TODO: use service trackers?
160 // String filter = OsgiFilterUtils.unifyFilter(ExecutionFlow.class,
163 String filter
= "(Bundle-SymbolicName=" + moduleName
+ ")";
164 ServiceReference
[] sfs
;
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
,
174 for (ServiceReference sf
: sfs
) {
175 ExecutionFlow flow
= (ExecutionFlow
) bundlesManager
176 .getBundleContext().getService(sf
);
177 flows
.put(flow
.getName(), flow
);
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,
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,
199 protected ExecutionFlowDescriptorConverter
findExecutionFlowDescriptorConverter(
200 String moduleName
, String moduleVersion
) {
202 String filter
= "(&(Bundle-SymbolicName=" + moduleName
203 + ")(Bundle-Version=" + moduleVersion
+ "))";
204 return bundlesManager
.getSingleService(
205 ExecutionFlowDescriptorConverter
.class, filter
);
208 public void setBundlesManager(BundlesManager bundlesManager
) {
209 this.bundlesManager
= bundlesManager
;
212 public void afterPropertiesSet() throws Exception
{
213 if (!useCachedServices
)
214 executionContextsTracker
= bundlesManager
215 .newTracker(ExecutionContext
.class);
218 public void destroy() throws Exception
{
219 if (executionContextsTracker
!= null)
220 executionContextsTracker
.close();
224 * Builds a minimal realized flow, based on the provided information
225 * (typically from the command line).
228 * a bundle id, or a pattern contained in a bundle symbolic name
230 * the execution flow name
231 * @return a minimal realized flow, to be used in an execution
233 public RealizedFlow
findRealizedFlow(String module
, String executionName
) {
234 // First check whether we have a bundleId
235 Long bundleId
= null;
237 bundleId
= Long
.parseLong(module
);
238 } catch (NumberFormatException e
) {
242 // Look for bundle names containing pattern
243 OsgiBundle bundle
= null;
244 if (bundleId
!= null) {
245 bundle
= bundlesManager
.getBundle(bundleId
);
247 bundle
= bundlesManager
.findFromPattern(module
);
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
);
260 .warn("Could not find any execution module matching these requirements.");
265 public void upgrade(NameVersion nameVersion
) {
266 OsgiBundle osgiBundle
= new OsgiBundle(nameVersion
);
267 bundlesManager
.upgradeSynchronous(osgiBundle
);
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
);
277 return defaultDescriptorConverter
;
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
;
285 return descriptorConverter
;
289 public ModuleDescriptor
getModuleDescriptor(String moduleName
,
291 return getExecutionModuleDescriptor(moduleName
, version
);
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
);
305 protected void setMetadataFromBundle(ModuleDescriptor md
, Bundle bundle
) {
308 if (md
.getName() == null || md
.getVersion() == null)
309 throw new SlcException("Name and version not available.");
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
))) {
324 throw new SlcException("Cannot find bundle.");
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
));
332 private String
getHeaderSafe(Bundle bundle
, Object key
) {
333 Object obj
= bundle
.getHeaders().get(key
);
337 return obj
.toString();
340 @SuppressWarnings("unchecked")
341 public synchronized void bind(Object service
, Map properties
)
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
);
354 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
355 listener
.executionModuleAdded(osgiBundle
, executionContext
);
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());
363 executionFlows
.get(osgiBundle
).add(executionFlow
);
364 if (log
.isTraceEnabled())
366 .debug("Registered " + executionFlow
+ " from "
368 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
369 listener
.executionFlowAdded(osgiBundle
, executionFlow
);
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())
378 .debug("Registered execution flow descriptor converter from "
385 @SuppressWarnings("unchecked")
386 public synchronized void unbind(Object service
, Map properties
)
388 if (service
instanceof ExecutionContext
) {
389 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
390 if (executionContexts
.containsKey(osgiBundle
)) {
391 ExecutionContext executionContext
= executionContexts
393 if (log
.isTraceEnabled())
394 log
.debug("Removed execution context from " + osgiBundle
);
396 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
397 listener
.executionModuleRemoved(osgiBundle
,
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 "
409 if (flows
.size() == 0) {
410 executionFlows
.remove(osgiBundle
);
411 if (log
.isTraceEnabled())
412 log
.debug("Removed flows set from " + osgiBundle
);
414 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
415 listener
.executionFlowRemoved(osgiBundle
, executionFlow
);
417 } else if (service
instanceof ExecutionFlowDescriptorConverter
) {
418 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
419 if (executionFlowDescriptorConverters
.containsKey(osgiBundle
)) {
420 executionFlowDescriptorConverters
.remove(osgiBundle
);
421 if (log
.isTraceEnabled())
423 .debug("Removed execution flow descriptor converter from "
431 @SuppressWarnings("unchecked")
432 private OsgiBundle
asOsgiBundle(Map properties
) {
433 String bundleSymbolicName
= checkAndGet(Constants
.BUNDLE_SYMBOLICNAME
,
435 String bundleVersion
= checkAndGet(Constants
.BUNDLE_VERSION
, properties
);
436 return new OsgiBundle(bundleSymbolicName
, bundleVersion
);
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
);
444 return properties
.get(key
).toString();
447 public void setDefaultDescriptorConverter(
448 ExecutionFlowDescriptorConverter defaultDescriptorConverter
) {
449 this.defaultDescriptorConverter
= defaultDescriptorConverter
;