1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2006, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss.embedded;
23
24 import java.io.IOException;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.util.Enumeration;
28 import java.util.List;
29
30 import org.jboss.beans.metadata.plugins.AbstractBeanMetaData;
31 import org.jboss.deployers.client.spi.main.MainDeployer;
32 import org.jboss.deployers.spi.DeploymentException;
33 import org.jboss.embedded.adapters.ServerConfig;
34 import org.jboss.kernel.Kernel;
35 import org.jboss.kernel.plugins.bootstrap.basic.BasicBootstrap;
36 import org.jboss.kernel.plugins.deployment.xml.BeanXMLDeployer;
37 import org.jboss.logging.Logger;
38 import org.jboss.virtual.VirtualFile;
39
40 /**
41 * Basic bootstrap class for embeddable JBoss
42 *
43 * @author <a href="bill@jboss.com">Bill Burke</a>
44 * @author adrian@jboss.org
45 * @version $Revision: 1.1 $
46 */
47 public class Bootstrap
48 {
49 private static final Logger log = Logger.getLogger(Bootstrap.class);
50
51 public static final String BOOTSTRAP_RESOURCE_PATH="jboss.embedded.bootstrap.resource.path";
52 public static final String BOOTSTRAP_RESOURCE_FILE="conf/bootstrap-beans.xml";
53
54 protected Kernel kernel;
55 protected ClassLoader loader = Thread.currentThread().getContextClassLoader();
56 protected MainDeployer mainDeployer;
57 protected boolean started;
58 protected boolean ignoreShutdownErrors;
59
60 private static Bootstrap instance;
61
62 /**
63 * For those applications that need a singelton Bootstrap instance
64 *
65 * @return the bootstrap
66 */
67 public static synchronized Bootstrap getInstance()
68 {
69 if (instance == null)
70 instance = new Bootstrap(createKernel());
71
72 return instance;
73 }
74
75 public Bootstrap()
76 {
77 this.kernel = createKernel();
78 }
79
80 public Bootstrap(Kernel kernel)
81 {
82 this.kernel = kernel;
83 }
84
85 public boolean isIgnoreShutdownErrors()
86 {
87 return ignoreShutdownErrors;
88 }
89
90 public void setIgnoreShutdownErrors(boolean ignoreShutdownErrors)
91 {
92 this.ignoreShutdownErrors = ignoreShutdownErrors;
93 }
94
95 public boolean isStarted()
96 {
97 return started;
98 }
99
100 public Kernel getKernel()
101 {
102 return kernel;
103 }
104
105 public void setKernel(Kernel kernel)
106 {
107 this.kernel = kernel;
108 }
109
110 public ClassLoader getLoader()
111 {
112 return loader;
113 }
114
115 public void setLoader(ClassLoader loader)
116 {
117 this.loader = loader;
118 }
119
120 protected static Kernel createKernel()
121 {
122 BasicBootstrap bootstrap1 = new BasicBootstrap();
123 bootstrap1.run();
124 return bootstrap1.getKernel();
125 }
126
127 protected void deployBaseBootstrapUrl(URL url) throws Throwable
128 {
129 BeanXMLDeployer deployer = new BeanXMLDeployer(kernel);
130 deployer.deploy(url);
131 }
132
133 protected void bootstrapURL(URL url) throws DeploymentException
134 {
135 try
136 {
137 // ServerConfig has to be created and installed before boostrap as we may want to use
138 // system properties set up in ServerConfig
139 ServerConfig config = new ServerConfig();
140 AbstractBeanMetaData bmd = new AbstractBeanMetaData("ServerConfig", ServerConfig.class.getName());
141 kernel.getController().install(bmd, config);
142 deployBaseBootstrapUrl(url);
143 mainDeployer = (MainDeployer)kernel.getRegistry().getEntry("MainDeployer").getTarget();
144 }
145 catch (Throwable throwable)
146 {
147 throw new RuntimeException("Unable to bootstrap: ", throwable);
148 }
149 mainDeployer.checkComplete();
150 started = true;
151 }
152
153 /**
154 *
155 * Specify top classpath resource directory where base JBoss Embedded directory structure is.
156
157 * The Embedded JBoss directory structure is determined by extrapolating a directory from a base
158 * classpath resource.
159
160 * The absolute directory will be determined by doing
161 * classloader.getResource(bootstrapResourcePath + "conf/bootstrap-beans.xml")
162 *
163 *
164 * @param bootstrapResourcePath
165 * @throws DeploymentException
166 */
167 public void bootstrap(String bootstrapResourcePath) throws DeploymentException
168 {
169 if (bootstrapResourcePath == null)
170 {
171 bootstrapResourcePath = "";
172 }
173 else if (!bootstrapResourcePath.equals("") && !bootstrapResourcePath.endsWith("/"))
174 {
175 bootstrapResourcePath += "/";
176 }
177 System.setProperty(BOOTSTRAP_RESOURCE_PATH, bootstrapResourcePath);
178 bootstrapResourcePath += BOOTSTRAP_RESOURCE_FILE;
179 URL url = loader.getResource(bootstrapResourcePath);
180 if (url == null)
181 throw new DeploymentException("Unable to find bootstrap file: " + bootstrapResourcePath + " in classpath");
182
183 bootstrapURL(url);
184 }
185
186 /**
187 * Will obtain resource path from jboss.embedded.bootstrap.resource.path System Property.
188 * Otherwise it just invoked bootstrap(String bootstrapResourcePath) with ""
189 *
190 * @throws DeploymentException
191 */
192 public void bootstrap() throws DeploymentException
193 {
194 String path = System.getProperty(BOOTSTRAP_RESOURCE_PATH, "");
195 bootstrap(path);
196 }
197
198 /**
199 * Shutdown the kernel and all deployments
200 *
201 */
202 public void shutdown()
203 {
204 try
205 {
206 mainDeployer.shutdown();
207 }
208 catch (Exception e)
209 {
210 if (!ignoreShutdownErrors)
211 throw new RuntimeException(e);
212 else
213 log.error("Failed to shutdown Bootstrap", e);
214 }
215 }
216
217 /**
218 * Look in java.class.path for any .jar or class directories whose base file/dir match
219 * any base file/dir names in the comma delimited path parameter
220 *
221 * If classpath is:
222 *
223 * /home/wburke/jars/foo.jar
224 *
225 * and path is:
226 *
227 * "foo.jar"
228 *
229 * This will be a match and that .jar file will be deployed
230 *
231 * @param path can be comma delimited
232 * @throws DeploymentException
233 */
234 public void scanClasspath(String path) throws DeploymentException
235 {
236 DeploymentGroup group = createDeploymentGroup();
237 group.addClasspath(path);
238 group.process();
239 }
240
241 /**
242 * Undeploy something deployed via scanSclasspath()
243 *
244 * @param path
245 * @throws DeploymentException
246 */
247 public void undeployClasspath(String path) throws DeploymentException
248 {
249 List<URL> paths = DeploymentGroup.getClassPaths(path);
250 for (URL url : paths)
251 {
252 undeploy(url);
253 }
254 }
255
256 /**
257 * Deploy the classpath directories or .jar files a classloader resource is located in.
258 * ClassLoader.getResources() is used to find the base resources.
259 *
260 * i.e.
261 *
262 * classpath is "/home/wburke/lib/tutorial.jar:/home/wburke/lib/pu.jar"
263 * tutorial.jar and pu.jar has "META-INF/persistence.xml" resource within it.
264 *
265 * addResourceBases("META-INF/persistence.xml") will try and deploy tutorial.jar and pu.jar because
266 * the both have the META-INF/persistence.xml resource within them.
267 *
268 *
269 * @param baseResource
270 * @throws DeploymentException
271 */
272 public void deployResourceBase(String baseResource) throws DeploymentException
273 {
274 DeploymentGroup group = createDeploymentGroup();
275 group.addResourceBase(baseResource);
276 group.process();
277 }
278
279 /**
280 *
281 *
282 * @param baseResource
283 * @throws DeploymentException
284 */
285 public void deployResourceBases(String baseResource) throws DeploymentException
286 {
287 DeploymentGroup group = createDeploymentGroup();
288 group.addResourceBases(baseResource);
289 group.process();
290 }
291
292 /**
293 * Find the .class resource of the given class
294 * Deploy a URL pointing to the classpath the resource is located in.
295 *
296 * i.e.
297 *
298 * classpath is "/home/wburke/lib/tutorial.jar"
299 * tutorial.jar has "META-INF/persistence.xml" resource within it.
300 *
301 * addResourceBase("META-INF/persistence.xml") will try and deploy tutorial.jar
302 *
303 * classloader.getResource("META-INF/persistence.xml") is used to determine the base location
304 *
305 *
306 * @param baseResource
307 * @throws DeploymentException
308 */
309 public void deployResourceBase(Class baseResource) throws DeploymentException
310 {
311 DeploymentGroup group = createDeploymentGroup();
312 group.addResourceBase(baseResource);
313 group.process();
314 }
315
316 public void deploy(URL url) throws DeploymentException
317 {
318 DeploymentGroup group = createDeploymentGroup();
319 group.add(url);
320 group.process();
321 }
322
323 public void deploy(VirtualFile file) throws DeploymentException
324 {
325 DeploymentGroup group = createDeploymentGroup();
326 group.add(file);
327 group.process();
328 }
329
330 /**
331 * Deploy a resource found by getResource() on the kernel's classloader
332 *
333 *
334 * @param resource
335 * @throws DeploymentException
336 */
337 public void deployResource(String resource) throws DeploymentException
338 {
339 DeploymentGroup group = createDeploymentGroup();
340 group.addResource(resource);
341 group.process();
342 }
343
344 /**
345 * Define a deploy directory and deploy all files within it. The recurse parameter tells whether to recurse into
346 * sub directories for deployments
347 *
348 *
349 * @param url
350 * @param recurse
351 * @throws DeploymentException
352 * @throws IOException
353 */
354 public void deployDirectory(URL url, boolean recurse) throws DeploymentException, IOException
355 {
356 DeploymentGroup group = createDeploymentGroup();
357 group.addDirectory(url, recurse);
358 group.process();
359 }
360
361 /**
362 *
363 * Find a deploy directory from a base resource
364 *
365 * @param resource
366 * @param recurse
367 * @throws DeploymentException
368 * @throws IOException
369 */
370 public void deployDirectoryFromResource(String resource, boolean recurse) throws DeploymentException, IOException
371 {
372 DeploymentGroup group = createDeploymentGroup();
373 group.addDirectoryByResource(resource, recurse);
374 group.process();
375 }
376
377 /**
378 * opposite of deployResourceBase()
379 *
380 *
381 *
382 * @param baseResource
383 * @throws DeploymentException
384 */
385 public void undeployResourceBase(String baseResource) throws DeploymentException
386 {
387 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
388 if (loader != null)
389 classLoader = loader;
390
391 URL url = classLoader.getResource(baseResource);
392 if (url == null)
393 throw new RuntimeException("Could not find baseResource: " + baseResource);
394
395 undeployResourceBase(url, baseResource);
396 }
397
398 private void undeployResourceBase(URL url, String baseResource)
399 throws DeploymentException
400 {
401 String urlString = url.toString();
402 int idx = urlString.lastIndexOf(baseResource);
403 urlString = urlString.substring(0, idx);
404 URL deployUrl;
405 try
406 {
407 deployUrl = new URL(urlString);
408 }
409 catch (MalformedURLException e)
410 {
411 throw new RuntimeException(e);
412 }
413 undeploy(deployUrl);
414 }
415
416 public void undeployResourceBases(String baseResource) throws DeploymentException
417 {
418 try
419 {
420 Enumeration<URL> urls = loader.getResources(baseResource);
421 while (urls.hasMoreElements())
422 {
423 URL url = urls.nextElement();
424 undeployResourceBase(url, baseResource);
425 }
426 }
427 catch (IOException e)
428 {
429 throw new RuntimeException(e);
430 }
431 }
432
433 /**
434 * opposite of deployResourceBase()
435 *
436 *
437 *
438 * @param baseResource
439 * @throws DeploymentException
440 */
441 public void undeployResourceBase(Class baseResource) throws DeploymentException
442 {
443 String resource = baseResource.getName().replace('.', '/') + ".class";
444 undeployResourceBase(resource);
445 }
446 /**
447 * opposite of deployResource
448 *
449 * @param resource
450 * @throws DeploymentException
451 */
452 public void undeployResource(String resource) throws DeploymentException
453 {
454 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
455 if (loader != null)
456 classLoader = loader;
457
458 URL url = classLoader.getResource(resource);
459 if (url == null)
460 throw new NullPointerException("Resource was null: " + resource);
461
462 undeploy(url);
463 }
464
465 public void undeploy(URL url) throws DeploymentException
466 {
467 VirtualFile vf = DeploymentGroup.getVirtualFile(url);
468 undeploy(vf);
469 }
470
471 public void undeploy(VirtualFile vf)
472 throws DeploymentException
473 {
474 mainDeployer.removeDeployment(vf.getName());
475 mainDeployer.process();
476 }
477
478 public void undeployDirectory(URL url, boolean recurse) throws DeploymentException, IOException
479 {
480 List<VirtualFile> files = DeploymentGroup.getDeployerDirUrls(null, url, recurse);
481 for (VirtualFile vf : files)
482 mainDeployer.removeDeployment(vf.getName());
483 mainDeployer.process();
484 }
485
486 public void undeployDirectoryFromResource(String resource, boolean recurse) throws DeploymentException, IOException
487 {
488 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
489 if (loader != null) classLoader = loader;
490 List<VirtualFile> files = DeploymentGroup.getDeployerDirUrlsFromResource(null, classLoader, resource, recurse);
491 for (VirtualFile vf : files)
492 mainDeployer.removeDeployment(vf.getName());
493 mainDeployer.process();
494 }
495
496 public DeploymentGroup createDeploymentGroup()
497 {
498 DeploymentGroup group = new DeploymentGroup();
499 group.setClassLoader(loader);
500 group.setMainDeployer(mainDeployer);
501 group.setKernel(kernel);
502 return group;
503 }
504
505 public static void main(String[] args) throws Exception
506 {
507 getInstance().bootstrap();
508 for (String arg : args)
509 {
510 getInstance().scanClasspath(arg);
511 }
512 System.out.println("Running...");
513 Thread t = new Thread();
514 t.setDaemon(false);
515 t.start();
516 }
517 }