blob: 10ee4e14b02ff8c19e6f1eea4b7a00fd83e1a557 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.ofbiz.jetty.container;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ofbiz.base.component.ComponentConfig;
import org.ofbiz.base.container.Container;
import org.ofbiz.base.container.ContainerConfig;
import org.ofbiz.base.container.ContainerException;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.SSLUtil;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.base.util.UtilValidate;
import org.eclipse.jetty.ajp.Ajp13SocketConnector;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.bio.SocketConnector;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.server.ssl.SslConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* JettyContainer - Container implementation for Jetty
*/
public class JettyContainer implements Container {
public static final String module = JettyContainer.class.getName();
private Map<String, Server> servers = new HashMap<String, Server>();
/**
* @see org.ofbiz.base.container.Container#init(java.lang.String[], java.lang.String)
*/
public void init(String[] args, String configFile) throws ContainerException {
// configure JSSE properties
SSLUtil.loadJsseProperties();
// session store directory
File sessionStoreDirectory = new File(UtilProperties.getPropertyValue("jetty", "session.store.directory", "runtime/jetty/sessions"));
if (!sessionStoreDirectory.exists()) {
if (!sessionStoreDirectory.mkdirs()) {
throw new ContainerException("error creating session store directory: " + sessionStoreDirectory.getAbsolutePath());
}
}
// get the jetty container config
ContainerConfig.Container jettyContainerConfig = ContainerConfig.getContainer("jetty-container", configFile);
// create the servers
for (ContainerConfig.Container.Property serverConfig : jettyContainerConfig.getPropertiesWithValue("server")) {
servers.put(serverConfig.name, createServer(serverConfig));
}
// create the webapp contexts
for (ComponentConfig componentConfig : ComponentConfig.getAllComponents()) {
for (ComponentConfig.WebappInfo webappInfo : componentConfig.getWebappInfos()) {
Server server = servers.get(webappInfo.server);
if (server == null) {
Debug.logError("Server with name [" + webappInfo.server + "] not found; not mounting [" + webappInfo.name + "]", module);
} else {
// set the root location (make sure we set the paths correctly)
String location = componentConfig.getRootLocation() + webappInfo.location;
location = location.replace('\\', '/');
if (location.endsWith("/")) {
location = location.substring(0, location.lastIndexOf("/"));
}
String mountPoint = webappInfo.mountPoint;
if (mountPoint.endsWith("/*")) {
mountPoint = mountPoint.substring(0, mountPoint.lastIndexOf("/"));
}
WebAppContext context = new WebAppContext(location, mountPoint);
context.setAttribute("_serverId", webappInfo.server);
context.setLogUrlOnStart(true);
// set the session manager
HashSessionManager sm = new HashSessionManager();
sm.setStoreDirectory(sessionStoreDirectory);
sm.setLazyLoad(true);
context.setSessionHandler(new SessionHandler(sm));
// set the virtual hosts
List<String> virtualHosts = webappInfo.getVirtualHosts();
if (UtilValidate.isNotEmpty(virtualHosts)) {
context.setVirtualHosts(virtualHosts.toArray(new String[virtualHosts.size()]));
}
// set the init parameters
Map<String, String> initParameters = webappInfo.getInitParameters();
if (UtilValidate.isNotEmpty(initParameters)) {
for (Map.Entry<String, String> e : initParameters.entrySet()) {
context.setInitParameter(e.getKey(), e.getValue());
}
}
((HandlerCollection) server.getHandler()).addHandler(context);
}
}
}
}
private Server createServer(ContainerConfig.Container.Property serverConfig) {
Server server = new Server();
server.setHandler(new HandlerCollection());
// send server version?
if (UtilValidate.isNotEmpty(serverConfig.getProperty("send-server-version"))) {
String sendServerVersionPropertyValue = serverConfig.getProperty("send-server-version").value;
try {
server.setSendServerVersion(Boolean.parseBoolean(sendServerVersionPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for send-server-version: " + sendServerVersionPropertyValue, module);
}
}
// thread pool
server.setThreadPool(createThreadPool(serverConfig));
// connectors
for (ContainerConfig.Container.Property connectorConfig : serverConfig.getPropertiesWithValue("connector")) {
Connector connector = null;
String connectorType = connectorConfig.getProperty("type").value;
if ("http".equals(connectorType)) {
connector = new SocketConnector();
} else if ("https".equals(connectorType)) {
connector = new SslSocketConnector();
} else if ("nio-http".equals(connectorType)) {
connector = new SelectChannelConnector();
} else if ("nio-https".equals(connectorType)) {
connector = new SslSelectChannelConnector();
} else if ("ajp13".equals(connectorType)) {
connector = new Ajp13SocketConnector();
}
if (connector != null) {
setConnectorOptions(connector, connectorConfig);
server.addConnector(connector);
}
}
// request logs
for (ContainerConfig.Container.Property props : serverConfig.getPropertiesWithValue("request-log")) {
NCSARequestLog requestLog = new NCSARequestLog();
if (UtilValidate.isNotEmpty(props.getProperty("filename"))) {
requestLog.setFilename(props.getProperty("filename").value);
}
if (UtilValidate.isNotEmpty(props.getProperty("append"))) {
requestLog.setAppend("true".equalsIgnoreCase(props.getProperty("append").value));
}
if (UtilValidate.isNotEmpty(props.getProperty("extended"))) {
requestLog.setExtended("true".equalsIgnoreCase(props.getProperty("extended").value));
}
if (UtilValidate.isNotEmpty(props.getProperty("log-dispatch"))) {
requestLog.setLogDispatch("true".equalsIgnoreCase(props.getProperty("log-dispatch").value));
}
if (UtilValidate.isNotEmpty(props.getProperty("log-latency"))) {
requestLog.setLogLatency("true".equalsIgnoreCase(props.getProperty("log-latency").value));
}
if (UtilValidate.isNotEmpty(props.getProperty("log-server"))) {
requestLog.setLogServer("true".equalsIgnoreCase(props.getProperty("log-server").value));
}
if (UtilValidate.isNotEmpty(props.getProperty("prefer-proxied-for-address"))) {
requestLog.setPreferProxiedForAddress("true".equalsIgnoreCase(props.getProperty("prefer-proxied-for-address").value));
}
if (UtilValidate.isNotEmpty(props.getProperty("timezone"))) {
requestLog.setLogTimeZone(props.getProperty("timezone").value);
}
if (UtilValidate.isNotEmpty(props.getProperty("date-format"))) {
requestLog.setLogDateFormat(props.getProperty("date-format").value);
}
if (UtilValidate.isNotEmpty(props.getProperty("retain-days"))) {
String retainDaysPropertyValue = props.getProperty("retain-days").value;
try {
requestLog.setRetainDays(Integer.parseInt(retainDaysPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for retain-days: " + retainDaysPropertyValue, module);
}
}
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(requestLog);
((HandlerCollection) server.getHandler()).addHandler(requestLogHandler);
}
return server;
}
private ThreadPool createThreadPool(ContainerConfig.Container.Property serverConfig) {
QueuedThreadPool threadPool = new QueuedThreadPool();
if (UtilValidate.isNotEmpty(serverConfig.getProperty("min-threads"))) {
String minThreadsPropertyValue = serverConfig.getProperty("min-threads").value;
try {
threadPool.setMinThreads(Integer.parseInt(minThreadsPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for min-threads: " + minThreadsPropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(serverConfig.getProperty("max-threads"))) {
String maxThreadsPropertyValue = serverConfig.getProperty("max-threads").value;
try {
threadPool.setMaxThreads(Integer.parseInt(maxThreadsPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for max-threads: " + maxThreadsPropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(serverConfig.getProperty("max-idle-time-ms"))) {
String maxIdleTimeMsPropertyValue = serverConfig.getProperty("max-idle-time-ms").value;
try {
threadPool.setMaxIdleTimeMs(Integer.parseInt(maxIdleTimeMsPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for max-idle-time-ms: " + maxIdleTimeMsPropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(serverConfig.getProperty("max-stop-time-ms"))) {
String maxStopTimeMsPropertyValue = serverConfig.getProperty("max-stop-time-ms").value;
try {
threadPool.setMaxStopTimeMs(Integer.parseInt(maxStopTimeMsPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for max-stop-time-ms: " + maxStopTimeMsPropertyValue, module);
}
}
return threadPool;
}
private void setConnectorOptions(Connector connector, ContainerConfig.Container.Property connectorConfig) {
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("host"))) {
connector.setHost(connectorConfig.getProperty("host").value);
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("port"))) {
String portPropertyValue = connectorConfig.getProperty("port").value;
try {
connector.setPort(Integer.parseInt(portPropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for port: " + portPropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("request-buffer-size"))) {
String requestBufferSizePropertyValue = connectorConfig.getProperty("request-buffer-size").value;
try {
connector.setRequestBufferSize(Integer.parseInt(requestBufferSizePropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for request-buffer-size: " + requestBufferSizePropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("request-header-size"))) {
String requestHeaderSizePropertyValue = connectorConfig.getProperty("request-header-size").value;
try {
connector.setRequestHeaderSize(Integer.parseInt(requestHeaderSizePropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for request-header-size: " + requestHeaderSizePropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("response-buffer-size"))) {
String responseBufferSizePropertyValue = connectorConfig.getProperty("response-buffer-size").value;
try {
connector.setResponseBufferSize(Integer.parseInt(responseBufferSizePropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for response-buffer-size: " + responseBufferSizePropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("response-header-size"))) {
String responseHeaderSizePropertyValue = connectorConfig.getProperty("response-header-size").value;
try {
connector.setResponseHeaderSize(Integer.parseInt(responseHeaderSizePropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for response-header-size: " + responseHeaderSizePropertyValue, module);
}
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("low-resource-max-idle-time"))) {
String lowResourceMaxIdleTimePropertyValue = connectorConfig.getProperty("low-resource-max-idle-time").value;
try {
connector.setLowResourceMaxIdleTime(Integer.parseInt(lowResourceMaxIdleTimePropertyValue));
} catch (NumberFormatException e) {
Debug.logError(e, "invalid value for low-resource-max-idle-time: " + lowResourceMaxIdleTimePropertyValue, module);
}
}
// SSL options
if (connector instanceof SslConnector) {
SslContextFactory cf = ((SslConnector) connector).getSslContextFactory();
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("keystore"))) {
cf.setKeyStorePath(connectorConfig.getProperty("keystore").value);
}
if (connectorConfig.getProperty("password") != null) {
cf.setKeyStorePassword(connectorConfig.getProperty("password").value);
}
if (connectorConfig.getProperty("key-password") != null) {
cf.setKeyManagerPassword(connectorConfig.getProperty("key-password").value);
}
if (UtilValidate.isNotEmpty(connectorConfig.getProperty("client-auth"))) {
if ("need".equals(connectorConfig.getProperty("client-auth").value)) {
cf.setNeedClientAuth(true);
} else if ("want".equals(connectorConfig.getProperty("client-auth").value)) {
cf.setWantClientAuth(true);
}
}
}
}
/**
* @see org.ofbiz.base.container.Container#start()
*/
public boolean start() throws ContainerException {
for (Server server : servers.values()) {
try {
server.start();
} catch (Exception e) {
throw new ContainerException(e);
}
}
return true;
}
/**
* @see org.ofbiz.base.container.Container#stop()
*/
public void stop() throws ContainerException {
for (Server server : servers.values()) {
try {
server.stop();
} catch (Exception e) {
throw new ContainerException(e);
}
}
}
}