/*
* Copyright 2005-2007 WSO2, Inc. (http://wso2.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wso2.carbon.server;
import org.apache.catalina.Engine;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.realm.MemoryRealm;
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.Constants;
import org.apache.catalina.valves.ValveBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonException;
import org.wso2.carbon.atomikos.AtomikosLifecycleListener;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.context.RegistryType;
import org.wso2.carbon.registry.api.RegistryService;
import org.wso2.carbon.server.transports.TransportManager;
import org.wso2.carbon.tomcat.BetterTomcat;
import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.user.api.UserRealmService;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.FileManipulator;
import org.wso2.carbon.utils.multitenancy.CarbonContextHolder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementPermission;
import java.util.Random;
/**
* Represents a Tomcat Server instance
*
* @see TomcatGenericWebappsDeployer
* @see TomcatCarbonWebappDeployer
*/
public class TomcatServer {
private static Log log = LogFactory.getLog(TomcatServer.class);
private static final BetterTomcat tomcat = TomcatUtil.getTomcat();
private boolean isWebappManagementEnabled;
private CarbonTomcatRealm realm;
private Random random = new Random();
private TenantManager tenantManager;
public TomcatServer() {
}
public void start() throws Exception {
checkPermission();
String carbonHome = System.getProperty("carbon.home");
String catalinaHome = new File(carbonHome).getAbsolutePath() + File.separator + "lib" +
File.separator + "tomcat";
/*File appBaseDir = new File(host.getAppBase() + webContextPrefix);
if (!appBaseDir.exists() && !appBaseDir.mkdirs()) {
throw new CarbonException("Could not create application base directory " +
appBaseDir.getAbsolutePath());
}*/
tomcat.setBaseDir(catalinaHome);
String libDir = carbonHome + File.separator + "lib";
// Create an engine
initWebappManagement();
initTxManager();
TransportManager.init();
String defaultHostName = "defaulthost";
// Clear the temp dir
File tempDir =
new File(System.getProperty("java.io.tmpdir") + File.separator + defaultHostName);
FileManipulator.deleteDir(tempDir);
// Create a default virtual host
if (System.getProperty("instances.value") != null) {
defaultHostName = "defaultHost" + random.nextInt();
}
createDefaultHost(defaultHostName);
tomcat.enableNaming();
// Deploy the Carbon webapp
File carbonWebappDir = new File(libDir + File.separator + "core");
if (carbonWebappDir.exists()) {
new TomcatCarbonWebappDeployer(carbonWebappDir.getAbsolutePath()).deploy();
}
// Start the embedded server
tomcat.start();
}
private void initTxManager() throws CarbonException {
Engine engine = tomcat.getTomcat().getEngine();
engine.addLifecycleListener(new AtomikosLifecycleListener());
}
private void initWebappManagement() throws Exception {
if (isWebappManagementEnabled = isWebappMgtEnabled()) {
String tomcatRealm =
ServerConfiguration.getInstance().getFirstProperty("Security.TomcatRealm");
if(tomcatRealm == null){
log.info("TomcatRealm not defined in carbon.xml. Using default: memory");
tomcatRealm = "UserManager";
}
if (tomcatRealm.equalsIgnoreCase("memory")) {
log.info("Using memory based TomcatRealm");
MemoryRealm memoryRealm = new MemoryRealm();
String tomcatUsersXml = CarbonUtils.getCarbonConfigDirPath() + File.separator +
"tomcat-users.xml";
if (new File(tomcatUsersXml).exists()) {
memoryRealm.setPathname(tomcatUsersXml);
tomcat.setDefaultRealm(memoryRealm);
} else {
String msg = "TomcatRealm has been set to memory in carbon.xml, but " +
tomcatUsersXml + " file cannot be found";
log.fatal(msg);
throw new Exception(msg);
}
} else if (tomcatRealm.equalsIgnoreCase("UserManager")) {
log.info("Using UserManager based TomcatRealm");
try {
realm = new CarbonTomcatRealm();
tomcat.setDefaultRealm(realm);
} catch (Exception e) {
log.error("Error trying to create the realm", e);
throw new Exception(e.getMessage(), e);
}
} else {
throw new Exception("Unknown TomcatRealm " + tomcatRealm + " " +
"has been specified in carbon.xml file");
}
}
}
/**
* Checks whether the webapp.mgt Carbon components are available
*
* @return true - if webapp.mgt components are available, false - otherwise
*/
private boolean isWebappMgtEnabled() {
File osgiPluginsDir =
new File(CarbonUtils.getCarbonHome() + File.separator + "repository" +
File.separator + "components" + File.separator + "plugins");
String[] plugins = osgiPluginsDir.list();
for (String plugin : plugins) {
if (plugin.indexOf("org.wso2.carbon.webapp.") != -1) {
return true;
}
}
return false;
}
private void checkPermission() {
SecurityManager secMan = System.getSecurityManager();
if (secMan != null) {
secMan.checkPermission(new ManagementPermission("control"));
}
}
/**
* Create a new Virtual host & add it to the Tomcat Engine
*
* @param defaultHostName Name of the Virtual host
*/
private void createDefaultHost(String defaultHostName) {
checkPermission();
File appBaseDir =
new File(System.getProperty("java.io.tmpdir") + File.separator + defaultHostName);
if (!appBaseDir.exists() && !appBaseDir.mkdirs()) {
throw new RuntimeException("Could not create application base dir " +
appBaseDir.getAbsolutePath());
}
StandardHost vhost = (StandardHost) tomcat.getHost();
tomcat.setDefaultHost(defaultHostName);
vhost.setAppBase(appBaseDir.getAbsolutePath());
vhost.setName(defaultHostName);
if (System.getProperty("disableHttpLog", "false").equals("false")) {
AccessLogValve accessLogValve = new AccessLogValve();
String carbonHome = System.getProperty("carbon.home");
accessLogValve.setDirectory(carbonHome + File.separator + "repository" + File.separator +
"logs");
accessLogValve.setRotatable(true);
accessLogValve.setPrefix("http_access_");
accessLogValve.setSuffix(".log");
accessLogValve.setPattern(Constants.AccessLog.COMBINED_ALIAS);
// accessLogValve.setPattern("common");
// accessLogValve.setPattern("%h %l %u %t "%r" %s %b");
accessLogValve.setResolveHosts(true);
accessLogValve.setEnabled(true);
vhost.addValve(accessLogValve);
}
vhost.addValve(new ValveBase() {
@Override
public void invoke(Request request, Response response)
throws IOException,
ServletException {
try {
/**
* To enable SaaS for webapp, add the following to the web.xml file
*
* <context-param>
* <param-name>carbon.enable.saas</param-name>
* <param-value>true</param-value>
* </context-param>
*/
String enableSaaSParam =
request.getContext().findParameter(WebApplication.ENABLE_SAAS);
if(enableSaaSParam != null && Boolean.valueOf(enableSaaSParam)){
// Set the SaaS enabled ThreadLocal variable
if(realm != null){
realm.enableSaaS();
}
}
initCarbonContext(request);
TomcatValveContainer.invokeValves(request, response);
if (response.getStatus() != Response.SC_MOVED_TEMPORARILY) {
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
getNext().invoke(request, response);
}
} catch (Exception e) {
log.error("Could not handle request: " + request.getRequestURI(), e);
} finally {
// This will destroy the carbon context holder on the current thread after
// invoking
// subsequent valves.
CarbonContextHolder.destroyCurrentCarbonContextHolder();
}
}
});
vhost.setDeployOnStartup(true);
vhost.setAutoDeploy(true);
}
public void initCarbonContext(Request request) throws Exception {
if (!isWebappManagementEnabled) {
return;
}
String tenantDomain = getTenantDomain(request);
CarbonContextHolder carbonContextHolder =
CarbonContextHolder.getThreadLocalCarbonContextHolder();
carbonContextHolder.setTenantDomain(tenantDomain);
UserRealmService userRealmService = OSGiEnvironmentDataHolder.getUserRealmService();
if (userRealmService != null) {
if(tenantManager == null) {
tenantManager = userRealmService.getTenantManager();
}
int tenantId = tenantManager.getTenantId(tenantDomain);
carbonContextHolder.setTenantId(tenantId);
carbonContextHolder.setProperty(CarbonContextHolder.USER_REALM,
userRealmService.getTenantUserRealm(tenantId));
RegistryService registryService = OSGiEnvironmentDataHolder.getRegistryService();
carbonContextHolder.setProperty(CarbonContextHolder.CONFIG_SYSTEM_REGISTRY_INSTANCE,
new GhostRegistry(registryService, tenantId,
RegistryType.SYSTEM_CONFIGURATION));
carbonContextHolder.setProperty(CarbonContextHolder.GOVERNANCE_SYSTEM_REGISTRY_INSTANCE,
new GhostRegistry(registryService, tenantId,
RegistryType.SYSTEM_GOVERNANCE));
}
}
private String getTenantDomain(HttpServletRequest request) {
String requestURI = request.getRequestURI();
if (requestURI.indexOf("/t/") == -1) { // Super tenant?
return null;
}
String temp = requestURI.substring(requestURI.indexOf("/t/") + 3);
if (temp.indexOf("/") != -1) {
temp = temp.substring(0, temp.indexOf("/"));
}
return temp;
}
/**
* Stop the Tomcat server.
*
* @throws Exception If an error occurs while stopping Tomcat
*/
public void stop() throws Exception {
checkPermission();
tomcat.stop();
}
public void addValveToDefaultHost() {
}
}