1 package org
.argeo
.slc
.osgi
;
3 import org
.apache
.commons
.logging
.Log
;
4 import org
.apache
.commons
.logging
.LogFactory
;
5 import org
.argeo
.slc
.SlcException
;
6 import org
.osgi
.framework
.Bundle
;
7 import org
.osgi
.framework
.BundleContext
;
8 import org
.osgi
.framework
.BundleException
;
9 import org
.osgi
.framework
.Constants
;
10 import org
.osgi
.framework
.FrameworkEvent
;
11 import org
.osgi
.framework
.FrameworkListener
;
12 import org
.osgi
.framework
.InvalidSyntaxException
;
13 import org
.osgi
.framework
.ServiceReference
;
14 import org
.osgi
.service
.packageadmin
.PackageAdmin
;
15 import org
.osgi
.util
.tracker
.ServiceTracker
;
16 import org
.springframework
.beans
.factory
.InitializingBean
;
17 import org
.springframework
.context
.ApplicationContext
;
18 import org
.springframework
.osgi
.context
.BundleContextAware
;
19 import org
.springframework
.osgi
.util
.OsgiFilterUtils
;
20 import org
.springframework
.util
.Assert
;
22 /** Wraps low-level access to a {@link BundleContext} */
23 public class BundlesManager
implements BundleContextAware
, FrameworkListener
,
25 private final static Log log
= LogFactory
.getLog(BundlesManager
.class);
27 private BundleContext bundleContext
;
29 private Long defaultTimeout
= 10000l;
30 private final Object refreshedPackageSem
= new Object();
33 * Stop the module, update it, refresh it and restart it. All synchronously.
35 public void upgradeSynchronous(OsgiBundle osgiBundle
) {
37 Bundle bundle
= findRelatedBundle(osgiBundle
);
38 stopSynchronous(bundle
);
39 updateSynchronous(bundle
);
40 // Refresh in case there are fragments
41 refreshSynchronous(bundle
);
42 startSynchronous(bundle
);
44 String filter
= "(Bundle-SymbolicName=" + bundle
.getSymbolicName()
46 // Wait for application context to be ready
47 // TODO: use service tracker
48 getServiceRefSynchronous(ApplicationContext
.class.getName(), filter
);
50 if (log
.isDebugEnabled())
51 log
.debug("Bundle " + bundle
.getSymbolicName()
52 + " ready to be used at latest version.");
53 } catch (Exception e
) {
54 throw new SlcException("Cannot update bundle " + osgiBundle
, e
);
58 /** Updates bundle synchronously. */
59 protected void updateSynchronous(Bundle bundle
) throws BundleException
{
60 // int originalState = bundle.getState();
62 boolean waiting
= true;
64 long begin
= System
.currentTimeMillis();
66 int state
= bundle
.getState();
67 if (state
== Bundle
.INSTALLED
|| state
== Bundle
.ACTIVE
68 || state
== Bundle
.RESOLVED
)
72 if (System
.currentTimeMillis() - begin
> defaultTimeout
)
73 throw new SlcException("Update of bundle "
74 + bundle
.getSymbolicName()
75 + " timed out. Bundle state = " + bundle
.getState());
78 if (log
.isTraceEnabled())
79 log
.debug("Bundle " + bundle
.getSymbolicName() + " updated.");
82 /** Starts bundle synchronously. Does nothing if already started. */
83 protected void startSynchronous(Bundle bundle
) throws BundleException
{
84 int originalState
= bundle
.getState();
85 if (originalState
== Bundle
.ACTIVE
)
89 boolean waiting
= true;
91 long begin
= System
.currentTimeMillis();
93 if (bundle
.getState() == Bundle
.ACTIVE
)
97 if (System
.currentTimeMillis() - begin
> defaultTimeout
)
98 throw new SlcException("Start of bundle "
99 + bundle
.getSymbolicName()
100 + " timed out. Bundle state = " + bundle
.getState());
103 if (log
.isTraceEnabled())
104 log
.debug("Bundle " + bundle
.getSymbolicName() + " started.");
107 /** Stops bundle synchronously. Does nothing if already started. */
108 protected void stopSynchronous(Bundle bundle
) throws BundleException
{
109 int originalState
= bundle
.getState();
110 if (originalState
!= Bundle
.ACTIVE
)
114 boolean waiting
= true;
116 long begin
= System
.currentTimeMillis();
118 if (bundle
.getState() != Bundle
.ACTIVE
119 && bundle
.getState() != Bundle
.STOPPING
)
123 if (System
.currentTimeMillis() - begin
> defaultTimeout
)
124 throw new SlcException("Stop of bundle "
125 + bundle
.getSymbolicName()
126 + " timed out. Bundle state = " + bundle
.getState());
129 if (log
.isTraceEnabled())
130 log
.debug("Bundle " + bundle
.getSymbolicName() + " stopped.");
133 /** Refresh bundle synchronously. Does nothing if already started. */
134 protected void refreshSynchronous(Bundle bundle
) throws BundleException
{
135 ServiceReference packageAdminRef
= bundleContext
136 .getServiceReference(PackageAdmin
.class.getName());
137 PackageAdmin packageAdmin
= (PackageAdmin
) bundleContext
138 .getService(packageAdminRef
);
139 Bundle
[] bundles
= { bundle
};
140 packageAdmin
.refreshPackages(bundles
);
142 synchronized (refreshedPackageSem
) {
144 refreshedPackageSem
.wait(defaultTimeout
);
145 } catch (InterruptedException e
) {
150 if (log
.isTraceEnabled())
151 log
.debug("Bundle " + bundle
.getSymbolicName() + " refreshed.");
154 public void frameworkEvent(FrameworkEvent event
) {
155 if (event
.getType() == FrameworkEvent
.PACKAGES_REFRESHED
) {
156 synchronized (refreshedPackageSem
) {
157 refreshedPackageSem
.notifyAll();
162 public ServiceReference
[] getServiceRefSynchronous(String clss
,
163 String filter
) throws InvalidSyntaxException
{
164 if (log
.isTraceEnabled())
165 log
.debug("Filter: '" + filter
+ "'");
166 ServiceReference
[] sfs
= null;
167 boolean waiting
= true;
168 long begin
= System
.currentTimeMillis();
170 sfs
= bundleContext
.getServiceReferences(clss
, filter
);
176 if (System
.currentTimeMillis() - begin
> defaultTimeout
)
177 throw new SlcException("Search of services " + clss
178 + " with filter " + filter
+ " timed out.");
184 protected void sleep(long ms
) {
187 } catch (InterruptedException e
) {
192 /** Creates and open a new service tracker. */
193 public ServiceTracker
newTracker(Class
<?
> clss
) {
194 ServiceTracker st
= new ServiceTracker(bundleContext
, clss
.getName(),
200 @SuppressWarnings(value
= { "unchecked" })
201 public <T
> T
getSingleService(Class
<T
> clss
, String filter
) {
202 Assert
.isTrue(OsgiFilterUtils
.isValidFilter(filter
), "valid filter");
203 ServiceReference
[] sfs
;
205 sfs
= bundleContext
.getServiceReferences(clss
.getName(), filter
);
206 } catch (InvalidSyntaxException e
) {
207 throw new SlcException("Cannot retrieve service reference for "
211 if (sfs
== null || sfs
.length
== 0)
213 else if (sfs
.length
> 1)
214 throw new SlcException("More than one execution flow found for "
216 return (T
) bundleContext
.getService(sfs
[0]);
219 public <T
> T
getSingleServiceStrict(Class
<T
> clss
, String filter
) {
220 T service
= getSingleService(clss
, filter
);
222 throw new SlcException("No execution flow found for " + filter
);
227 /** @return the related bundle or null if not found */
228 public Bundle
findRelatedBundle(OsgiBundle osgiBundle
) {
229 Bundle bundle
= null;
230 if (osgiBundle
.getInternalBundleId() != null) {
231 bundle
= bundleContext
.getBundle(osgiBundle
.getInternalBundleId());
233 osgiBundle
.getName().equals(bundle
.getSymbolicName()),
234 "symbolic name consistent");
235 Assert
.isTrue(osgiBundle
.getVersion().equals(
236 bundle
.getHeaders().get(Constants
.BUNDLE_VERSION
)),
237 "version consistent");
239 for (Bundle b
: bundleContext
.getBundles()) {
240 if (b
.getSymbolicName().equals(osgiBundle
.getName())) {
241 if (b
.getHeaders().get(Constants
.BUNDLE_VERSION
).equals(
242 osgiBundle
.getVersion())) {
244 osgiBundle
.setInternalBundleId(b
.getBundleId());
252 /** Find a single bundle based on a symbolic name pattern. */
253 public OsgiBundle
findFromPattern(String pattern
) {
254 OsgiBundle osgiBundle
= null;
255 for (Bundle b
: bundleContext
.getBundles()) {
256 if (b
.getSymbolicName().contains(pattern
)) {
257 osgiBundle
= new OsgiBundle(b
);
264 public OsgiBundle
getBundle(Long bundleId
) {
265 Bundle bundle
= bundleContext
.getBundle(bundleId
);
266 return new OsgiBundle(bundle
);
269 public void setBundleContext(BundleContext bundleContext
) {
270 this.bundleContext
= bundleContext
;
273 public void afterPropertiesSet() throws Exception
{
274 bundleContext
.addFrameworkListener(this);
277 public void setDefaultTimeout(Long defaultTimeout
) {
278 this.defaultTimeout
= defaultTimeout
;
281 /** Temporary internal access for {@link OsgiExecutionModulesManager} */
282 BundleContext
getBundleContext() {
283 return bundleContext
;