All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.uima.ducc.ws.server.DuccWebServer Maven / Gradle / Ivy

The newest version!
/*
 * 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.uima.ducc.ws.server;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.jasper.servlet.JspServlet;
import org.apache.tomcat.InstanceManager;
import org.apache.tomcat.SimpleInstanceManager;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.apache.uima.ducc.common.config.CommonConfiguration;
import org.apache.uima.ducc.common.internationalization.Messages;
import org.apache.uima.ducc.common.utils.DuccLogger;
import org.apache.uima.ducc.common.utils.DuccPropertiesResolver;
import org.apache.uima.ducc.common.utils.id.DuccId;
import org.apache.uima.ducc.ws.DuccPlugins;
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.jsp.JettyJspServlet;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;


public class DuccWebServer {
	private static DuccLogger logger = DuccLogger.getLogger(DuccWebServer.class);
	private static Messages messages = Messages.getInstance();
	
	private static DuccId jobid = null;
	
	
	
	 public enum ConfigValue {
		  MaxThreads("500"),
		  IdleTimeout("30000"),
		  PortHttp("42133"),
		  PortHttps("42155"),
		  WelcomePage("index.html"),
		  JavaVersion("1.8")
		  ;
		  private String defaultValue;
		  private ConfigValue(String value) {
		      defaultValue = value;
		  }
		  public int getInt(String property) {
		      String location = "getInt";
		      int retVal = Integer.parseInt(defaultValue);
		      String desc = "[default]";
		      if(property != null) {
		         property = property.trim();
		         if(property.length() > 0) {
		            retVal = Integer.parseInt(property);
		            desc = "";
		  
		         }
		      }
		      String text = name()+"="+retVal+" "+desc;
		      logger.debug(location, jobid, text.trim());
		      return retVal;
		  }
		  public String getString(String property) {
			  String location = "getString";
		      String retVal = defaultValue;
		      String desc = "[default]";
		      if(property != null) {
			         property = property.trim();
			         if(property.length() > 0) {
			            retVal = property;
			            desc = "";
			         }
		      }
		      String text = name()+"="+retVal+" "+desc;
		      logger.debug(location, jobid, text.trim());
		      return retVal;
		  }
	 }
	
	/**
	 * To support https, do the following:
	 * 
	 * 1. use 'keytool -keystore keystore -alias jetty -genkey -keyalg RSA -validity 10000' to create
	 *    keystore in ducc_web/etc directory
	 * 2. in ducc.properties set SSL port, for example:
	 * 		ducc.ws.port.ssl = 42155
	 */
	
	private String rootDir = "?";
	private Server server;
	private CommonConfiguration commonConfiguration;
	
	public DuccWebServer(CommonConfiguration commonConfiguration) {
		this.commonConfiguration = commonConfiguration;
		init();
	}
	
	/**
	 * The DUCC cluster name can be set in the ducc.properties file, for example:
	 * 		ducc.cluster.name=Watson!
	 */
	public String getClusterName() {
		return commonConfiguration.clusterName;
	}
	
	/**
	 * The DUCC class definition file can be set in the ducc.properties file, for example:
	 * 		ducc.rm.class.definitions = blade.classes
	 */
	public String getClassDefinitionFile() {
		return commonConfiguration.classDefinitionFile;
	}
	
	public int getPort() {
		String property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_port);
        int portHttp = ConfigValue.PortHttp.getInt(property);
        return portHttp;
	}
	
	public int getPortSsl() {
		String property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_port_ssl);
        int portHttps = ConfigValue.PortHttps.getInt(property);
        return portHttps;
	}
	
	public String getWelcomePage() {
		String property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_welcome_page);
        String welcomePage = ConfigValue.WelcomePage.getString(property);
        return welcomePage;
	}
	
	public String getRootDir() {
		return rootDir;
	}

	public String getKeyStorePassword() {
		return DuccWebServerHelper.getKeyStorePassword();
	}

	public String getKeyManagerPassword() {
		return DuccWebServerHelper.getKeyManagerPassword();
	}
	private static List jspInitializers() {
		JettyJasperInitializer sci = new JettyJasperInitializer();
		ContainerInitializer initializer = new ContainerInitializer(sci, null);
		List initializers = new ArrayList();
		initializers.add(initializer);
		return initializers;
	}
    private void enableEmbeddedJspSupport(ServletContextHandler servletContextHandler) throws IOException
    {
        // Establish Scratch directory for the servlet context (used by JSP compilation)
        File tempDir = new File(System.getProperty("java.io.tmpdir"));
        File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp");
    
        if (!scratchDir.exists())
        {
            if (!scratchDir.mkdirs())
            {
                throw new IOException("Unable to create scratch directory: " + scratchDir);
            }
        }
        servletContextHandler.setAttribute("javax.servlet.context.tempdir", scratchDir);
    
        // Set Classloader of Context to be sane (needed for JSTL)
        // JSP requires a non-System classloader, this simply wraps the
        // embedded System classloader in a way that makes it suitable
        // for JSP to use
        ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
        servletContextHandler.setClassLoader(jspClassLoader);
        
        // Manually call JettyJasperInitializer on context startup
        servletContextHandler.addBean(new JspStarter(servletContextHandler));
        
        // Create / Register JSP Servlet (must be named "jsp" per spec)
        ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
        holderJsp.setInitOrder(0);
        holderJsp.setInitParameter("logVerbosityLevel", "ERROR");
        holderJsp.setInitParameter("fork", "false");
        holderJsp.setInitParameter("xpoweredBy", "false");
        holderJsp.setInitParameter("compilerTargetVM", ConfigValue.JavaVersion.toString());
        holderJsp.setInitParameter("compilerSourceVM", ConfigValue.JavaVersion.toString());
        holderJsp.setInitParameter("keepgenerated", "false");
        servletContextHandler.addServlet(holderJsp, "*.jsp");
    }
	private void init() {
		String methodName = "init";
		logger.trace(methodName, null, messages.fetch("enter"));
		logger.info(methodName, null, messages.fetchLabel("cluster name")+getClusterName());
		logger.info(methodName, null, messages.fetchLabel("class definition file")+getClassDefinitionFile());
		
		String property;

        /**                                                                                                                                                        
         * Determine server idle timeout                                                                                                                           
         * ducc.ws.idle.timeout                                                                                                                                    
         */
        property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_idle_timeout);
        int idleTimeout = ConfigValue.IdleTimeout.getInt(property);

        /**                                                                                                                                                        
         * Determine server max threads                                                                                                                            
         * ducc.ws.max.threads                                                                                                                                     
         */
        property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_max_threads);
        int maxThreads = ConfigValue.MaxThreads.getInt(property);

        /**                                                                                                                                                        
         * Determine server http port                                                                                                                              
         * ducc.ws.port                                                                                                                                            
         */
        property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_port);
        int portHttp = ConfigValue.PortHttp.getInt(property);

        /**                                                                                                                                                        
          * Determine server https port                                                                                                                             
          * ducc.ws.port.ssl                                                                                                                                      
          */
        property = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_port_ssl);
        int portHttps = ConfigValue.PortHttps.getInt(property);

        try {
        	InetAddress inetAddress = InetAddress.getLocalHost();
            String host = inetAddress.getCanonicalHostName();
            DuccWebMonitor.getInstance().register(host, ""+portHttp);
        }
        catch(Exception e) {
            logger.error(methodName, jobid, e);
        }

        // === jetty.xml ===                                                                                                                                       

        // Setup Threadpool                                                                                                                                        
        QueuedThreadPool threadPool = new QueuedThreadPool();
        threadPool.setMaxThreads(maxThreads);

        // Server                                                                                                                                                          
        server = new Server(threadPool);

        // Scheduler                                                                                                                                                       
        server.addBean(new ScheduledExecutorScheduler());

        // === jetty-http.xml ===                                                                                                                                          
        ServerConnector http = new ServerConnector(server, new HttpConnectionFactory());
        http.setPort(portHttp);
        http.setIdleTimeout(idleTimeout);
        server.addConnector(http);

        // === jetty-https.xml ===                                                                                                                                         
        // SSL Context Factory                                                                                                                                             
        SslContextFactory sslContextFactory = new SslContextFactory();
        String keystore = DuccWebServerHelper.getDuccWebKeyStore();

        logger.info(methodName, jobid, "keystore="+keystore);
        HttpConfiguration http_config = new HttpConfiguration();
 		http_config.setSecureScheme("https");
 		http_config.setSecurePort(portHttps);
 		logger.info(methodName, jobid, "portHttps="+portHttps);
        HttpConfiguration https_config = new HttpConfiguration(http_config);
        https_config.addCustomizer(new SecureRequestCustomizer());
         
        ServerConnector https = new ServerConnector(server,
             new SslConnectionFactory(sslContextFactory,"http/1.1"),
             new HttpConnectionFactory(https_config));

        https.setPort(portHttps);
        sslContextFactory.setKeyStorePath(keystore);
        String pw = getKeyStorePassword();
        logger.trace(methodName, jobid, "pw="+pw);
        sslContextFactory.setKeyStorePassword(getKeyStorePassword());    
        sslContextFactory.setKeyManagerPassword(getKeyManagerPassword());
        
        server.setConnectors(new Connector[] { http });
        server.addConnector(https);
        
        // JSP
        ServletContextHandler jspHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
        
        jspHandler.setContextPath("/");
        jspHandler.setResourceBase("root");
        try {
        	enableEmbeddedJspSupport(jspHandler);
        } catch( IOException e) {
        	logger.error(methodName, jobid, e);
        }
    
        jspHandler.addServlet(DefaultServlet.class, "/");

        ResourceHandler resourceHandler = new ResourceHandler();
        resourceHandler.setDirectoriesListed(true);
        rootDir = DuccWebServerHelper.getDuccWebRoot();
        resourceHandler.setResourceBase(rootDir);
        
        jspHandler.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers());
        jspHandler.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
        try {
			Properties properties = DuccWebProperties.get();
			String ducc_runmode = properties.getProperty("ducc.runmode","Production");
			logger.debug(methodName, null, "ducc.runmode:"+ducc_runmode);
			logger.debug(methodName, null, "rootdir:"+rootDir);
			String $runmode_jsp = rootDir+File.separator+"$banner"+File.separator+"$runmode.jsp";
			logger.debug(methodName, null, "$runmode_jsp:"+$runmode_jsp);
			File $runmodeFile = new File($runmode_jsp);
			logger.debug(methodName, null, "path:"+$runmodeFile.getAbsolutePath());
			$runmodeFile.delete();
			String text;
			if(ducc_runmode.equalsIgnoreCase("Test")) {
				text = "<%@ include file=\"$runmode.test.jsp\" %>";
			}
			else {
				text = "<%@ include file=\"$runmode.production.jsp\" %>";
			}
			PrintWriter out = new PrintWriter($runmodeFile);
			out.println(text);
			out.flush();
			out.close();
        }
        catch(Exception e) {
			logger.info(methodName, null, e);
        }
        //
        HandlerList handlers = new HandlerList();
		
        String key = "ducc.ws.requestLog.RetainDays";
        int dflt = 0;
        int requestLogRetainDays = DuccPropertiesResolver.get(key, dflt);
        logger.info(methodName, jobid, "requestLogRetainDays="+requestLogRetainDays);
        if(requestLogRetainDays > 0) {
			String requestLogTimeZone = "GMT";
			String requestLogFmt = "yyyy_MM_dd";
			String requestLogFile = DuccWebServerHelper.getDuccWebLogsDir()+requestLogFmt+".request.log";
			NCSARequestLog requestLog = new NCSARequestLog();
		    requestLog.setFilename(requestLogFile);
		    requestLog.setFilenameDateFormat(requestLogFmt);
		    requestLog.setRetainDays(requestLogRetainDays);
		    requestLog.setAppend(true);
		    requestLog.setExtended(true);
		    requestLog.setLogCookies(false);
		    requestLog.setLogTimeZone(requestLogTimeZone);
		    RequestLogHandler requestLogHandler = new RequestLogHandler();
		    requestLogHandler.setRequestLog(requestLog);
		    handlers.addHandler(requestLogHandler);
		    logger.info(methodName, jobid, "requestLogFile="+requestLogFile);
        }
		
        DuccHandler duccHandler = new DuccHandler(this);
        ArrayList localHandlers = DuccPlugins.getInstance().gethandlers(this);
        DuccHandlerClassic duccHandlerClassic = new DuccHandlerClassic(this);
        DuccHandlerJsonFormat duccHandlerJson = new DuccHandlerJsonFormat(this);
        DuccHandlerProxy duccHandlerProxy = new DuccHandlerProxy();
        DuccHandlerViz duccHandlerViz = new DuccHandlerViz();
        DuccHandlerUserAuthentication duccHandlerUserAuthentication = new DuccHandlerUserAuthentication();
        SessionHandler sessionHandler = new SessionHandler();
        handlers.addHandler(sessionHandler);
        handlers.addHandler(duccHandlerUserAuthentication);
        
        String welcomePage = getWelcomePage();
        jspHandler.setWelcomeFiles(new String[]{ welcomePage });
        resourceHandler.setWelcomeFiles(new String[]{ welcomePage });
        
        DuccHandlerHttpRequestFilter httpRequestFilter = new DuccHandlerHttpRequestFilter(this);
        handlers.addHandler(httpRequestFilter);
        
        for(Handler handler: localHandlers) {
        	handlers.addHandler(handler);
        }
        handlers.addHandler(duccHandlerJson);
        handlers.addHandler(duccHandlerProxy);
        handlers.addHandler(duccHandlerClassic);
        handlers.addHandler(duccHandlerViz);
        handlers.addHandler(duccHandler);
        handlers.addHandler(jspHandler);
        handlers.addHandler(resourceHandler);
        handlers.addHandler(new DefaultHandler());
        server.setHandler(handlers);
		
        logger.trace(methodName, null, messages.fetch("exit"));
	}
	
	public void start() throws Exception {
		server.start();
	}
	
	public void join() throws Exception {
		server.join();
	}
	
	public void stop() throws Exception {
		server.stop();
	}
    public static class JspStarter extends AbstractLifeCycle implements ServletContextHandler.ServletContainerInitializerCaller
    {
        JettyJasperInitializer sci;
        ServletContextHandler context;
        
        public JspStarter (ServletContextHandler context)
        {
            this.sci = new JettyJasperInitializer();
            this.context = context;
            this.context.setAttribute("org.apache.tomcat.JarScanner", new StandardJarScanner());
        }

        @Override
        protected void doStart() throws Exception
        {
            ClassLoader old = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(context.getClassLoader());
            try
            {
                sci.onStartup(null, context.getServletContext());   
                super.doStart();
            }
            finally
            {
                Thread.currentThread().setContextClassLoader(old);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy