001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.e_app;
031:
032: import com.caucho.config.ConfigException;
033: import com.caucho.ejb.manager.EjbContainer;
034: import com.caucho.java.WorkDir;
035: import com.caucho.lifecycle.Lifecycle;
036: import com.caucho.loader.*;
037: import com.caucho.log.Log;
038: import com.caucho.server.deploy.EnvironmentDeployInstance;
039: import com.caucho.server.webapp.WebAppContainer;
040: import com.caucho.server.webapp.WebAppController;
041: import com.caucho.server.webapp.WebAppConfig;
042: import com.caucho.util.L10N;
043: import com.caucho.vfs.Depend;
044: import com.caucho.vfs.JarPath;
045: import com.caucho.vfs.Path;
046: import com.caucho.vfs.Vfs;
047:
048: import javax.annotation.PostConstruct;
049: import java.util.ArrayList;
050: import java.util.logging.Level;
051: import java.util.logging.Logger;
052:
053: /**
054: * An enterprise application (ear)
055: */
056: public class EnterpriseApplication implements EnvironmentBean,
057: EnvironmentDeployInstance {
058: static final L10N L = new L10N(EnterpriseApplication.class);
059: static final Logger log = Logger
060: .getLogger(EnterpriseApplication.class.getName());
061:
062: private static final EnvironmentLocal<EnterpriseApplication> _localEApp = new EnvironmentLocal<EnterpriseApplication>();
063:
064: /*
065: protected static EnvironmentLocal<EJBServerInterface> _localServer
066: = new EnvironmentLocal<EJBServerInterface>("caucho.ejb-server");
067: */
068:
069: private EnvironmentClassLoader _loader;
070:
071: private String _name;
072:
073: private String _ejbServerJndiName = "java:comp/env/cmp";
074:
075: private Path _rootDir;
076:
077: private Path _earPath;
078:
079: private String _prefix = "";
080:
081: private EarDeployController _controller;
082:
083: private Path _webappsPath;
084:
085: private WebAppContainer _container;
086: private String _version;
087:
088: private String _libraryDirectory;
089:
090: private boolean _hasModule;
091:
092: // private WarDirApplicationGenerator _warDeploy;
093:
094: private ArrayList<Path> _ejbPaths = new ArrayList<Path>();
095:
096: private ArrayList<WebModule> _webConfigList = new ArrayList<WebModule>();
097:
098: private ArrayList<WebAppController> _webApps = new ArrayList<WebAppController>();
099:
100: private Throwable _configException;
101:
102: private final Lifecycle _lifecycle;
103:
104: /**
105: * Creates the application.
106: */
107: EnterpriseApplication(WebAppContainer container,
108: EarDeployController controller, String name) {
109: if (container == null || controller == null)
110: throw new NullPointerException();
111:
112: _container = container;
113:
114: _controller = controller;
115: _name = name;
116:
117: ClassLoader parentLoader;
118:
119: if (container != null)
120: parentLoader = container.getClassLoader();
121: else
122: parentLoader = Thread.currentThread()
123: .getContextClassLoader();
124:
125: _loader = new EnvironmentClassLoader(parentLoader);
126: _loader.setId("eapp:" + name);
127:
128: _webappsPath = _controller.getRootDirectory().lookup("webapps");
129: WorkDir.setLocalWorkDir(_controller.getRootDirectory().lookup(
130: "META-INF/work"), _loader);
131:
132: _lifecycle = new Lifecycle(log, toString(), Level.INFO);
133:
134: if (controller.getArchivePath() != null)
135: Environment.addDependency(new Depend(controller
136: .getArchivePath()), _loader);
137:
138: _localEApp.set(this , _loader);
139: }
140:
141: /*
142: // ejb/0fa0
143: public EnterpriseApplication()
144: {
145: _lifecycle = new Lifecycle(log, toString(), Level.INFO);
146: }
147: */
148:
149: public static EnterpriseApplication getLocal() {
150: return _localEApp.get();
151: }
152:
153: /**
154: * Sets the name.
155: */
156: public void setName(String name) {
157: _name = name;
158: _loader.setId("eapp:" + name + "");
159: }
160:
161: /**
162: * Gets the name.
163: */
164: public String getName() {
165: return _name;
166: }
167:
168: /**
169: * Sets the library directory.
170: */
171: public void setLibraryDirectory(String libraryDirectory) {
172: _libraryDirectory = libraryDirectory;
173: }
174:
175: /**
176: * Gets the library directory.
177: */
178: public String getLibraryDirectory() {
179: return _libraryDirectory;
180: }
181:
182: /**
183: * Sets the ejb-server jndi name.
184: */
185: public void setEjbServerJndiName(String name) {
186: _ejbServerJndiName = name;
187: }
188:
189: /**
190: * Sets the root directory.
191: */
192: public void setRootDirectory(Path rootDir) {
193: _rootDir = rootDir;
194: }
195:
196: /**
197: * Sets the root directory.
198: */
199: public Path getRootDirectory() {
200: return _rootDir;
201: }
202:
203: /**
204: * Returns the class loader.
205: */
206: public EnvironmentClassLoader getClassLoader() {
207: return _loader;
208: }
209:
210: /**
211: * Sets the class loader.
212: */
213: public void setEnvironmentClassLoader(EnvironmentClassLoader loader) {
214: _loader = loader;
215: }
216:
217: /**
218: * Sets the path to the .ear file
219: */
220: public void setEarPath(Path earPath) {
221: _earPath = earPath;
222: }
223:
224: /**
225: * Sets the path to the expanded webapps
226: */
227: public void setWebapps(Path webappsPath) {
228: _webappsPath = webappsPath;
229: }
230:
231: /**
232: * Sets the prefix URL for web applications.
233: */
234: public void setPrefix(String prefix) {
235: _prefix = prefix;
236: }
237:
238: /**
239: * Sets the id
240: */
241: public void setId(String id) {
242: }
243:
244: /**
245: * Sets the application version.
246: */
247: public void setVersion(String version) {
248: _version = version;
249: }
250:
251: /**
252: * Sets the schema location
253: */
254: public void setSchemaLocation(String schema) {
255: }
256:
257: /**
258: * Sets the display name.
259: */
260: public void setDisplayName(String name) {
261: }
262:
263: /**
264: * Sets the description.
265: */
266: public void setDescription(String description) {
267: }
268:
269: /**
270: * Sets the icon.
271: */
272: public void setIcon(Icon icon) {
273: }
274:
275: /**
276: * Adds a module.
277: */
278: public Module createModule() {
279: _hasModule = true;
280:
281: return new Module();
282: }
283:
284: /**
285: * Finds a web module based on the web-uri
286: */
287: WebModule findWebModule(String webUri) {
288: for (int i = 0; i < _webConfigList.size(); i++) {
289: WebModule web = _webConfigList.get(i);
290:
291: if (webUri.equals(web.getWebURI()))
292: return web;
293: }
294:
295: return null;
296: }
297:
298: /**
299: * Finds a web module based on the web-uri
300: */
301: void addWebModule(WebModule webModule) {
302: _webConfigList.add(webModule);
303: }
304:
305: /**
306: * Adds a security role.
307: */
308: public void addSecurityRole(SecurityRole role) {
309: }
310:
311: /**
312: * Returns true if it's modified.
313: */
314: public boolean isModified() {
315: return _loader.isModified();
316: }
317:
318: /**
319: * Returns true if it's modified.
320: */
321: public boolean isModifiedNow() {
322: return _loader.isModifiedNow();
323: }
324:
325: /**
326: * Log the reason for modification.
327: */
328: public boolean logModified(Logger log) {
329: return _loader.logModified(log);
330: }
331:
332: /**
333: * Returns true if it's modified.
334: */
335: public boolean isDeployError() {
336: return _configException != null;
337: }
338:
339: /**
340: * Returns true if the application is idle.
341: */
342: public boolean isDeployIdle() {
343: return false;
344: }
345:
346: /**
347: * Sets the config exception.
348: */
349: public void setConfigException(Throwable e) {
350: _configException = e;
351:
352: for (WebAppController controller : _webApps) {
353: controller.setConfigException(e);
354: }
355: }
356:
357: /**
358: * Gets the config exception.
359: */
360: public Throwable getConfigException() {
361: return _configException;
362: }
363:
364: /**
365: * Configures the application.
366: */
367: @PostConstruct
368: public void init() throws Exception {
369: if (!_lifecycle.toInit())
370: return;
371:
372: Vfs.setPwd(_rootDir, _loader);
373:
374: _loader.addJarManifestClassPath(_rootDir);
375:
376: // server/13bb vs TCK
377: if ("1.4".equals(_version)) {
378: // XXX: tck ejb30/persistence/basic needs to add the lib/*.jar
379: // to find the META-INF/persistence.xml
380: fillDefaultLib();
381: } else {
382: fillDefaultModules();
383: }
384:
385: if (_ejbPaths.size() != 0) {
386: EjbContainer ejbContainer = EjbContainer.create();
387:
388: for (Path path : _ejbPaths) {
389: ejbContainer.addRoot(path);
390: _loader.addJar(path);
391: }
392:
393: _loader.validate();
394:
395: // XXX:??
396: /*
397: Path ejbJar = _rootDir.lookup("META-INF/ejb-jar.xml");
398: if (ejbJar.canRead()) {
399: ejbContainer.addRoot(path);
400: }
401: */
402:
403: // starts with the environment
404: // ejbServer.start();
405: }
406:
407: // updates the invocation caches
408: if (_container != null)
409: _container.clearCache();
410: }
411:
412: private void fillDefaultModules() {
413: try {
414: fillDefaultLib();
415:
416: for (String file : _rootDir.list()) {
417: if (file.endsWith(".jar")) {
418: Path path = _rootDir.lookup(file);
419: Path jar = JarPath.create(path);
420:
421: try {
422: if (jar.lookup(
423: "META-INF/application-client.xml")
424: .canRead()) {
425: // app-client jar
426: } else if (jar.lookup("META-INF/ejb-jar.xml")
427: .canRead()) {
428: addEjbPath(path);
429:
430: _loader.addJar(path);
431: _loader.addJarManifestClassPath(path);
432: } else {
433: addEjbPath(path);
434:
435: _loader.addJar(path);
436: }
437: } catch (java.util.zip.ZipException e) {
438: // XXX: jpa tck, error in opening zip file
439: // canRead() is throwing an exception when
440: // META-INF/application-client.xml does not exist?
441: log.log(Level.WARNING, e.toString(), e);
442: }
443: } else if (file.endsWith(".war")) {
444: Module module = createModule();
445: WebModule web = new WebModule();
446: web.setWebURI(file);
447:
448: module.addWeb(web);
449: }
450: }
451: } catch (RuntimeException e) {
452: throw e;
453: } catch (Exception e) {
454: throw ConfigException.create(e);
455: }
456: }
457:
458: private void fillDefaultLib() throws Exception {
459: String libDir = "lib";
460:
461: // ejb/0fa0
462: if (_libraryDirectory != null)
463: libDir = _libraryDirectory;
464:
465: if (_rootDir.lookup(libDir).isDirectory()) {
466: Path lib = _rootDir.lookup(libDir);
467:
468: for (String file : lib.list()) {
469: if (file.endsWith(".jar")) {
470: _loader.addJar(lib.lookup(file));
471: }
472: }
473: }
474: }
475:
476: /**
477: * Configures the application.
478: */
479: public void start() {
480: if (!_lifecycle.toStarting())
481: return;
482:
483: Thread thread = Thread.currentThread();
484: ClassLoader oldLoader = thread.getContextClassLoader();
485:
486: try {
487: thread.setContextClassLoader(getClassLoader());
488:
489: for (int i = 0; i < _webConfigList.size(); i++) {
490: WebModule web = _webConfigList.get(i);
491:
492: initWeb(web);
493: }
494:
495: getClassLoader().start();
496:
497: for (WebAppController webApp : _webApps) {
498: _container.getWebAppGenerator().update(
499: webApp.getContextPath());
500: }
501: } finally {
502: _lifecycle.toActive();
503:
504: thread.setContextClassLoader(oldLoader);
505: }
506: }
507:
508: void initWeb(WebModule web) {
509: String webUri = web.getWebURI();
510: String contextUrl = web.getContextRoot();
511: Path path = _rootDir.lookup(webUri);
512: Path archivePath = null;
513:
514: if (contextUrl == null)
515: contextUrl = webUri;
516:
517: WebAppController controller = null;
518:
519: if (webUri.endsWith(".war")) {
520: // server/2a16
521: String name = webUri.substring(0, webUri.length() - 4);
522: int p = name.lastIndexOf('/');
523: if (p > 0)
524: name = name.substring(p + 1);
525:
526: // XXX:
527: if (contextUrl.equals(""))
528: contextUrl = "/" + name;
529:
530: if (contextUrl.endsWith(".war"))
531: contextUrl = contextUrl.substring(0, contextUrl
532: .length() - 4);
533:
534: Path expandPath = _webappsPath;
535:
536: try {
537: expandPath.mkdirs();
538: } catch (Exception e) {
539: log.log(Level.WARNING, e.toString(), e);
540: }
541:
542: archivePath = path;
543: path = expandPath.lookup(name);
544: } else {
545: // server/2a15
546: if (contextUrl.equals("")) {
547: String name = webUri;
548: int p = name.lastIndexOf('/');
549: if (p > 0)
550: name = name.substring(p + 1);
551: contextUrl = "/" + name;
552: }
553:
554: // server/2a17
555: if (contextUrl.endsWith(".war"))
556: contextUrl = contextUrl.substring(0, contextUrl
557: .length() - 4);
558: }
559:
560: controller = findWebAppEntry(contextUrl);
561:
562: if (controller == null) {
563: controller = new WebAppController(contextUrl, contextUrl,
564: path, _container);
565:
566: _webApps.add(controller);
567: }
568:
569: if (archivePath != null)
570: controller.setArchivePath(archivePath);
571:
572: controller.setDynamicDeploy(true);
573:
574: if (_configException != null)
575: controller.setConfigException(_configException);
576:
577: for (WebAppConfig config : web.getWebAppList())
578: controller.addConfigDefault(config);
579: }
580:
581: /**
582: * Returns any matching web-app.
583: */
584: public WebAppController findWebAppEntry(String name) {
585: for (int i = 0; i < _webApps.size(); i++) {
586: WebAppController controller = _webApps.get(i);
587:
588: if (controller.isNameMatch(name))
589: return controller;
590: }
591:
592: return null;
593: }
594:
595: private void addDepend(Path path) {
596: _loader.addDependency(new com.caucho.vfs.Depend(path));
597: }
598:
599: /**
600: * Returns the webapps for the enterprise-application.
601: */
602: public ArrayList<WebAppController> getApplications() {
603: return _webApps;
604: }
605:
606: /**
607: * Stops the e-application.
608: */
609: public void stop() {
610: if (!_lifecycle.toStopping())
611: return;
612:
613: Thread thread = Thread.currentThread();
614: ClassLoader oldLoader = thread.getContextClassLoader();
615:
616: try {
617: thread.setContextClassLoader(_loader);
618:
619: //log.info(this + " stopping");
620:
621: _loader.stop();
622:
623: //log.fine(this + " stopped");
624: } finally {
625: _lifecycle.toStop();
626:
627: thread.setContextClassLoader(oldLoader);
628: }
629: }
630:
631: /**
632: * destroys the e-application.
633: */
634: public void destroy() {
635: stop();
636:
637: if (!_lifecycle.toDestroy())
638: return;
639:
640: Thread thread = Thread.currentThread();
641: ClassLoader oldLoader = thread.getContextClassLoader();
642:
643: try {
644: thread.setContextClassLoader(getClassLoader());
645:
646: log.fine(this + " destroying");
647:
648: ArrayList<WebAppController> webApps = _webApps;
649: _webApps = null;
650:
651: if (webApps != null) {
652: for (WebAppController webApp : webApps) {
653: _container.getWebAppGenerator().update(
654: webApp.getContextPath());
655: }
656: }
657: } finally {
658: thread.setContextClassLoader(oldLoader);
659:
660: _loader.destroy();
661:
662: log.fine(this + " destroyed");
663: }
664: }
665:
666: //
667: // JMX utilities
668: //
669:
670: public String getClientRefs() {
671: EjbContainer ejbContainer = EjbContainer.create();
672:
673: return ejbContainer.getClientRemoteConfig();
674: }
675:
676: public String toString() {
677: return "EnterpriseApplication[" + getName() + "]";
678: }
679:
680: public class Module {
681: /**
682: * Sets the module id.
683: */
684: public void setId(String id) {
685: }
686:
687: /**
688: * Creates a new web module.
689: */
690: public void addWeb(WebModule web) throws Exception {
691: String webUri = web.getWebURI();
692:
693: WebModule oldWeb = findWebModule(webUri);
694:
695: if (oldWeb != null) {
696: String contextUrl = web.getContextRoot();
697:
698: if (contextUrl != null && !"".equals(contextUrl))
699: oldWeb.setContextRoot(contextUrl);
700:
701: oldWeb.addWebAppList(web.getWebAppList());
702: } else
703: addWebModule(web);
704: }
705:
706: /**
707: * Adds a new ejb module.
708: */
709: public void addEjb(Path path) throws Exception {
710: addEjbPath(path);
711:
712: _loader.addJar(path);
713: // ejb/0853
714: _loader.addJarManifestClassPath(path);
715: }
716:
717: /**
718: * Adds a new java module.
719: */
720: public void addJava(Path path) throws ConfigException {
721: if (!path.canRead())
722: throw new ConfigException(L
723: .l("<java> module {0} must be a valid path.",
724: path));
725: }
726:
727: /**
728: * Adds a new connector
729: */
730: public void addConnector(String path) {
731: }
732:
733: /**
734: * Adds a new alt-dd module.
735: */
736: public void addAltDD(String path) {
737: }
738: }
739:
740: private void addEjbPath(Path ejbPath) {
741: if (_ejbPaths.contains(ejbPath))
742: return;
743:
744: _ejbPaths.add(ejbPath);
745: }
746: }
|