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
.DisposableBean
;
17 import org
.springframework
.beans
.factory
.InitializingBean
;
18 import org
.springframework
.context
.ApplicationContext
;
19 import org
.springframework
.osgi
.context
.BundleContextAware
;
20 import org
.springframework
.osgi
.util
.OsgiFilterUtils
;
21 import org
.springframework
.util
.Assert
;
23 /** Wraps low-level access to a {@link BundleContext} */
24 public class BundlesManager
implements BundleContextAware
, FrameworkListener
,
25 InitializingBean
, DisposableBean
{
26 private final static Log log
= LogFactory
.getLog(BundlesManager
.class);
28 private BundleContext bundleContext
;
30 private Long defaultTimeout
= 10000l;
31 private Long pollingPeriod
= 100l;
33 // Refresh sync objects
34 private final Object refreshedPackageSem
= new Object();
35 private Boolean packagesRefreshed
= false;
38 * Stop the module, update it, refresh it and restart it. All synchronously.
40 public void upgradeSynchronous(OsgiBundle osgiBundle
) {
42 Bundle bundle
= findRelatedBundle(osgiBundle
);
44 long begin
= System
.currentTimeMillis();
47 stopSynchronous(bundle
);
49 long bUpdate
= System
.currentTimeMillis();
50 updateSynchronous(bundle
);
52 // Refresh in case there are fragments
53 long bRefresh
= System
.currentTimeMillis();
54 refreshSynchronous(bundle
);
56 long bStart
= System
.currentTimeMillis();
57 startSynchronous(bundle
);
59 long aStart
= System
.currentTimeMillis();
60 if (log
.isDebugEnabled()) {
61 log
.debug("OSGi upgrade performed in " + (aStart
- begin
)
62 + "ms for bundle " + osgiBundle
);
63 log
.debug(" stop \t: " + (bUpdate
- bStop
) + "ms");
64 log
.debug(" update\t: " + (bRefresh
- bUpdate
) + "ms");
65 log
.debug(" refresh\t: " + (bStart
- bRefresh
) + "ms");
66 log
.debug(" start\t: " + (aStart
- bStart
) + "ms");
67 log
.debug(" TOTAL\t: " + (aStart
- begin
) + "ms");
70 long bAppContext
= System
.currentTimeMillis();
71 String filter
= "(Bundle-SymbolicName=" + bundle
.getSymbolicName()
73 // Wait for application context to be ready
74 // TODO: use service tracker
75 getServiceRefSynchronous(ApplicationContext
.class.getName(), filter
);
76 long aAppContext
= System
.currentTimeMillis();
77 long end
= aAppContext
;
79 if (log
.isDebugEnabled()) {
80 log
.debug("Application context refresh performed in "
81 + (aAppContext
- bAppContext
) + "ms for bundle "
83 log
.debug(" TOTAL\t: " + (aAppContext
- bAppContext
) + "ms");
86 if (log
.isDebugEnabled())
87 log
.debug("Bundle " + bundle
.getSymbolicName()
88 + " ready to be used at latest version."
89 + " (upgrade performed in " + (end
- begin
) + "ms).");
90 log
.debug(" TOTAL\t: " + (end
- begin
) + "ms");
91 } catch (Exception e
) {
92 throw new SlcException("Cannot update bundle " + osgiBundle
, e
);
96 /** Updates bundle synchronously. */
97 protected void updateSynchronous(Bundle bundle
) throws BundleException
{
99 boolean waiting
= true;
101 long begin
= System
.currentTimeMillis();
103 int state
= bundle
.getState();
104 if (state
== Bundle
.INSTALLED
|| state
== Bundle
.ACTIVE
105 || state
== Bundle
.RESOLVED
)
109 checkTimeout(begin
, "Update of bundle " + bundle
.getSymbolicName()
110 + " timed out. Bundle state = " + bundle
.getState());
113 if (log
.isTraceEnabled())
114 log
.debug("Bundle " + bundle
.getSymbolicName() + " updated.");
117 /** Starts bundle synchronously. Does nothing if already started. */
118 protected void startSynchronous(Bundle bundle
) throws BundleException
{
119 int originalState
= bundle
.getState();
120 if (originalState
== Bundle
.ACTIVE
)
124 boolean waiting
= true;
126 long begin
= System
.currentTimeMillis();
128 if (bundle
.getState() == Bundle
.ACTIVE
)
132 checkTimeout(begin
, "Start of bundle " + bundle
.getSymbolicName()
133 + " timed out. Bundle state = " + bundle
.getState());
136 if (log
.isTraceEnabled())
137 log
.debug("Bundle " + bundle
.getSymbolicName() + " started.");
140 /** Stops bundle synchronously. Does nothing if already started. */
141 protected void stopSynchronous(Bundle bundle
) throws BundleException
{
142 int originalState
= bundle
.getState();
143 if (originalState
!= Bundle
.ACTIVE
)
147 boolean waiting
= true;
149 long begin
= System
.currentTimeMillis();
151 if (bundle
.getState() != Bundle
.ACTIVE
152 && bundle
.getState() != Bundle
.STOPPING
)
156 checkTimeout(begin
, "Stop of bundle " + bundle
.getSymbolicName()
157 + " timed out. Bundle state = " + bundle
.getState());
160 if (log
.isTraceEnabled())
161 log
.debug("Bundle " + bundle
.getSymbolicName() + " stopped.");
164 /** Refresh bundle synchronously. Does nothing if already started. */
165 protected void refreshSynchronous(Bundle bundle
) throws BundleException
{
166 ServiceReference packageAdminRef
= bundleContext
167 .getServiceReference(PackageAdmin
.class.getName());
168 PackageAdmin packageAdmin
= (PackageAdmin
) bundleContext
169 .getService(packageAdminRef
);
170 Bundle
[] bundles
= { bundle
};
172 long begin
= System
.currentTimeMillis();
173 synchronized (refreshedPackageSem
) {
174 packagesRefreshed
= false;
175 packageAdmin
.refreshPackages(bundles
);
177 refreshedPackageSem
.wait(defaultTimeout
);
178 } catch (InterruptedException e
) {
181 if (!packagesRefreshed
) {
182 long now
= System
.currentTimeMillis();
183 throw new SlcException("Packages not refreshed after "
184 + (now
- begin
) + "ms");
186 packagesRefreshed
= false;
190 if (log
.isTraceEnabled())
191 log
.debug("Bundle " + bundle
.getSymbolicName() + " refreshed.");
194 public void frameworkEvent(FrameworkEvent event
) {
195 if (event
.getType() == FrameworkEvent
.PACKAGES_REFRESHED
) {
196 synchronized (refreshedPackageSem
) {
197 packagesRefreshed
= true;
198 refreshedPackageSem
.notifyAll();
203 public ServiceReference
[] getServiceRefSynchronous(String clss
,
204 String filter
) throws InvalidSyntaxException
{
205 if (log
.isTraceEnabled())
206 log
.debug("Filter: '" + filter
+ "'");
207 ServiceReference
[] sfs
= null;
208 boolean waiting
= true;
209 long begin
= System
.currentTimeMillis();
211 sfs
= bundleContext
.getServiceReferences(clss
, filter
);
217 if (System
.currentTimeMillis() - begin
> defaultTimeout
)
218 throw new SlcException("Search of services " + clss
219 + " with filter " + filter
+ " timed out.");
225 protected void checkTimeout(long begin
, String msg
) {
226 long now
= System
.currentTimeMillis();
227 if (now
- begin
> defaultTimeout
)
228 throw new SlcException(msg
+ " (timeout after " + (now
- begin
)
233 protected void sleepWhenPolling() {
235 Thread
.sleep(pollingPeriod
);
236 } catch (InterruptedException e
) {
241 /** Creates and open a new service tracker. */
242 public ServiceTracker
newTracker(Class
<?
> clss
) {
243 ServiceTracker st
= new ServiceTracker(bundleContext
, clss
.getName(),
249 @SuppressWarnings(value
= { "unchecked" })
250 public <T
> T
getSingleService(Class
<T
> clss
, String filter
) {
251 Assert
.isTrue(OsgiFilterUtils
.isValidFilter(filter
), "valid filter");
252 ServiceReference
[] sfs
;
254 sfs
= bundleContext
.getServiceReferences(clss
.getName(), filter
);
255 } catch (InvalidSyntaxException e
) {
256 throw new SlcException("Cannot retrieve service reference for "
260 if (sfs
== null || sfs
.length
== 0)
262 else if (sfs
.length
> 1)
263 throw new SlcException("More than one execution flow found for "
265 return (T
) bundleContext
.getService(sfs
[0]);
268 public <T
> T
getSingleServiceStrict(Class
<T
> clss
, String filter
) {
269 T service
= getSingleService(clss
, filter
);
271 throw new SlcException("No execution flow found for " + filter
);
276 /** @return the related bundle or null if not found */
277 public Bundle
findRelatedBundle(OsgiBundle osgiBundle
) {
278 Bundle bundle
= null;
279 if (osgiBundle
.getInternalBundleId() != null) {
280 bundle
= bundleContext
.getBundle(osgiBundle
.getInternalBundleId());
282 osgiBundle
.getName().equals(bundle
.getSymbolicName()),
283 "symbolic name consistent");
284 Assert
.isTrue(osgiBundle
.getVersion().equals(
285 bundle
.getHeaders().get(Constants
.BUNDLE_VERSION
)),
286 "version consistent");
288 for (Bundle b
: bundleContext
.getBundles()) {
289 if (b
.getSymbolicName().equals(osgiBundle
.getName())) {
290 if (b
.getHeaders().get(Constants
.BUNDLE_VERSION
).equals(
291 osgiBundle
.getVersion())) {
293 osgiBundle
.setInternalBundleId(b
.getBundleId());
301 /** Find a single bundle based on a symbolic name pattern. */
302 public OsgiBundle
findFromPattern(String pattern
) {
303 OsgiBundle osgiBundle
= null;
304 for (Bundle b
: bundleContext
.getBundles()) {
305 if (b
.getSymbolicName().contains(pattern
)) {
306 osgiBundle
= new OsgiBundle(b
);
313 public OsgiBundle
getBundle(Long bundleId
) {
314 Bundle bundle
= bundleContext
.getBundle(bundleId
);
315 return new OsgiBundle(bundle
);
318 public void setBundleContext(BundleContext bundleContext
) {
319 this.bundleContext
= bundleContext
;
322 public void afterPropertiesSet() throws Exception
{
323 bundleContext
.addFrameworkListener(this);
326 public void destroy() throws Exception
{
327 bundleContext
.removeFrameworkListener(this);
330 public void setDefaultTimeout(Long defaultTimeout
) {
331 this.defaultTimeout
= defaultTimeout
;
334 /** Temporary internal access for {@link OsgiExecutionModulesManager} */
335 BundleContext
getBundleContext() {
336 return bundleContext
;
339 public void setPollingPeriod(Long pollingPeriod
) {
340 this.pollingPeriod
= pollingPeriod
;