]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBuilder.java
Add Jcr utilities.
[lgpl/argeo-commons.git] / org.argeo.osgi.boot / src / org / argeo / osgi / boot / OsgiBuilder.java
1 package org.argeo.osgi.boot;
2
3 import java.lang.reflect.Method;
4 import java.net.URI;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Properties;
12 import java.util.Set;
13 import java.util.TreeMap;
14
15 import org.eclipse.osgi.launch.EquinoxFactory;
16 import org.osgi.framework.Bundle;
17 import org.osgi.framework.BundleContext;
18 import org.osgi.framework.BundleEvent;
19 import org.osgi.framework.BundleException;
20 import org.osgi.framework.FrameworkUtil;
21 import org.osgi.framework.InvalidSyntaxException;
22 import org.osgi.framework.ServiceReference;
23 import org.osgi.framework.launch.Framework;
24 import org.osgi.framework.launch.FrameworkFactory;
25 import org.osgi.util.tracker.BundleTracker;
26 import org.osgi.util.tracker.ServiceTracker;
27
28 /** OSGi builder, focusing on ease of use for scripting. */
29 public class OsgiBuilder {
30 private final static String PROP_HTTP_PORT = "org.osgi.service.http.port";
31 private final static String PROP_HTTPS_PORT = "org.osgi.service.https.port";
32 private final static String PROP_OSGI_CLEAN = "osgi.clean";
33
34 private Map<Integer, StartLevel> startLevels = new TreeMap<>();
35 private List<String> distributionBundles = new ArrayList<>();
36
37 private Map<String, String> configuration = new HashMap<String, String>();
38 private Framework framework;
39 private String baseUrl = null;
40
41 public OsgiBuilder() {
42 // configuration.put("osgi.clean", "true");
43 configuration.put(OsgiBoot.CONFIGURATION_AREA_PROP, System.getProperty(OsgiBoot.CONFIGURATION_AREA_PROP));
44 configuration.put(OsgiBoot.INSTANCE_AREA_PROP, System.getProperty(OsgiBoot.INSTANCE_AREA_PROP));
45 configuration.put(PROP_OSGI_CLEAN, System.getProperty(PROP_OSGI_CLEAN));
46 }
47
48 public Framework launch() {
49 // start OSGi
50 FrameworkFactory frameworkFactory = new EquinoxFactory();
51 framework = frameworkFactory.newFramework(configuration);
52 try {
53 framework.start();
54 } catch (BundleException e) {
55 throw new OsgiBootException("Cannot start OSGi framework", e);
56 }
57
58 BundleContext bc = framework.getBundleContext();
59 String osgiData = bc.getProperty(OsgiBoot.INSTANCE_AREA_PROP);
60 // String osgiConf = bc.getProperty(OsgiBoot.CONFIGURATION_AREA_PROP);
61 String osgiConf = framework.getDataFile("").getAbsolutePath();
62 if (OsgiBootUtils.isDebug())
63 OsgiBootUtils.debug("OSGi starting - data: " + osgiData + " conf: " + osgiConf);
64
65 OsgiBoot osgiBoot = new OsgiBoot(framework.getBundleContext());
66 if (distributionBundles.isEmpty()) {
67 osgiBoot.getProvisioningManager().install(null);
68 } else {
69 // install bundles
70 for (String distributionBundle : distributionBundles) {
71 List<String> bundleUrls = osgiBoot.getDistributionUrls(distributionBundle, baseUrl);
72 osgiBoot.installUrls(bundleUrls);
73 }
74 }
75 // start bundles
76 osgiBoot.startBundles(startLevelsToProperties());
77
78 // if (OsgiBootUtils.isDebug())
79 // for (Bundle bundle : bc.getBundles()) {
80 // OsgiBootUtils.debug(bundle.getLocation());
81 // }
82 return framework;
83 }
84
85 public OsgiBuilder conf(String key, String value) {
86 checkNotLaunched();
87 configuration.put(key, value);
88 return this;
89 }
90
91 public OsgiBuilder install(String uri) {
92 // TODO dynamic install
93 checkNotLaunched();
94 if (!distributionBundles.contains(uri))
95 distributionBundles.add(uri);
96 return this;
97 }
98
99 public OsgiBuilder start(int startLevel, String bundle) {
100 // TODO dynamic start
101 checkNotLaunched();
102 StartLevel sl;
103 if (!startLevels.containsKey(startLevel))
104 startLevels.put(startLevel, new StartLevel());
105 sl = startLevels.get(startLevel);
106 sl.add(bundle);
107 return this;
108 }
109
110 public OsgiBuilder waitForServlet(String base) {
111 service("(&(objectClass=javax.servlet.Servlet)(osgi.http.whiteboard.servlet.pattern=" + base + "))");
112 return this;
113 }
114
115 public OsgiBuilder waitForBundle(String bundles) {
116 List<String> lst = new ArrayList<>();
117 Collections.addAll(lst, bundles.split(","));
118 BundleTracker<Object> bt = new BundleTracker<Object>(getBc(), Bundle.ACTIVE, null) {
119
120 @Override
121 public Object addingBundle(Bundle bundle, BundleEvent event) {
122 if (lst.contains(bundle.getSymbolicName())) {
123 return bundle.getSymbolicName();
124 } else {
125 return null;
126 }
127 }
128 };
129 bt.open();
130 while (bt.getTrackingCount() != lst.size()) {
131 try {
132 Thread.sleep(500l);
133 } catch (InterruptedException e) {
134 break;
135 }
136 }
137 bt.close();
138 return this;
139
140 }
141
142 public OsgiBuilder main(String clssUri, String[] args) {
143
144 // waitForBundle(bundleSymbolicName);
145 try {
146 URI uri = new URI(clssUri);
147 if (!"bundleclass".equals(uri.getScheme()))
148 throw new IllegalArgumentException("Unsupported scheme for " + clssUri);
149 String bundleSymbolicName = uri.getHost();
150 String clss = uri.getPath().substring(1);
151 Bundle bundle = null;
152 for (Bundle b : getBc().getBundles()) {
153 if (bundleSymbolicName.equals(b.getSymbolicName())) {
154 bundle = b;
155 break;
156 }
157 }
158 if (bundle == null)
159 throw new OsgiBootException("Bundle " + bundleSymbolicName + " not found");
160 Class<?> c = bundle.loadClass(clss);
161 Object[] mainArgs = { args };
162 Method mainMethod = c.getMethod("main", String[].class);
163 mainMethod.invoke(null, mainArgs);
164 } catch (Throwable e) {
165 throw new OsgiBootException("Cannot execute " + clssUri, e);
166 }
167 return this;
168 }
169
170 public Object service(String service) {
171 return service(service, 0);
172 }
173
174 public Object service(String service, long timeout) {
175 ServiceTracker<Object, Object> st;
176 if (service.contains("(")) {
177 try {
178 st = new ServiceTracker<>(getBc(), FrameworkUtil.createFilter(service), null);
179 } catch (InvalidSyntaxException e) {
180 throw new IllegalArgumentException("Badly formatted filter", e);
181 }
182 } else {
183 st = new ServiceTracker<>(getBc(), service, null);
184 }
185 st.open();
186 try {
187 return st.waitForService(timeout);
188 } catch (InterruptedException e) {
189 OsgiBootUtils.error("Interrupted", e);
190 return null;
191 } finally {
192 st.close();
193 }
194
195 }
196
197 public void shutdown() {
198 checkLaunched();
199 try {
200 framework.stop();
201 } catch (BundleException e) {
202 e.printStackTrace();
203 System.exit(1);
204 }
205 try {
206 framework.waitForStop(10 * 60 * 1000);
207 } catch (InterruptedException e) {
208 e.printStackTrace();
209 System.exit(1);
210 }
211 System.exit(0);
212 }
213
214 public void setHttpPort(Integer port) {
215 checkNotLaunched();
216 configuration.put(PROP_HTTP_PORT, Integer.toString(port));
217 }
218
219 public void setHttpsPort(Integer port) {
220 checkNotLaunched();
221 configuration.put(PROP_HTTPS_PORT, Integer.toString(port));
222 }
223
224 public void setClean(boolean clean) {
225 checkNotLaunched();
226 configuration.put(PROP_OSGI_CLEAN, Boolean.toString(clean));
227 }
228
229 public Integer getHttpPort() {
230 if (!isLaunched()) {
231 if (configuration.containsKey(PROP_HTTP_PORT))
232 return Integer.parseInt(configuration.get(PROP_HTTP_PORT));
233 else
234 return -1;
235 } else {
236 // TODO wait for service?
237 ServiceReference<?> sr = getBc().getServiceReference("org.osgi.service.http.HttpService");
238 if (sr == null)
239 return -1;
240 Object port = sr.getProperty("http.port");
241 if (port == null)
242 return -1;
243 return Integer.parseInt(port.toString());
244 }
245 }
246
247 public Integer getHttpsPort() {
248 if (!isLaunched()) {
249 if (configuration.containsKey(PROP_HTTPS_PORT))
250 return Integer.parseInt(configuration.get(PROP_HTTPS_PORT));
251 else
252 return -1;
253 } else {
254 // TODO wait for service?
255 ServiceReference<?> sr = getBc().getServiceReference("org.osgi.service.http.HttpService");
256 if (sr == null)
257 return -1;
258 Object port = sr.getProperty("https.port");
259 if (port == null)
260 return -1;
261 return Integer.parseInt(port.toString());
262 }
263 }
264
265 public Object spring(String bundle) {
266 return service("(&(Bundle-SymbolicName=" + bundle + ")"
267 + "(objectClass=org.springframework.context.ApplicationContext))");
268 }
269
270 //
271 // BEAN
272 //
273
274 public BundleContext getBc() {
275 checkLaunched();
276 return framework.getBundleContext();
277 }
278
279 public void setBaseUrl(String baseUrl) {
280 this.baseUrl = baseUrl;
281 }
282
283 //
284 // UTILITIES
285 //
286 private Properties startLevelsToProperties() {
287 Properties properties = new Properties();
288 for (Integer startLevel : startLevels.keySet()) {
289 String property = OsgiBoot.PROP_ARGEO_OSGI_START + "." + startLevel;
290 StringBuilder value = new StringBuilder();
291 for (String bundle : startLevels.get(startLevel).getBundles()) {
292 value.append(bundle);
293 value.append(',');
294 }
295 // TODO remove trailing comma
296 properties.put(property, value.toString());
297 }
298 return properties;
299 }
300
301 private void checkLaunched() {
302 if (!isLaunched())
303 throw new OsgiBootException("OSGi runtime is not launched");
304 }
305
306 private void checkNotLaunched() {
307 if (isLaunched())
308 throw new OsgiBootException("OSGi runtime already launched");
309 }
310
311 private boolean isLaunched() {
312 return framework != null;
313 }
314
315 private static class StartLevel {
316 private Set<String> bundles = new HashSet<>();
317
318 public void add(String bundle) {
319 String[] b = bundle.split(",");
320 Collections.addAll(bundles, b);
321 }
322
323 public Set<String> getBundles() {
324 return bundles;
325 }
326 }
327 }