]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/BundlesManager.java
Reduce debug verbosity
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.osgi / src / main / java / org / argeo / slc / osgi / BundlesManager.java
1 package org.argeo.slc.osgi;
2
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;
21
22 /** Wraps low-level access to a {@link BundleContext} */
23 public class BundlesManager implements BundleContextAware, FrameworkListener,
24 InitializingBean {
25 private final static Log log = LogFactory.getLog(BundlesManager.class);
26
27 private BundleContext bundleContext;
28
29 private Long defaultTimeout = 10000l;
30 private final Object refreshedPackageSem = new Object();
31
32 /**
33 * Stop the module, update it, refresh it and restart it. All synchronously.
34 */
35 public void upgradeSynchronous(OsgiBundle osgiBundle) {
36 try {
37 Bundle bundle = findRelatedBundle(osgiBundle);
38 stopSynchronous(bundle);
39 updateSynchronous(bundle);
40 // Refresh in case there are fragments
41 refreshSynchronous(bundle);
42 startSynchronous(bundle);
43
44 String filter = "(Bundle-SymbolicName=" + bundle.getSymbolicName()
45 + ")";
46 // Wait for application context to be ready
47 // TODO: use service tracker
48 getServiceRefSynchronous(ApplicationContext.class.getName(), filter);
49
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);
55 }
56 }
57
58 /** Updates bundle synchronously. */
59 protected void updateSynchronous(Bundle bundle) throws BundleException {
60 // int originalState = bundle.getState();
61 bundle.update();
62 boolean waiting = true;
63
64 long begin = System.currentTimeMillis();
65 do {
66 int state = bundle.getState();
67 if (state == Bundle.INSTALLED || state == Bundle.ACTIVE
68 || state == Bundle.RESOLVED)
69 waiting = false;
70
71 sleep(100);
72 if (System.currentTimeMillis() - begin > defaultTimeout)
73 throw new SlcException("Update of bundle "
74 + bundle.getSymbolicName()
75 + " timed out. Bundle state = " + bundle.getState());
76 } while (waiting);
77
78 if (log.isTraceEnabled())
79 log.debug("Bundle " + bundle.getSymbolicName() + " updated.");
80 }
81
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)
86 return;
87
88 bundle.start();
89 boolean waiting = true;
90
91 long begin = System.currentTimeMillis();
92 do {
93 if (bundle.getState() == Bundle.ACTIVE)
94 waiting = false;
95
96 sleep(100);
97 if (System.currentTimeMillis() - begin > defaultTimeout)
98 throw new SlcException("Start of bundle "
99 + bundle.getSymbolicName()
100 + " timed out. Bundle state = " + bundle.getState());
101 } while (waiting);
102
103 if (log.isTraceEnabled())
104 log.debug("Bundle " + bundle.getSymbolicName() + " started.");
105 }
106
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)
111 return;
112
113 bundle.stop();
114 boolean waiting = true;
115
116 long begin = System.currentTimeMillis();
117 do {
118 if (bundle.getState() != Bundle.ACTIVE
119 && bundle.getState() != Bundle.STOPPING)
120 waiting = false;
121
122 sleep(100);
123 if (System.currentTimeMillis() - begin > defaultTimeout)
124 throw new SlcException("Stop of bundle "
125 + bundle.getSymbolicName()
126 + " timed out. Bundle state = " + bundle.getState());
127 } while (waiting);
128
129 if (log.isTraceEnabled())
130 log.debug("Bundle " + bundle.getSymbolicName() + " stopped.");
131 }
132
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);
141
142 synchronized (refreshedPackageSem) {
143 try {
144 refreshedPackageSem.wait(defaultTimeout);
145 } catch (InterruptedException e) {
146 // silent
147 }
148 }
149
150 if (log.isTraceEnabled())
151 log.debug("Bundle " + bundle.getSymbolicName() + " refreshed.");
152 }
153
154 public void frameworkEvent(FrameworkEvent event) {
155 if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
156 synchronized (refreshedPackageSem) {
157 refreshedPackageSem.notifyAll();
158 }
159 }
160 }
161
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();
169 do {
170 sfs = bundleContext.getServiceReferences(clss, filter);
171
172 if (sfs != null)
173 waiting = false;
174
175 sleep(100);
176 if (System.currentTimeMillis() - begin > defaultTimeout)
177 throw new SlcException("Search of services " + clss
178 + " with filter " + filter + " timed out.");
179 } while (waiting);
180
181 return sfs;
182 }
183
184 protected void sleep(long ms) {
185 try {
186 Thread.sleep(ms);
187 } catch (InterruptedException e) {
188 // silent
189 }
190 }
191
192 /** Creates and open a new service tracker. */
193 public ServiceTracker newTracker(Class<?> clss) {
194 ServiceTracker st = new ServiceTracker(bundleContext, clss.getName(),
195 null);
196 st.open();
197 return st;
198 }
199
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;
204 try {
205 sfs = bundleContext.getServiceReferences(clss.getName(), filter);
206 } catch (InvalidSyntaxException e) {
207 throw new SlcException("Cannot retrieve service reference for "
208 + filter, e);
209 }
210
211 if (sfs == null || sfs.length == 0)
212 return null;
213 else if (sfs.length > 1)
214 throw new SlcException("More than one execution flow found for "
215 + filter);
216 return (T) bundleContext.getService(sfs[0]);
217 }
218
219 public <T> T getSingleServiceStrict(Class<T> clss, String filter) {
220 T service = getSingleService(clss, filter);
221 if (service == null)
222 throw new SlcException("No execution flow found for " + filter);
223 else
224 return service;
225 }
226
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());
232 Assert.isTrue(
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");
238 } else {
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())) {
243 bundle = b;
244 osgiBundle.setInternalBundleId(b.getBundleId());
245 }
246 }
247 }
248 }
249 return bundle;
250 }
251
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);
258 break;
259 }
260 }
261 return osgiBundle;
262 }
263
264 public OsgiBundle getBundle(Long bundleId) {
265 Bundle bundle = bundleContext.getBundle(bundleId);
266 return new OsgiBundle(bundle);
267 }
268
269 public void setBundleContext(BundleContext bundleContext) {
270 this.bundleContext = bundleContext;
271 }
272
273 public void afterPropertiesSet() throws Exception {
274 bundleContext.addFrameworkListener(this);
275 }
276
277 public void setDefaultTimeout(Long defaultTimeout) {
278 this.defaultTimeout = defaultTimeout;
279 }
280
281 /** Temporary internal access for {@link OsgiExecutionModulesManager} */
282 BundleContext getBundleContext() {
283 return bundleContext;
284 }
285
286 }