| /******************************************************************************* |
| * 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); |
| } |
| } |
| } |
| |
| } |