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

com.cisco.oss.foundation.http.server.jetty.JettyHttpServerFactory Maven / Gradle / Ivy

/*
 * Copyright 2014 Cisco Systems, Inc.
 *
 *  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 com.cisco.oss.foundation.http.server.jetty;

import com.cisco.oss.foundation.configuration.ConfigurationFactory;
import com.cisco.oss.foundation.directory.RegistrationManager;
import com.cisco.oss.foundation.directory.ServiceDirectory;
import com.cisco.oss.foundation.directory.entity.OperationalStatus;
import com.cisco.oss.foundation.directory.entity.ProvidedServiceInstance;
import com.cisco.oss.foundation.directory.exception.ServiceException;
import com.cisco.oss.foundation.directory.impl.DirectoryServiceClient;
import com.cisco.oss.foundation.http.server.HttpServerFactory;
import com.cisco.oss.foundation.http.server.ServerFailedToStartException;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.nio.BlockingChannelConnector;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * This is a factory that enables creating servers in a common way
 *
 * @author Yair Ogen
 */
public enum JettyHttpServerFactory implements HttpServerFactory , JettyHttpServerFactoryExtensions {

    INSTANCE;

    private final static Logger LOGGER = LoggerFactory.getLogger(JettyHttpServerFactory.class);

    static{
        try {
            Configuration configuration = ConfigurationFactory.getConfiguration();
            String sdHost = configuration.getString("service.sd.host", "");
            int sdPort = configuration.getInt("service.sd.port", -1);

            if(StringUtils.isNotBlank(sdHost)){
                ServiceDirectory.getServiceDirectoryConfig().setProperty( DirectoryServiceClient.SD_API_SD_SERVER_FQDN_PROPERTY, sdHost);
            }

            if(sdPort > 0){
                ServiceDirectory.getServiceDirectoryConfig().setProperty( DirectoryServiceClient.SD_API_SD_SERVER_PORT_PROPERTY, sdPort);
            }
        } catch (Exception e) {
            LOGGER.error("Can't assign service Directory host and port properties: {}",e ,e);
        }
    }

    private static final Map> servers = new ConcurrentHashMap>();

    private JettyHttpServerFactory() {
    }

    /**
     * start a new http server
     *
     * @param serviceName - the http logical service name
     * @param servlets    - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}.
     *                    
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} */ @Override public void startHttpServer(String serviceName, ListMultimap servlets) { ArrayListMultimap filterMap = ArrayListMultimap.create(); startHttpServer(serviceName, servlets, filterMap); } @Override public void startHttpServer(String serviceName, ListMultimap servlets, Map initParams) { ArrayListMultimap filterMap = ArrayListMultimap.create(); startHttpServer(serviceName, servlets, filterMap, Collections.emptyList(), initParams); } @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filterMap, List eventListeners, Map initParams) { startHttpServer(serviceName, servlets, filterMap, eventListeners, initParams, "", "", "", ""); } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param eventListeners event listeners to be applied on this server */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, List eventListeners) { ArrayListMultimap filterMap = ArrayListMultimap.create(); startHttpServer(serviceName, servlets, filterMap, eventListeners); } /** * start a new http server * * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param filters - a mapping between filter path and filter instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap filterMap = ArrayListMultimap.create()} */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filters) { startHttpServer(serviceName, servlets, filters, "", ""); } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param filters - a mapping between filter path and filter instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap filterMap = ArrayListMultimap.create()} * @param eventListeners event listeners to be applied on this server */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filters, List eventListeners) { startHttpServer(serviceName, servlets, filters, eventListeners, "", "", "", ""); } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param filters - a mapping between filter path and filter instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap filterMap = ArrayListMultimap.create()} * @param keyStorePath - a path to the keystore file * @param keyStorePassword - the keystore password */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filters, String keyStorePath, String keyStorePassword) { startHttpServer(serviceName, servlets, filters, keyStorePath, keyStorePassword, "", ""); } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param keyStorePath - a path to the keystore file * @param keyStorePassword - the keystore password */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, String keyStorePath, String keyStorePassword) { startHttpServer(serviceName, servlets, keyStorePath, keyStorePassword, "", ""); } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param filters - a mapping between filter path and filter instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap filterMap = ArrayListMultimap.create()} * @param keyStorePath - a path to the keystore file * @param keyStorePassword - the keystore password * @param trustStorePath - the trust store file path * @param trustStorePassword - the trust store password */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filters, String keyStorePath, String keyStorePassword, String trustStorePath, String trustStorePassword) { startHttpServer(serviceName, servlets, filters, Collections.emptyList(), keyStorePath, keyStorePassword, trustStorePath, trustStorePassword); } @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filters, List eventListeners, String keyStorePath, String keyStorePassword, String trustStorePath, String trustStorePassword) { startHttpServer(serviceName, servlets, filters, eventListeners, new HashMap(), keyStorePath, keyStorePassword, trustStorePath, trustStorePassword); } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param filters - a mapping between filter path and filter instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap filterMap = ArrayListMultimap.create()} * @param eventListeners event listeners to be applied on this server * @param keyStorePath - a path to the keystore file * @param keyStorePassword - the keystore password * @param trustStorePath - the trust store file path * @param trustStorePassword - the trust store password */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, ListMultimap filters, List eventListeners, Map initParams, String keyStorePath, String keyStorePassword, String trustStorePath, String trustStorePassword) { if (servers.get(serviceName) != null) { throw new UnsupportedOperationException("you must first stop stop server: " + serviceName + " before you want to start it again!"); } ContextHandlerCollection handler = new ContextHandlerCollection(); JettyHttpThreadPool jettyHttpThreadPool = new JettyHttpThreadPool(serviceName); for (Map.Entry entry : servlets.entries()) { ServletContextHandler context = new ServletContextHandler(); if (eventListeners != null && !eventListeners.isEmpty()) { context.setEventListeners(eventListeners.toArray(new EventListener[0])); } context.addServlet(new ServletHolder(entry.getValue()), entry.getKey()); for (Map.Entry initParam : initParams.entrySet()) { context.setInitParameter(initParam.getKey(), initParam.getValue()); } HttpServerUtil.addFiltersToServletContextHandler(serviceName, jettyHttpThreadPool, context); for (Map.Entry filterEntry : filters.entries()) { context.addFilter(new FilterHolder(filterEntry.getValue()), filterEntry.getKey(), EnumSet.allOf(DispatcherType.class)); } handler.addHandler(context); } Server server = new Server(); server.setSendServerVersion(false); try { Configuration configuration = ConfigurationFactory.getConfiguration(); // set connectors String host = configuration.getString(serviceName + ".http.host", "0.0.0.0"); int port = configuration.getInt(serviceName + ".http.port", 8080); int connectionIdleTime = configuration.getInt(serviceName + ".http.connectionIdleTime", 180000); boolean isBlockingChannelConnector = configuration.getBoolean(serviceName + ".http.isBlockingChannelConnector", false); int numberOfAcceptors = configuration.getInt(serviceName + ".http.numberOfAcceptors", Runtime.getRuntime().availableProcessors()); int acceptQueueSize = configuration.getInt(serviceName + ".http.acceptQueueSize", 0); boolean serviceDirectoryEnabled = configuration.getBoolean(serviceName + ".http.serviceDirectory.isEnabled", false); AbstractConnector connector = null; if (isBlockingChannelConnector) { connector = new BlockingChannelConnector(); } else { connector = new SelectChannelConnector(); } connector.setAcceptQueueSize(acceptQueueSize); connector.setAcceptors(numberOfAcceptors); connector.setPort(port); connector.setHost(host); connector.setMaxIdleTime(connectionIdleTime); connector.setRequestHeaderSize(configuration.getInt(serviceName + ".http.requestHeaderSize", connector.getRequestHeaderSize())); Connector[] connectors = null; boolean useHttpsOnly = configuration.getBoolean(serviceName + ".https.useHttpsOnly", false); boolean isSSL = StringUtils.isNotBlank(keyStorePath) && StringUtils.isNotBlank(keyStorePassword); int sslPort = -1; SslSelectChannelConnector sslSelectChannelConnector = null; if (isSSL) { String sslHost = configuration.getString(serviceName + ".https.host", "0.0.0.0"); sslPort = configuration.getInt(serviceName + ".https.port", 8090); SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath(keyStorePath); sslContextFactory.setKeyStorePassword(keyStorePassword); boolean addTrustStoreSupport = StringUtils.isNotEmpty(trustStorePath) && StringUtils.isNotEmpty(trustStorePassword); if (addTrustStoreSupport) { sslContextFactory.setTrustStore(trustStorePath); sslContextFactory.setTrustStorePassword(trustStorePassword); sslContextFactory.setNeedClientAuth(true); } sslSelectChannelConnector = new SslSelectChannelConnector(sslContextFactory); sslSelectChannelConnector.setHost(sslHost); sslSelectChannelConnector.setPort(sslPort); if (useHttpsOnly) { connectors = new Connector[]{sslSelectChannelConnector}; } else { connectors = new Connector[]{connector, sslSelectChannelConnector}; } } else { connectors = new Connector[]{connector}; } server.setConnectors(connectors); // set thread pool server.setThreadPool(jettyHttpThreadPool.threadPool); // set servlets/context handlers server.setHandler(handler); server.start(); ProvidedServiceInstance instance = null; if (serviceDirectoryEnabled) { instance = registerWithSDServer(serviceName, host, port); } servers.put(serviceName, Pair.of(server,instance)); if (sslPort != -1 && sslSelectChannelConnector != null) { LOGGER.info("Https server: {} started on {}", serviceName, sslPort); } if(!useHttpsOnly){ LOGGER.info("Http server: {} started on {}", serviceName, port); } // server.join(); } catch (Exception e) { LOGGER.error("Problem starting the http {} server. Error is {}.", new Object[]{serviceName, e, e}); throw new ServerFailedToStartException(e); } } /** * @param serviceName - the http logical service name * @param servlets - a mapping between servlet path and servlet instance. This mapping uses the google collections {@link com.google.common.collect.ListMultimap}. *
Example of usage: * {@code ArrayListMultimap servletMap = ArrayListMultimap.create()} * @param keyStorePath - a path to the keystore file * @param keyStorePassword - the keystore password * @param trustStorePath - the trust store file path * @param trustStorePassword - the trust store password */ @Override public void startHttpServer(String serviceName, ListMultimap servlets, String keyStorePath, String keyStorePassword, String trustStorePath, String trustStorePassword) { ArrayListMultimap filterMap = ArrayListMultimap.create(); startHttpServer(serviceName, servlets, filterMap, keyStorePath, keyStorePassword, trustStorePath, trustStorePassword); } /** * stop the http server * * @param serviceName - the http logical service name */ @Override public void stopHttpServer(String serviceName) { Pair pair = servers.get(serviceName); if (pair != null) { Server server = pair.getLeft(); if (server != null) { try { server.stop(); servers.remove(serviceName); LOGGER.info("Http server: {} stopped", serviceName); } catch (Exception e) { LOGGER.error("Problem stopping the http {} server. Error is {}.", serviceName, e); } } ProvidedServiceInstance instance = pair.getRight(); if(instance != null){ try { final RegistrationManager registrationManager = ServiceDirectory.getRegistrationManager(); // registrationManager.updateServiceOperationalStatus(instance.getServiceName(),instance.getProviderId(),OperationalStatus.DOWN); registrationManager.unregisterService(instance.getServiceName(),instance.getProviderId()); } catch (ServiceException e) { LOGGER.error("Problem stopping the http {} server. Error is {}.", serviceName, e); } } } } @Override public void setErrorHandler(String serviceName, ErrorHandler errorHandler) { Server server = servers.get(serviceName).getLeft(); if (server != null) { server.addBean(errorHandler); } } private ProvidedServiceInstance registerWithSDServer(final String serviceName, String host, int port) throws Exception { // Get a RegistrationManager instance from ServiceDirectory. // The ServiceDirectory will load a default ServiceDirectoryConfig and instantialize a RegistrationManager instance. final RegistrationManager registrationManager = ServiceDirectory.getRegistrationManager(); // Construct the service instance. serviceName and providerId together uniquely identify a service instance where providerId is defined as "address-port". final ProvidedServiceInstance instance = new ProvidedServiceInstance(serviceName, host, port); // Setting the service instance URI. URI is defined as tcp://address:port for the TCP end point instance.setUri("http://" + host + ":" + port + ""); instance.setAddress(host); instance.setPort(port); instance.setStatus(OperationalStatus.UP); registrationManager.registerService(instance, null); // Update the OperationalStatus of the instance to DOWN, this instance will be removed from the ServiceInstance lookup. // registrationManager.updateServiceOperationalStatus(serviceName, instance.getProviderId(), OperationalStatus.DOWN); // Update the instance: OperationalStatus to UP, and the "version" metadata to "2.5.1" // instance.setStatus(OperationalStatus.UP); // instance.getMetadata().put("version", "2.5.1"); // instance.getMetadata().put("datacenter", "dc01"); // registrationManager.updateService(instance); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { // Unregister the instance. try { registrationManager.unregisterService(serviceName, instance.getProviderId()); } catch (ServiceException e) { LOGGER.error("can't un-register the service in service directory server. error is: {}", e); } } }); return instance; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy