2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org
.argeo
.slc
.osgi
;
19 import java
.util
.ArrayList
;
20 import java
.util
.Arrays
;
21 import java
.util
.HashMap
;
22 import java
.util
.HashSet
;
23 import java
.util
.Iterator
;
24 import java
.util
.List
;
26 import java
.util
.Properties
;
29 import org
.apache
.commons
.logging
.Log
;
30 import org
.apache
.commons
.logging
.LogFactory
;
31 import org
.argeo
.slc
.SlcException
;
32 import org
.argeo
.slc
.build
.BasicNameVersion
;
33 import org
.argeo
.slc
.build
.NameVersion
;
34 import org
.argeo
.slc
.core
.execution
.AbstractExecutionModulesManager
;
35 import org
.argeo
.slc
.core
.execution
.DefaultExecutionFlowDescriptorConverter
;
36 import org
.argeo
.slc
.deploy
.ModuleDescriptor
;
37 import org
.argeo
.slc
.execution
.ExecutionContext
;
38 import org
.argeo
.slc
.execution
.ExecutionFlow
;
39 import org
.argeo
.slc
.execution
.ExecutionFlowDescriptor
;
40 import org
.argeo
.slc
.execution
.ExecutionFlowDescriptorConverter
;
41 import org
.argeo
.slc
.execution
.ExecutionModuleDescriptor
;
42 import org
.argeo
.slc
.execution
.ExecutionModulesListener
;
43 import org
.argeo
.slc
.process
.RealizedFlow
;
44 import org
.osgi
.framework
.Bundle
;
45 import org
.osgi
.framework
.Constants
;
46 import org
.osgi
.framework
.InvalidSyntaxException
;
47 import org
.osgi
.framework
.ServiceReference
;
48 import org
.osgi
.util
.tracker
.ServiceTracker
;
49 import org
.springframework
.beans
.factory
.DisposableBean
;
50 import org
.springframework
.beans
.factory
.InitializingBean
;
51 import org
.springframework
.osgi
.service
.importer
.OsgiServiceLifecycleListener
;
53 public class OsgiExecutionModulesManager
extends
54 AbstractExecutionModulesManager
implements InitializingBean
,
55 DisposableBean
, OsgiServiceLifecycleListener
{
58 // // Force usage of vanilla Xalan when in OSGi
59 // // We would like to do it in a cleaner way
60 // // but the integration of Xalan and Xerces in the JRE
61 // // makes it very difficult
62 // // Suggestions welcome!
63 // Properties systemProperties = System.getProperties();
64 // // if (!systemProperties
65 // // .containsKey("javax.xml.parsers.DocumentBuilderFactory"))
66 // // System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
67 // // "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
69 // // (!systemProperties.containsKey("javax.xml.parsers.SAXParserFactory"))
70 // // System.setProperty("javax.xml.parsers.SAXParserFactory",
71 // // "org.apache.xerces.jaxp.SAXParserFactoryImpl");
72 // if (!systemProperties
73 // .containsKey("javax.xml.transform.TransformerFactory"))
74 // System.setProperty("javax.xml.transform.TransformerFactory",
75 // "org.apache.xalan.processor.TransformerFactoryImpl");
78 private final static String PROPERTY_CACHE_SERVICES
= "slc.osgi.execution.cacheServices";
80 private final static Log log
= LogFactory
81 .getLog(OsgiExecutionModulesManager
.class);
83 private BundlesManager bundlesManager
;
84 private ServiceTracker executionContextsTracker
;
85 private Map
<OsgiBundle
, ExecutionContext
> executionContexts
= new HashMap
<OsgiBundle
, ExecutionContext
>();
86 private Map
<OsgiBundle
, ExecutionFlowDescriptorConverter
> executionFlowDescriptorConverters
= new HashMap
<OsgiBundle
, ExecutionFlowDescriptorConverter
>();
87 private Map
<OsgiBundle
, Set
<ExecutionFlow
>> executionFlows
= new HashMap
<OsgiBundle
, Set
<ExecutionFlow
>>();
88 private ExecutionFlowDescriptorConverter defaultDescriptorConverter
= new DefaultExecutionFlowDescriptorConverter();
90 private Boolean useCachedServices
= Boolean
.parseBoolean(System
91 .getProperty(PROPERTY_CACHE_SERVICES
, "true"));
93 public synchronized ExecutionModuleDescriptor
getExecutionModuleDescriptor(
94 String moduleName
, String version
) {
95 ExecutionModuleDescriptor md
= new ExecutionModuleDescriptor();
96 if (useCachedServices
) {
97 OsgiBundle osgiBundle
= null;
98 BasicNameVersion nameVersion
= new BasicNameVersion(moduleName
,
100 bundles
: for (Iterator
<OsgiBundle
> iterator
= executionContexts
101 .keySet().iterator(); iterator
.hasNext();) {
102 OsgiBundle ob
= iterator
.next();
103 if (ob
.equals(nameVersion
)) {
108 if (osgiBundle
== null)
109 throw new SlcException("No execution module registered for "
111 md
.setName(osgiBundle
.getName());
112 md
.setVersion(osgiBundle
.getVersion());
113 md
.setLabel(osgiBundle
.getLabel());
114 md
.setDescription(osgiBundle
.getDescription());
116 md
.setName(moduleName
);
117 md
.setVersion(version
);
118 setMetadataFromBundle(md
, null);
120 ExecutionFlowDescriptorConverter executionFlowDescriptorConverter
= getExecutionFlowDescriptorConverter(
121 moduleName
, version
);
122 if (executionFlowDescriptorConverter
== null)
123 throw new SlcException("No flow converter found.");
124 executionFlowDescriptorConverter
.addFlowsToDescriptor(md
, listFlows(
125 moduleName
, version
));
129 public synchronized List
<ExecutionModuleDescriptor
> listExecutionModules() {
130 List
<ExecutionModuleDescriptor
> descriptors
= new ArrayList
<ExecutionModuleDescriptor
>();
132 if (useCachedServices
) {
133 for (Iterator
<OsgiBundle
> iterator
= executionContexts
.keySet()
134 .iterator(); iterator
.hasNext();) {
135 OsgiBundle osgiBundle
= iterator
.next();
136 ExecutionModuleDescriptor md
= new ExecutionModuleDescriptor();
137 setMetadataFromBundle(md
, bundlesManager
138 .findRelatedBundle(osgiBundle
));
142 ServiceReference
[] arr
= executionContextsTracker
143 .getServiceReferences();
145 log
.error("Tracker returned null.");
149 List
<ServiceReference
> srs
= Arrays
.asList(arr
);
150 // ServiceReference[] srs =
151 // executionContexts.getServiceReferences();
152 for (ServiceReference sr
: srs
) {
153 ExecutionModuleDescriptor md
= new ExecutionModuleDescriptor();
154 setMetadataFromBundle(md
, sr
.getBundle());
161 protected synchronized Map
<String
, ExecutionFlow
> listFlows(
162 String moduleName
, String moduleVersion
) {
164 Map
<String
, ExecutionFlow
> flows
= new HashMap
<String
, ExecutionFlow
>();
165 if (useCachedServices
) {
166 OsgiBundle key
= new OsgiBundle(
167 moduleName
, moduleVersion
);
168 if(!executionFlows
.containsKey(key
))
170 Set
<ExecutionFlow
> flowsT
= executionFlows
.get(key
);
171 for (ExecutionFlow flow
: flowsT
)
172 flows
.put(flow
.getName(), flow
);
175 // TODO: use service trackers?
176 // String filter = OsgiFilterUtils.unifyFilter(ExecutionFlow.class,
179 String filter
= "(Bundle-SymbolicName=" + moduleName
+ ")";
180 ServiceReference
[] sfs
;
182 sfs
= bundlesManager
.getBundleContext().getServiceReferences(
183 ExecutionFlow
.class.getName(), filter
);
184 } catch (InvalidSyntaxException e
) {
185 throw new SlcException(
186 "Cannot retrieve service reference for flow " + filter
,
190 for (ServiceReference sf
: sfs
) {
191 ExecutionFlow flow
= (ExecutionFlow
) bundlesManager
192 .getBundleContext().getService(sf
);
193 flows
.put(flow
.getName(), flow
);
199 protected ExecutionFlow
findExecutionFlow(String moduleName
,
200 String moduleVersion
, String flowName
) {
201 String filter
= "(&(Bundle-SymbolicName=" + moduleName
202 + ")(org.springframework.osgi.bean.name=" + flowName
+ "))";
203 return bundlesManager
.getSingleServiceStrict(ExecutionFlow
.class,
207 protected ExecutionContext
findExecutionContext(String moduleName
,
208 String moduleVersion
) {
209 String filter
= "(&(Bundle-SymbolicName=" + moduleName
210 + ")(Bundle-Version=" + moduleVersion
+ "))";
211 return bundlesManager
.getSingleServiceStrict(ExecutionContext
.class,
215 protected ExecutionFlowDescriptorConverter
findExecutionFlowDescriptorConverter(
216 String moduleName
, String moduleVersion
) {
218 String filter
= "(&(Bundle-SymbolicName=" + moduleName
219 + ")(Bundle-Version=" + moduleVersion
+ "))";
220 return bundlesManager
.getSingleService(
221 ExecutionFlowDescriptorConverter
.class, filter
);
224 public void setBundlesManager(BundlesManager bundlesManager
) {
225 this.bundlesManager
= bundlesManager
;
228 public void afterPropertiesSet() throws Exception
{
229 if (!useCachedServices
)
230 executionContextsTracker
= bundlesManager
231 .newTracker(ExecutionContext
.class);
234 public void destroy() throws Exception
{
235 if (executionContextsTracker
!= null)
236 executionContextsTracker
.close();
240 * Builds a minimal realized flow, based on the provided information
241 * (typically from the command line).
244 * a bundle id, or a pattern contained in a bundle symbolic name
246 * the execution flow name
247 * @return a minimal realized flow, to be used in an execution
249 public RealizedFlow
findRealizedFlow(String module
, String executionName
) {
250 // First check whether we have a bundleId
251 Long bundleId
= null;
253 bundleId
= Long
.parseLong(module
);
254 } catch (NumberFormatException e
) {
258 // Look for bundle names containing pattern
259 OsgiBundle bundle
= null;
260 if (bundleId
!= null) {
261 bundle
= bundlesManager
.getBundle(bundleId
);
263 bundle
= bundlesManager
.findFromPattern(module
);
266 if (bundle
!= null) {
267 RealizedFlow launch
= new RealizedFlow();
268 launch
.setModuleName(bundle
.getName());
269 launch
.setModuleVersion(bundle
.getVersion());
270 ExecutionFlowDescriptor descriptor
= new ExecutionFlowDescriptor();
271 descriptor
.setName(executionName
);
272 launch
.setFlowDescriptor(descriptor
);
276 .warn("Could not find any execution module matching these requirements.");
281 public void upgrade(NameVersion nameVersion
) {
282 OsgiBundle osgiBundle
= new OsgiBundle(nameVersion
);
283 bundlesManager
.upgradeSynchronous(osgiBundle
);
286 protected synchronized ExecutionFlowDescriptorConverter
getExecutionFlowDescriptorConverter(
287 String moduleName
, String moduleVersion
) {
288 if (useCachedServices
) {
289 OsgiBundle osgiBundle
= new OsgiBundle(moduleName
, moduleVersion
);
290 if (executionFlowDescriptorConverters
.containsKey(osgiBundle
))
291 return executionFlowDescriptorConverters
.get(osgiBundle
);
293 return defaultDescriptorConverter
;
295 // Check whether a descriptor converter is published by this module
296 ExecutionFlowDescriptorConverter descriptorConverter
= findExecutionFlowDescriptorConverter(
297 moduleName
, moduleVersion
);
298 if (descriptorConverter
== null)
299 return defaultDescriptorConverter
;
301 return descriptorConverter
;
305 public ModuleDescriptor
getModuleDescriptor(String moduleName
,
307 return getExecutionModuleDescriptor(moduleName
, version
);
310 public List
<ModuleDescriptor
> listModules() {
311 Bundle
[] bundles
= bundlesManager
.getBundleContext().getBundles();
312 List
<ModuleDescriptor
> lst
= new ArrayList
<ModuleDescriptor
>();
313 for (Bundle bundle
: bundles
) {
314 ModuleDescriptor moduleDescriptor
= new ModuleDescriptor();
315 setMetadataFromBundle(moduleDescriptor
, bundle
);
316 lst
.add(moduleDescriptor
);
321 protected void setMetadataFromBundle(ModuleDescriptor md
, Bundle bundle
) {
324 if (md
.getName() == null || md
.getVersion() == null)
325 throw new SlcException("Name and version not available.");
327 Bundle
[] bundles
= bundlesManager
.getBundleContext().getBundles();
328 for (Bundle b
: bundles
) {
329 if (b
.getSymbolicName().equals(md
.getName())
330 && md
.getVersion().equals(
331 getHeaderSafe(b
, Constants
.BUNDLE_VERSION
))) {
340 throw new SlcException("Cannot find bundle.");
342 md
.setName(bdl
.getSymbolicName());
343 md
.setVersion(getHeaderSafe(bdl
, Constants
.BUNDLE_VERSION
));
344 md
.setLabel(getHeaderSafe(bdl
, Constants
.BUNDLE_NAME
));
345 md
.setDescription(getHeaderSafe(bdl
, Constants
.BUNDLE_DESCRIPTION
));
348 private String
getHeaderSafe(Bundle bundle
, Object key
) {
349 Object obj
= bundle
.getHeaders().get(key
);
353 return obj
.toString();
356 @SuppressWarnings("unchecked")
357 public synchronized void bind(Object service
, Map properties
)
359 if (service
instanceof ExecutionContext
) {
360 ExecutionContext executionContext
= (ExecutionContext
) service
;
361 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
362 Bundle bundle
= bundlesManager
.findRelatedBundle(osgiBundle
);
363 osgiBundle
.setLabel(getHeaderSafe(bundle
, Constants
.BUNDLE_NAME
));
364 osgiBundle
.setDescription(getHeaderSafe(bundle
,
365 Constants
.BUNDLE_DESCRIPTION
));
366 executionContexts
.put(osgiBundle
, executionContext
);
367 if (log
.isTraceEnabled())
368 log
.debug("Registered execution context from " + osgiBundle
);
370 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
371 listener
.executionModuleAdded(osgiBundle
, executionContext
);
373 } else if (service
instanceof ExecutionFlow
) {
374 ExecutionFlow executionFlow
= (ExecutionFlow
) service
;
375 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
376 if (!executionFlows
.containsKey(osgiBundle
)) {
377 executionFlows
.put(osgiBundle
, new HashSet());
379 executionFlows
.get(osgiBundle
).add(executionFlow
);
380 if (log
.isTraceEnabled())
382 .debug("Registered " + executionFlow
+ " from "
384 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
385 listener
.executionFlowAdded(osgiBundle
, executionFlow
);
387 } else if (service
instanceof ExecutionFlowDescriptorConverter
) {
388 ExecutionFlowDescriptorConverter executionFlowDescriptorConverter
= (ExecutionFlowDescriptorConverter
) service
;
389 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
390 executionFlowDescriptorConverters
.put(osgiBundle
,
391 executionFlowDescriptorConverter
);
392 if (log
.isTraceEnabled())
394 .debug("Registered execution flow descriptor converter from "
401 @SuppressWarnings("unchecked")
402 public synchronized void unbind(Object service
, Map properties
)
404 if (service
instanceof ExecutionContext
) {
405 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
406 if (executionContexts
.containsKey(osgiBundle
)) {
407 ExecutionContext executionContext
= executionContexts
409 if (log
.isTraceEnabled())
410 log
.debug("Removed execution context from " + osgiBundle
);
412 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
413 listener
.executionModuleRemoved(osgiBundle
,
416 } else if (service
instanceof ExecutionFlow
) {
417 ExecutionFlow executionFlow
= (ExecutionFlow
) service
;
418 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
419 if (executionFlows
.containsKey(osgiBundle
)) {
420 Set flows
= executionFlows
.get(osgiBundle
);
421 flows
.remove(executionFlow
);
422 if (log
.isTraceEnabled())
423 log
.debug("Removed " + executionFlow
+ " from "
425 if (flows
.size() == 0) {
426 executionFlows
.remove(osgiBundle
);
427 if (log
.isTraceEnabled())
428 log
.debug("Removed flows set from " + osgiBundle
);
430 for (ExecutionModulesListener listener
: getExecutionModulesListeners())
431 listener
.executionFlowRemoved(osgiBundle
, executionFlow
);
433 } else if (service
instanceof ExecutionFlowDescriptorConverter
) {
434 OsgiBundle osgiBundle
= asOsgiBundle(properties
);
435 if (executionFlowDescriptorConverters
.containsKey(osgiBundle
)) {
436 executionFlowDescriptorConverters
.remove(osgiBundle
);
437 if (log
.isTraceEnabled())
439 .debug("Removed execution flow descriptor converter from "
447 @SuppressWarnings("unchecked")
448 private OsgiBundle
asOsgiBundle(Map properties
) {
449 String bundleSymbolicName
= checkAndGet(Constants
.BUNDLE_SYMBOLICNAME
,
451 String bundleVersion
= checkAndGet(Constants
.BUNDLE_VERSION
, properties
);
452 return new OsgiBundle(bundleSymbolicName
, bundleVersion
);
455 @SuppressWarnings("unchecked")
456 private String
checkAndGet(Object key
, Map properties
) {
457 if (!properties
.containsKey(key
) || properties
.get(key
) == null)
458 throw new SlcException(key
+ " not set in " + properties
);
460 return properties
.get(key
).toString();
463 public void setDefaultDescriptorConverter(
464 ExecutionFlowDescriptorConverter defaultDescriptorConverter
) {
465 this.defaultDescriptorConverter
= defaultDescriptorConverter
;