/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.server.e_app;
import com.caucho.config.ConfigException;
import com.caucho.ejb.manager.EjbManager;
import com.caucho.env.deploy.EnvironmentDeployInstance;
import com.caucho.inject.Module;
import com.caucho.java.WorkDir;
import com.caucho.lifecycle.Lifecycle;
import com.caucho.loader.*;
import com.caucho.server.webapp.WebAppContainer;
import com.caucho.server.webapp.WebAppController;
import com.caucho.server.webapp.WebAppConfig;
import com.caucho.util.L10N;
import com.caucho.vfs.Depend;
import com.caucho.vfs.JarPath;
import com.caucho.vfs.Path;
import com.caucho.vfs.Vfs;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An enterprise application (ear)
*/
@Module
public class EnterpriseApplication
implements EnvironmentBean, EnvironmentDeployInstance
{
static final L10N L = new L10N(EnterpriseApplication.class);
static final Logger log
= Logger.getLogger(EnterpriseApplication.class.getName());
private static final EnvironmentLocal<EnterpriseApplication> _localEApp
= new EnvironmentLocal<EnterpriseApplication>();
/*
protected static EnvironmentLocal<EJBServerInterface> _localServer
= new EnvironmentLocal<EJBServerInterface>("caucho.ejb-server");
*/
private EnvironmentClassLoader _loader;
private String _name;
private EarDeployController _controller;
private Path _webappsPath;
private WebAppContainer _webAppContainer;
private String _version;
private String _libraryDirectory;
private ArrayList<Path> _ejbPaths
= new ArrayList<Path>();
private ArrayList<WebModule> _webConfigList
= new ArrayList<WebModule>();
private ArrayList<WebAppController> _webApps
= new ArrayList<WebAppController>();
private Throwable _configException;
private final Lifecycle _lifecycle;
/**
* Creates the application.
*/
EnterpriseApplication(WebAppContainer container,
EarDeployController controller, String name)
{
_webAppContainer = container;
_controller = controller;
_name = name;
ClassLoader parentLoader;
if (container != null)
parentLoader = container.getClassLoader();
else
parentLoader = Thread.currentThread().getContextClassLoader();
_loader = EnvironmentClassLoader.create(parentLoader, "eapp:" + name);
if (_controller != null) {
Path entAppRoot = _controller.getRootDirectory();
// XXX: restrict to META-INF?
ResourceLoader loader = new ResourceLoader(_loader, entAppRoot);
loader.init();
_webappsPath = entAppRoot.lookup("webapps");
WorkDir.setLocalWorkDir(entAppRoot.lookup("META-INF/work"),
_loader);
}
_lifecycle = new Lifecycle(log, toString(), Level.INFO);
if (_controller != null && _controller.getArchivePath() != null)
Environment.addDependency(new Depend(_controller.getArchivePath()), _loader);
_localEApp.set(this, _loader);
}
public static EnterpriseApplication create(String name)
{
EnterpriseApplication application = _localEApp.getLevel();
if (application == null) {
application = new EnterpriseApplication(null, null, name);
}
return application;
}
public static EnterpriseApplication getCurrent()
{
return _localEApp.get();
}
/**
* Sets the name.
*/
public void setName(String name)
{
_name = name;
_loader.setId("eapp:" + name + "");
}
/**
* Gets the name.
*/
public String getName()
{
return _name;
}
/**
* Sets the library directory.
*/
public void setLibraryDirectory(String libraryDirectory)
{
_libraryDirectory = libraryDirectory;
}
/**
* Gets the library directory.
*/
public String getLibraryDirectory()
{
return _libraryDirectory;
}
/**
* Sets the ejb-server jndi name.
*/
public void setEjbServerJndiName(String name)
{
}
/**
* Sets the root directory.
*/
public Path getRootDirectory()
{
return _controller.getRootDirectory();
}
/**
* Returns the class loader.
*/
public EnvironmentClassLoader getClassLoader()
{
return _loader;
}
/**
* Sets the class loader.
*/
public void setEnvironmentClassLoader(EnvironmentClassLoader loader)
{
_loader = loader;
}
/**
* Sets the path to the .ear file
*/
public void setEarPath(Path earPath)
{
}
/**
* Sets the path to the expanded webapps
*/
public void setWebapps(Path webappsPath)
{
_webappsPath = webappsPath;
}
/**
* Sets the prefix URL for web applications.
*/
public void setPrefix(String prefix)
{
}
/**
* Sets the id
*/
public void setId(String id)
{
}
/**
* Sets the application version.
*/
public void setVersion(String version)
{
_version = version;
}
/**
* Sets the schema location
*/
public void setSchemaLocation(String schema)
{
}
/**
* Sets the display name.
*/
public void setDisplayName(String name)
{
}
/**
* Sets the description.
*/
public void setDescription(String description)
{
}
/**
* Sets the icon.
*/
public void setIcon(Icon icon)
{
}
/**
* Adds a module.
*/
public Module createModule()
{
return new Module();
}
/**
* Finds a web module based on the web-uri
*/
WebModule findWebModule(String webUri)
{
for (int i = 0; i < _webConfigList.size(); i++) {
WebModule web = _webConfigList.get(i);
if (webUri.equals(web.getWebURI()))
return web;
}
return null;
}
/**
* Finds a web module based on the web-uri
*/
void addWebModule(WebModule webModule)
{
_webConfigList.add(webModule);
}
/**
* Adds a security role.
*/
public void addSecurityRole(SecurityRole role)
{
}
/**
* Returns true if it's modified.
*/
public boolean isModified()
{
return _loader.isModified();
}
/**
* Returns true if it's modified.
*/
public boolean isModifiedNow()
{
return _loader.isModifiedNow();
}
/**
* Log the reason for modification.
*/
public boolean logModified(Logger log)
{
return _loader.logModified(log);
}
/**
* Returns true if it's modified.
*/
public boolean isDeployError()
{
return _configException != null;
}
/**
* Returns true if the application is idle.
*/
public boolean isDeployIdle()
{
return false;
}
/**
* Sets the config exception.
*/
@Override
public void setConfigException(Throwable e)
{
_configException = e;
for (WebAppController controller : _webApps) {
controller.setConfigException(e);
}
}
/**
* Gets the config exception.
*/
public Throwable getConfigException()
{
return _configException;
}
/**
* Initialization before configuration
*/
public void preConfigInit()
{
}
/**
* Configures the application.
*/
@PostConstruct
public void init()
throws Exception
{
if (! _lifecycle.toInit())
return;
try {
Path rootDir = getRootDirectory();
Vfs.setPwd(rootDir, _loader);
_loader.addJarManifestClassPath(rootDir);
// server/13bb vs TCK
if ("1.4".equals(_version)) {
// XXX: tck ejb30/persistence/basic needs to add the lib/*.jar
// to find the META-INF/persistence.xml
fillDefaultLib();
}
else {
fillDefaultModules();
}
EjbManager ejbManager = EjbManager.create();
if (_ejbPaths.size() != 0) {
for (Path path : _ejbPaths) {
// ejbManager.addRoot(path);
_loader.addJar(path);
}
_loader.validate();
// XXX:??
/*
*/
// starts with the environment
// ejbServer.start();
}
// ioc/0p63
Path ejbJar = rootDir.lookup("META-INF/ejb-jar.xml");
if (ejbJar.canRead()) {
ejbManager.configureRootPath(rootDir);
}
_loader.start();
// updates the invocation caches
if (_webAppContainer != null)
_webAppContainer.clearCache();
} catch (Exception e) {
_configException = ConfigException.create(e);
log.log(Level.WARNING, e.toString(), e);
_loader.setConfigException(_configException);
}
fillErrors();
}
private void fillDefaultModules()
{
try {
fillDefaultLib();
Path rootDir = getRootDirectory();
for (String file : rootDir.list()) {
if (file.endsWith(".jar")) {
Path path = rootDir.lookup(file);
Path jar = JarPath.create(path);
try {
if (jar.lookup("META-INF/application-client.xml").canRead()) {
// app-client jar
}
else if (jar.lookup("META-INF/ejb-jar.xml").canRead()) {
addEjbPath(path);
_loader.addJar(path);
_loader.addJarManifestClassPath(path);
}
else {
addEjbPath(path);
_loader.addJar(path);
}
}
catch (java.util.zip.ZipException e) {
// XXX: jpa tck, error in opening zip file
// canRead() is throwing an exception when
// META-INF/application-client.xml does not exist?
log.log(Level.WARNING, e.toString(), e);
}
}
else if (file.endsWith(".war")) {
Module module = createModule();
WebModule web = new WebModule();
web.setWebURI(file);
module.addWeb(web);
}
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw ConfigException.create(e);
}
}
private void fillDefaultLib()
throws Exception
{
String libDir = "lib";
// ejb/0fa0
if (_libraryDirectory != null)
libDir = _libraryDirectory;
Path rootDir = getRootDirectory();
if (rootDir.lookup(libDir).isDirectory()) {
Path lib = rootDir.lookup(libDir);
for (String file : lib.list()) {
if (file.endsWith(".jar")) {
_loader.addJar(lib.lookup(file));
}
}
}
}
/**
* Configures the application.
*/
@Override
public void start()
{
if (! _lifecycle.toStarting())
return;
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(getClassLoader());
getClassLoader().start();
for (int i = 0; i < _webConfigList.size(); i++) {
WebModule web = _webConfigList.get(i);
initWeb(web);
}
if (_webAppContainer != null) {
for (WebAppController webApp : _webApps) {
// server/13bb
//_webAppContainer.getWebAppGenerator().updateNoStart(webApp.getContextPath());
// _webAppContainer.getWebAppGenerator().update(
_webAppContainer.getWebAppGenerator().update(webApp.getContextPath());
}
}
if (_configException != null) {
for (WebAppController controller : _webApps) {
controller.setConfigException(_configException);
}
}
} finally {
if (_configException != null)
_lifecycle.toError();
else
_lifecycle.toActive();
thread.setContextClassLoader(oldLoader);
if (_configException != null)
throw ConfigException.create(_configException);
}
}
private void fillErrors()
{
if (_configException != null) {
for (WebAppController controller : _webApps) {
controller.setConfigException(_configException);
}
}
}
void initWeb(WebModule web)
{
String webUri = web.getWebURI();
String contextUrl = web.getContextRoot();
Path path = getRootDirectory().lookup(webUri);
Path archivePath = null;
if (contextUrl == null)
contextUrl = webUri;
WebAppController controller = null;
if (webUri.endsWith(".war")) {
// server/2a16
String name = webUri.substring(0, webUri.length() - 4);
int p = name.lastIndexOf('/');
if (p > 0)
name = name.substring(p + 1);
// XXX:
if (contextUrl.equals(""))
contextUrl = "/" + name;
if (contextUrl.endsWith(".war"))
contextUrl = contextUrl.substring(0, contextUrl.length() - 4);
Path expandPath = _webappsPath;
try {
expandPath.mkdirs();
} catch (Exception e) {
log.log(Level.WARNING, e.toString(), e);
}
archivePath = path;
path = expandPath.lookup(name);
} else {
// server/2a15
if (contextUrl.equals("")) {
String name = webUri;
int p = name.lastIndexOf('/');
if (p > 0)
name = name.substring(p + 1);
contextUrl = "/" + name;
}
// server/2a17
if (contextUrl.endsWith(".war"))
contextUrl = contextUrl.substring(0, contextUrl.length() - 4);
}
if (! contextUrl.startsWith("/"))
contextUrl = "/" + contextUrl;
controller = findWebAppEntry(contextUrl);
String id;
if (contextUrl.equals("/"))
id = "production/webapp/default/ROOT";
else
id = "production/webapp/default" + contextUrl;
if (controller == null) {
if (contextUrl.equals("/"))
contextUrl = "";
controller = new WebAppController(id,
path,
_webAppContainer,
contextUrl);
_webApps.add(controller);
}
if (archivePath != null)
controller.setArchivePath(archivePath);
controller.setDynamicDeploy(true);
if (_configException != null)
controller.setConfigException(_configException);
for (WebAppConfig config : web.getWebAppList())
controller.addConfigDefault(config);
}
/**
* Returns any matching web-app.
*/
public WebAppController findWebAppEntry(String name)
{
for (int i = 0; i < _webApps.size(); i++) {
WebAppController controller = _webApps.get(i);
if (controller.isNameMatch(name))
return controller;
}
return null;
}
/**
* Returns the webapps for the enterprise-application.
*/
public ArrayList<WebAppController> getApplications()
{
return _webApps;
}
/**
* Stops the e-application.
*/
public void stop()
{
if (! _lifecycle.toStopping())
return;
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(_loader);
//log.info(this + " stopping");
_loader.stop();
//log.fine(this + " stopped");
} finally {
_lifecycle.toStop();
thread.setContextClassLoader(oldLoader);
}
}
/**
* destroys the e-application.
*/
public void destroy()
{
stop();
if (! _lifecycle.toDestroy())
return;
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(getClassLoader());
log.fine(this + " destroying");
ArrayList<WebAppController> webApps = _webApps;
_webApps = null;
if (webApps != null && _webAppContainer != null) {
for (WebAppController webApp : webApps) {
_webAppContainer.getWebAppGenerator().update(webApp.getContextPath());
}
}
} finally {
thread.setContextClassLoader(oldLoader);
_loader.destroy();
log.fine(this + " destroyed");
}
}
//
// JMX utilities
//
public String getClientRefs()
{
throw new UnsupportedOperationException(getClass().getName());
/*
EjbContainer ejbContainer = EjbContainer.create();
return ejbContainer.getClientRemoteConfig();
*/
}
public String toString()
{
return "EnterpriseApplication[" + getName() + "]";
}
public class Module {
/**
* Sets the module id.
*/
public void setId(String id)
{
}
/**
* Creates a new web module.
*/
public void addWeb(WebModule web)
throws Exception
{
String webUri = web.getWebURI();
WebModule oldWeb = findWebModule(webUri);
if (oldWeb != null) {
String contextUrl = web.getContextRoot();
if (contextUrl != null && ! "".equals(contextUrl))
oldWeb.setContextRoot(contextUrl);
oldWeb.addWebAppList(web.getWebAppList());
}
else
addWebModule(web);
}
/**
* Adds a new ejb module.
*/
public void addEjb(Path path)
throws Exception
{
addEjbPath(path);
_loader.addJar(path);
// ejb/0853
_loader.addJarManifestClassPath(path);
}
/**
* Adds a new java module.
*/
public void addJava(Path path)
throws ConfigException
{
if (! path.canRead())
throw new ConfigException(L.l("<java> module {0} must be a valid path.",
path));
}
/**
* Adds a new connector
*/
public void addConnector(String path)
{
}
/**
* Adds a new alt-dd module.
*/
public void addAltDD(String path)
{
}
}
private void addEjbPath(Path ejbPath)
{
if (_ejbPaths.contains(ejbPath))
return;
_ejbPaths.add(ejbPath);
EjbManager ejbContainer = EjbManager.create();
//ejbContainer.addRoot(ejbPath);
}
}