| /** |
| * 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.apache.oozie.server; |
| |
| import com.google.inject.Guice; |
| import com.google.inject.Inject; |
| import com.google.inject.Injector; |
| import com.google.inject.ProvisionException; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.oozie.server.guice.OozieGuiceModule; |
| import org.apache.oozie.service.ConfigurationService; |
| import org.apache.oozie.service.ServiceException; |
| import org.apache.oozie.service.Services; |
| import org.apache.oozie.util.ConfigUtils; |
| import org.eclipse.jetty.rewrite.handler.RewriteHandler; |
| import org.eclipse.jetty.security.ConstraintSecurityHandler; |
| import org.eclipse.jetty.server.Connector; |
| import org.eclipse.jetty.server.HttpConfiguration; |
| import org.eclipse.jetty.server.HttpConnectionFactory; |
| import org.eclipse.jetty.server.Server; |
| import org.eclipse.jetty.server.ServerConnector; |
| import org.eclipse.jetty.server.handler.HandlerCollection; |
| import org.eclipse.jetty.servlet.ErrorPageErrorHandler; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.servlet.http.HttpServletResponse; |
| import java.io.IOException; |
| import java.net.URISyntaxException; |
| import java.util.Objects; |
| |
| /** |
| * Class to start Oozie inside an embedded Jetty server. |
| */ |
| public class EmbeddedOozieServer { |
| private static final Logger LOG = LoggerFactory.getLogger(EmbeddedOozieServer.class); |
| protected static final String OOZIE_HTTPS_TRUSTSTORE_FILE = "oozie.https.truststore.file"; |
| protected static final String OOZIE_HTTPS_TRUSTSTORE_TYPE = "oozie.https.truststore.type"; |
| protected static final String OOZIE_HTTPS_TRUSTSTORE_PASS = "oozie.https.truststore.pass"; |
| protected static final String TRUSTSTORE_PATH_SYSTEM_PROPERTY = "javax.net.ssl.trustStore"; |
| protected static final String TRUSTSTORE_TYPE_SYSTEM_PROPERTY = "javax.net.ssl.trustStoreType"; |
| protected static final String TRUSTSTORE_PASS_SYSTEM_PROPERTY = "javax.net.ssl.trustStorePassword"; |
| private static String contextPath; |
| protected Server server; |
| private int httpPort; |
| private int httpsPort; |
| private final WebAppContext servletContextHandler; |
| private final ServletMapper oozieServletMapper; |
| private final FilterMapper oozieFilterMapper; |
| private JspHandler jspHandler; |
| private Services serviceController; |
| private SSLServerConnectorFactory sslServerConnectorFactory; |
| private Configuration conf; |
| private final RewriteHandler oozieRewriteHandler; |
| private final ConstraintSecurityHandler constraintSecurityHandler; |
| |
| /** |
| * Construct Oozie server |
| * @param server jetty server to be embedded |
| * @param jspHandler handler responsible for setting webapp context for JSP |
| * @param serviceController controller for Oozie services; must be already initialized |
| * @param sslServerConnectorFactory factory to create server connector configured for SSL |
| * @param oozieRewriteHandler URL rewriter |
| * @param servletContextHandler main web application context handler |
| * @param oozieServletMapper maps servlets to URLs |
| * @param oozieFilterMapper maps filters |
| * @param constraintSecurityHandler constraint security handler |
| */ |
| @Inject |
| public EmbeddedOozieServer(final Server server, |
| final JspHandler jspHandler, |
| final Services serviceController, |
| final SSLServerConnectorFactory sslServerConnectorFactory, |
| final RewriteHandler oozieRewriteHandler, |
| final WebAppContext servletContextHandler, |
| final ServletMapper oozieServletMapper, |
| final FilterMapper oozieFilterMapper, |
| final ConstraintSecurityHandler constraintSecurityHandler) |
| { |
| this.constraintSecurityHandler = constraintSecurityHandler; |
| this.serviceController = Objects.requireNonNull(serviceController, "serviceController is null"); |
| this.jspHandler = Objects.requireNonNull(jspHandler, "jspHandler is null"); |
| this.sslServerConnectorFactory = Objects.requireNonNull(sslServerConnectorFactory, |
| "sslServerConnectorFactory is null"); |
| this.server = Objects.requireNonNull(server, "server is null"); |
| this.oozieRewriteHandler = Objects.requireNonNull(oozieRewriteHandler, "rewriter is null"); |
| this.servletContextHandler = Objects.requireNonNull(servletContextHandler, "servletContextHandler is null"); |
| this.oozieServletMapper = Objects.requireNonNull(oozieServletMapper, "oozieServletMapper is null"); |
| this.oozieFilterMapper = Objects.requireNonNull(oozieFilterMapper, "oozieFilterMapper is null"); |
| } |
| |
| /** |
| * Set up the Oozie server by configuring jetty server settings and starts Oozie services |
| * |
| * @throws URISyntaxException if the server URI is not well formatted |
| * @throws IOException in case of IO issues |
| * @throws ServiceException if the server could not start |
| */ |
| public void setup() throws URISyntaxException, IOException, ServiceException { |
| conf = serviceController.get(ConfigurationService.class).getConf(); |
| setContextPath(conf); |
| httpPort = getConfigPort(ConfigUtils.OOZIE_HTTP_PORT); |
| |
| HttpConfiguration httpConfiguration = new HttpConfigurationWrapper(conf).getDefaultHttpConfiguration(); |
| |
| ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration)); |
| connector.setPort(httpPort); |
| connector.setHost(conf.get(ConfigUtils.OOZIE_HTTP_HOSTNAME)); |
| |
| HandlerCollection handlerCollection = new HandlerCollection(); |
| setTrustStore(); |
| setTrustStoreType(); |
| setTrustStorePassword(); |
| |
| if (isSecured()) { |
| httpsPort = getConfigPort(ConfigUtils.OOZIE_HTTPS_PORT); |
| ServerConnector sslConnector = sslServerConnectorFactory.createSecureServerConnector(httpsPort, conf, server); |
| server.setConnectors(new Connector[]{connector, sslConnector}); |
| constraintSecurityHandler.setHandler(servletContextHandler); |
| handlerCollection.addHandler(constraintSecurityHandler); |
| } |
| else { |
| server.setConnectors(new Connector[]{connector}); |
| } |
| |
| servletContextHandler.setContextPath(contextPath); |
| oozieServletMapper.mapOozieServlets(); |
| oozieFilterMapper.addFilters(); |
| |
| servletContextHandler.setParentLoaderPriority(true); |
| jspHandler.setupWebAppContext(servletContextHandler); |
| |
| addErrorHandler(); |
| |
| handlerCollection.addHandler(servletContextHandler); |
| handlerCollection.addHandler(oozieRewriteHandler); |
| server.setHandler(handlerCollection); |
| } |
| |
| /** |
| * set the truststore path from the config file, if is not set by the user |
| */ |
| private void setTrustStore() { |
| if (System.getProperty(TRUSTSTORE_PATH_SYSTEM_PROPERTY) == null) { |
| final String trustStorePath = conf.get(OOZIE_HTTPS_TRUSTSTORE_FILE); |
| if (trustStorePath != null) { |
| LOG.info("Setting javax.net.ssl.trustStore from config file"); |
| System.setProperty(TRUSTSTORE_PATH_SYSTEM_PROPERTY, trustStorePath); |
| } |
| } else { |
| LOG.info("javax.net.ssl.trustStore is already set. The value from config file will be ignored"); |
| } |
| } |
| |
| /** |
| * set the truststore type from the config file, if is not set by the user |
| */ |
| private void setTrustStoreType() { |
| if (System.getProperty(TRUSTSTORE_TYPE_SYSTEM_PROPERTY) == null) { |
| final String trustStoreType = conf.get(OOZIE_HTTPS_TRUSTSTORE_TYPE); |
| if (trustStoreType != null) { |
| LOG.info("Setting javax.net.ssl.trustStoreType from config file"); |
| System.setProperty(TRUSTSTORE_TYPE_SYSTEM_PROPERTY, trustStoreType); |
| } |
| } else { |
| LOG.info("javax.net.ssl.trustStoreType is already set. The value from config file will be ignored"); |
| } |
| } |
| |
| /** |
| * set the truststore password from the config file, if is not set by the user |
| */ |
| private void setTrustStorePassword() { |
| if (System.getProperty(TRUSTSTORE_PASS_SYSTEM_PROPERTY) == null) { |
| final String trustStorePassword = conf.get(OOZIE_HTTPS_TRUSTSTORE_PASS); |
| if (trustStorePassword != null) { |
| LOG.info("Setting javax.net.ssl.trustStorePassword from config file"); |
| System.setProperty(TRUSTSTORE_PASS_SYSTEM_PROPERTY, trustStorePassword); |
| } |
| } else { |
| LOG.info("javax.net.ssl.trustStorePassword is already set. The value from config file will be ignored"); |
| } |
| } |
| |
| private void addErrorHandler() { |
| ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler(); |
| errorHandler.addErrorPage(HttpServletResponse.SC_BAD_REQUEST, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_UNAUTHORIZED, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_FORBIDDEN, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_CONFLICT, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_NOT_IMPLEMENTED, "/error"); |
| errorHandler.addErrorPage(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "/error"); |
| errorHandler.addErrorPage("java.lang.Throwable", "/error"); |
| servletContextHandler.setErrorHandler(errorHandler); |
| } |
| |
| private int getConfigPort(String confVar) { |
| String confHttpPort = conf.get(confVar); |
| int port; |
| try { |
| port = Integer.parseInt(confHttpPort); |
| } |
| catch (final NumberFormatException nfe) { |
| throw new NumberFormatException(String.format("Port number for '%s \"%s\" ('%s') is not an integer.", |
| confVar, confHttpPort, confHttpPort)); |
| } |
| return port; |
| } |
| |
| private boolean isSecured() { |
| boolean isSSLEnabled = Boolean.parseBoolean(conf.get("oozie.https.enabled")); |
| LOG.info("Server started with oozie.https.enabled = " + isSSLEnabled); |
| return isSSLEnabled; |
| } |
| |
| public static void setContextPath(Configuration oozieConfiguration) { |
| String baseUrl = oozieConfiguration.get("oozie.base.url").replaceAll("[\r\n]",""); |
| String contextPath = baseUrl.substring(baseUrl.lastIndexOf("/")); |
| LOG.info("Server started with contextPath = " + contextPath); |
| EmbeddedOozieServer.contextPath = contextPath; |
| } |
| |
| public static String getContextPath(Configuration oozieConfiguration) { |
| if (contextPath != null) { |
| return contextPath; |
| } |
| |
| setContextPath(oozieConfiguration); |
| return EmbeddedOozieServer.contextPath; |
| } |
| |
| public void start() throws Exception { |
| server.start(); |
| LOG.info("Server started."); |
| } |
| |
| public void shutdown() throws Exception { |
| LOG.info("Shutting down."); |
| if (serviceController != null) { |
| serviceController.destroy(); |
| LOG.info("Oozie services stopped."); |
| } |
| |
| if (server != null) { |
| server.stop(); |
| LOG.info("Server stopped."); |
| } |
| } |
| |
| public void join() throws InterruptedException { |
| server.join(); |
| } |
| |
| public void addShutdownHook() { |
| Runtime.getRuntime().addShutdownHook(new Thread() { |
| public void run() { |
| try { |
| shutdown(); |
| } catch (final Exception e) { |
| LOG.error("There were errors during shutdown.", e); |
| } |
| } |
| }); |
| } |
| |
| public static void main(String[] args) throws Exception { |
| final Injector guiceInjector = Guice.createInjector(new OozieGuiceModule()); |
| |
| EmbeddedOozieServer embeddedOozieServer = null; |
| try { |
| embeddedOozieServer = guiceInjector.getInstance(EmbeddedOozieServer.class); |
| } catch (final ProvisionException ex) { |
| LOG.error("Failed to get EmbeddedOozieServer", ex); |
| System.exit(1); |
| } |
| |
| embeddedOozieServer.addShutdownHook(); |
| embeddedOozieServer.setup(); |
| try { |
| embeddedOozieServer.start(); |
| } catch (final Exception e) { |
| LOG.error("Could not start EmbeddedOozieServer!", e); |
| System.exit(1); |
| } |
| embeddedOozieServer.join(); |
| } |
| } |