org.apache.hadoop.gateway.GatewayServer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.gateway.GatewayServer.java

Source

/**
 * 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.hadoop.gateway;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.gateway.audit.api.Action;
import org.apache.hadoop.gateway.audit.api.ActionOutcome;
import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
import org.apache.hadoop.gateway.audit.api.Auditor;
import org.apache.hadoop.gateway.audit.api.ResourceType;
import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl;
import org.apache.hadoop.gateway.deploy.DeploymentFactory;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.hadoop.gateway.services.GatewayServices;
import org.apache.hadoop.gateway.services.ServiceLifecycleException;
import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
import org.apache.hadoop.gateway.services.security.SSLService;
import org.apache.hadoop.gateway.topology.Topology;
import org.apache.hadoop.gateway.topology.TopologyEvent;
import org.apache.hadoop.gateway.topology.TopologyListener;
import org.apache.hadoop.gateway.topology.file.FileTopologyProvider;
import org.apache.log4j.PropertyConfigurator;
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.webapp.WebAppContext;
import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

public class GatewayServer {
    private static GatewayResources res = ResourcesFactory.get(GatewayResources.class);
    private static GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
    private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor(
            AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
            AuditConstants.KNOX_COMPONENT_NAME);
    private static GatewayServer server;
    private static GatewayServices services;

    private static Properties buildProperties;

    private Server jetty;
    private ErrorHandler errorHandler;
    private GatewayConfig config;
    private ContextHandlerCollection contexts;
    private FileTopologyProvider monitor;
    private TopologyListener listener;
    private Map<String, WebAppContext> deployments;

    public static void main(String[] args) {
        try {
            configureLogging();
            CommandLine cmd = GatewayCommandLine.parse(args);
            if (cmd.hasOption(GatewayCommandLine.HELP_LONG)) {
                GatewayCommandLine.printHelp();
            } else if (cmd.hasOption(GatewayCommandLine.VERSION_LONG)) {
                printVersion();
            } else if (cmd.hasOption(GatewayCommandLine.REDEPLOY_LONG)) {
                GatewayConfig config = new GatewayConfigImpl();
                redeployTopologies(config, cmd.getOptionValue(GatewayCommandLine.REDEPLOY_LONG));
            } else {
                services = instantiateGatewayServices();
                if (services == null) {
                    log.failedToInstantiateGatewayServices();
                }
                GatewayConfig config = new GatewayConfigImpl();
                if (config.isHadoopKerberosSecured()) {
                    configureKerberosSecurity(config);
                }
                Map<String, String> options = new HashMap<String, String>();
                options.put(GatewayCommandLine.PERSIST_LONG,
                        Boolean.toString(cmd.hasOption(GatewayCommandLine.PERSIST_LONG)));
                services.init(config, options);
                if (!cmd.hasOption(GatewayCommandLine.NOSTART_LONG)) {
                    startGateway(config, services);
                }
            }
        } catch (ParseException e) {
            log.failedToParseCommandLine(e);
            GatewayCommandLine.printHelp();
        } catch (ServiceLifecycleException e) {
            log.failedToStartGateway(e);
        }
    }

    private static void printVersion() {
        buildProperties = loadBuildProperties();
        System.out.println(res.gatewayVersionMessage( // I18N not required.
                buildProperties.getProperty("build.version", "unknown"),
                buildProperties.getProperty("build.hash", "unknown")));
    }

    private static GatewayServices instantiateGatewayServices() {
        ServiceLoader<GatewayServices> loader = ServiceLoader.load(GatewayServices.class);
        Iterator<GatewayServices> services = loader.iterator();
        if (services.hasNext()) {
            return services.next();
        }
        return null;
    }

    public static synchronized GatewayServices getGatewayServices() {
        return services;
    }

    private static void configureLogging() {
        PropertyConfigurator.configure(System.getProperty("log4j.configuration"));
        //    String fileName = config.getGatewayConfDir() + File.separator + "log4j.properties";
        //    File file = new File( fileName );
        //    if( file.isFile() && file.canRead() ) {
        //      FileInputStream stream;
        //      try {
        //        stream = new FileInputStream( file );
        //        Properties properties = new Properties();
        //        properties.load( stream );
        //        PropertyConfigurator.configure( properties );
        //        log.loadedLoggingConfig( fileName );
        //      } catch( IOException e ) {
        //        log.failedToLoadLoggingConfig( fileName );
        //      }
        //    }
    }

    private static void configureKerberosSecurity(GatewayConfig config) {
        System.setProperty(GatewayConfig.HADOOP_KERBEROS_SECURED, "true");
        System.setProperty(GatewayConfig.KRB5_CONFIG, config.getKerberosConfig());
        System.setProperty(GatewayConfig.KRB5_DEBUG, Boolean.toString(config.isKerberosDebugEnabled()));
        System.setProperty(GatewayConfig.KRB5_LOGIN_CONFIG, config.getKerberosLoginConfig());
        System.setProperty(GatewayConfig.KRB5_USE_SUBJECT_CREDS_ONLY, "false");
    }

    private static Properties loadBuildProperties() {
        Properties properties = new Properties();
        InputStream inputStream = GatewayServer.class.getClassLoader().getResourceAsStream("build.properties");
        if (inputStream != null) {
            try {
                properties.load(inputStream);
                inputStream.close();
            } catch (IOException e) {
                // Ignore.
            }
        }
        return properties;
    }

    private static void extractToFile(String resource, File file) throws IOException {
        InputStream input = ClassLoader.getSystemResourceAsStream(resource);
        OutputStream output = new FileOutputStream(file);
        IOUtils.copy(input, output);
        output.close();
        input.close();
    }

    private static void redeployTopology(Topology topology) {
        File topologyFile = new File(topology.getUri());
        long start = System.currentTimeMillis();
        long limit = 1000L; // One second.
        long elapsed = 1;
        while (elapsed <= limit) {
            try {
                long origTimestamp = topologyFile.lastModified();
                long setTimestamp = Math.max(System.currentTimeMillis(), topologyFile.lastModified() + elapsed);
                if (topologyFile.setLastModified(setTimestamp)) {
                    long newTimstamp = topologyFile.lastModified();
                    if (newTimstamp > origTimestamp) {
                        break;
                    } else {
                        Thread.sleep(10);
                        elapsed = System.currentTimeMillis() - start;
                        continue;
                    }
                } else {
                    log.failedToRedeployTopology(topology.getName());
                    break;
                }
            } catch (InterruptedException e) {
                log.failedToRedeployTopology(topology.getName(), e);
                e.printStackTrace();
            }
        }
    }

    public static void redeployTopologies(GatewayConfig config, String topologyName) {
        try {
            File topologiesDir = calculateAbsoluteTopologiesDir(config);
            FileTopologyProvider provider = new FileTopologyProvider(topologiesDir);
            provider.reloadTopologies();
            for (Topology topology : provider.getTopologies()) {
                if (topologyName == null || topologyName.equals(topology.getName())) {
                    redeployTopology(topology);
                }
            }
        } catch (SAXException e) {
            log.failedToRedeployTopologies(e);
        } catch (IOException e) {
            log.failedToRedeployTopologies(e);
        }
    }

    public static GatewayServer startGateway(GatewayConfig config, GatewayServices svcs) {
        try {
            log.startingGateway();
            server = new GatewayServer(config);
            synchronized (server) {
                //KM[ Commented this out because is causes problems with
                // multiple services instance used in a single test process.
                // I'm not sure what drive including this check though.
                //if (services == null) {
                services = svcs;
                //}
                //KM]
                services.start();
                DeploymentFactory.setGatewayServices(services);
                server.start();
                log.startedGateway(server.jetty.getConnectors()[0].getLocalPort());
                return server;
            }
        } catch (Exception e) {
            log.failedToStartGateway(e);
            return null;
        }
    }

    public GatewayServer(GatewayConfig config) {
        this(config, null);
    }

    public GatewayServer(GatewayConfig config, Properties options) {
        this.config = config;
        this.listener = new InternalTopologyListener();
    }

    //  private void setupSslExample() throws Exception {
    //    SslContextFactory sslContextFactory = new SslContextFactory( true );
    //    sslContextFactory.setCertAlias( "server" );
    //    sslContextFactory.setKeyStorePath( "target/test-classes/server-keystore.jks" );
    //    sslContextFactory.setKeyStorePassword( "password" );
    //    //sslContextFactory.setKeyManagerPassword( "password" );
    //    sslContextFactory.setTrustStore( "target/test-classes/server-truststore.jks" );
    //    sslContextFactory.setTrustStorePassword( "password" );
    //    sslContextFactory.setNeedClientAuth( false );
    //    sslContextFactory.setTrustAll( true );
    //    SslConnector sslConnector = new SslSelectChannelConnector( sslContextFactory );
    //
    //    ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS );
    //    context.setContextPath( "/" );
    //    ServletHolder servletHolder = new ServletHolder( new MockServlet() );
    //    context.addServlet( servletHolder, "/*" );
    //
    //    jetty = new Server();
    //    jetty.addConnector( sslConnector );
    //    jetty.setHandler( context );
    //    jetty.start();
    //  }

    private synchronized void start() throws Exception {

        // Create the global context handler.
        contexts = new ContextHandlerCollection();
        // A map to keep track of current deployments by cluster name.
        deployments = new ConcurrentHashMap<String, WebAppContext>();

        // Determine the socket address and check availability.
        InetSocketAddress address = config.getGatewayAddress();
        checkAddressAvailability(address);

        // Start Jetty.
        if (config.isSSLEnabled()) {
            jetty = new Server();
        } else {
            jetty = new Server(address);
        }
        if (config.isSSLEnabled()) {
            SSLService ssl = services.getService("SSLService");
            String keystoreFileName = config.getGatewaySecurityDir() + File.separatorChar + "keystores"
                    + File.separatorChar + "gateway.jks";
            Connector connector = (Connector) ssl.buildSSlConnector(keystoreFileName);
            connector.setHost(address.getHostName());
            connector.setPort(address.getPort());
            jetty.addConnector(connector);
        }
        jetty.setHandler(contexts);
        try {
            jetty.start();
        } catch (IOException e) {
            log.failedToStartGateway(e);
            throw e;
        }

        // Create a dir/file based cluster topology provider.
        File topologiesDir = calculateAbsoluteTopologiesDir();
        monitor = new FileTopologyProvider(topologiesDir);
        monitor.addTopologyChangeListener(listener);

        // Load the current topologies.
        log.loadingTopologiesFromDirectory(topologiesDir.getAbsolutePath());
        monitor.reloadTopologies();

        // Start the topology monitor.
        log.monitoringTopologyChangesInDirectory(topologiesDir.getAbsolutePath());
        monitor.startMonitor();
    }

    public synchronized void stop() throws Exception {
        log.stoppingGateway();
        services.stop();
        monitor.stopMonitor();
        jetty.stop();
        jetty.join();
        log.stoppedGateway();
    }

    public InetSocketAddress[] getAddresses() {
        InetSocketAddress[] addresses = new InetSocketAddress[jetty.getConnectors().length];
        for (int i = 0, n = addresses.length; i < n; i++) {
            Connector connector = jetty.getConnectors()[i];
            String host = connector.getHost();
            if (host == null) {
                addresses[i] = new InetSocketAddress(connector.getLocalPort());
            } else {
                addresses[i] = new InetSocketAddress(host, connector.getLocalPort());
            }
        }
        return addresses;
    }

    private synchronized void internalDeploy(Topology topology, File warFile) {
        String name = topology.getName();
        String warPath = warFile.getAbsolutePath();
        errorHandler = new ErrorHandler();
        errorHandler.setShowStacks(false);
        WebAppContext context = new WebAppContext();
        context.setDefaultsDescriptor(null);
        context.setContextPath("/" + config.getGatewayPath() + "/" + name);
        context.setWar(warPath);
        context.setErrorHandler(errorHandler);
        // internalUndeploy( topology ); KNOX-152
        context.setAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE, name);
        deployments.put(name, context);
        contexts.addHandler(context);
        try {
            context.start();
        } catch (Exception e) {
            log.failedToDeployTopology(name, e);
        }
    }

    private synchronized void internalUndeploy(Topology topology) {
        WebAppContext context = deployments.remove(topology.getName());
        if (context != null) {
            ServiceRegistry sr = getGatewayServices().getService(GatewayServices.SERVICE_REGISTRY_SERVICE);
            if (sr != null) {
                sr.removeClusterServices(topology.getName());
            }
            contexts.removeHandler(context);
            try {
                context.stop();
            } catch (Exception e) {
                log.failedToUndeployTopology(topology.getName(), e);
            }
        }
    }

    // Using an inner class to hide the handleTopologyEvent method from consumers of GatewayServer.
    private class InternalTopologyListener implements TopologyListener {

        @Override
        public void handleTopologyEvent(List<TopologyEvent> events) {
            synchronized (GatewayServer.this) {
                for (TopologyEvent event : events) {
                    Topology topology = event.getTopology();
                    File deployDir = calculateAbsoluteDeploymentsDir();
                    if (event.getType().equals(TopologyEvent.Type.DELETED)) {
                        File[] files = deployDir
                                .listFiles(new WarDirFilter(topology.getName() + "\\.war\\.[0-9A-Fa-f]+"));
                        if (files != null) {
                            for (File file : files) {
                                auditor.audit(Action.UNDEPLOY, topology.getName(), ResourceType.TOPOLOGY,
                                        ActionOutcome.UNAVAILABLE);
                                log.deletingDeployment(file.getAbsolutePath());
                                internalUndeploy(topology);
                                FileUtils.deleteQuietly(file);
                            }
                        }
                    } else {
                        try {
                            File warDir = calculateDeploymentDir(topology);
                            if (!warDir.exists()) {
                                auditor.audit(Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY,
                                        ActionOutcome.UNAVAILABLE);
                                log.deployingTopology(topology.getName(), warDir.getAbsolutePath());
                                internalUndeploy(topology); // KNOX-152
                                WebArchive war = null;
                                war = DeploymentFactory.createDeployment(config, topology);
                                if (!deployDir.exists()) {
                                    deployDir.mkdirs();
                                }
                                File tmp = war.as(ExplodedExporter.class).exportExploded(deployDir,
                                        warDir.getName() + ".tmp");
                                tmp.renameTo(warDir);
                                internalDeploy(topology, warDir);
                                //log.deployedTopology( topology.getName());
                            } else {
                                auditor.audit(Action.REDEPLOY, topology.getName(), ResourceType.TOPOLOGY,
                                        ActionOutcome.UNAVAILABLE);
                                log.redeployingTopology(topology.getName(), warDir.getAbsolutePath());
                                internalDeploy(topology, warDir);
                                //log.redeployedTopology( topology.getName() );
                            }
                        } catch (Throwable e) {
                            auditor.audit(Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY,
                                    ActionOutcome.FAILURE);
                            log.failedToDeployTopology(topology.getName(), e);
                        }
                    }
                }
            }
        }

    }

    private static File calculateAbsoluteTopologiesDir(GatewayConfig config) {
        File topoDir = new File(config.getGatewayTopologyDir());
        topoDir = topoDir.getAbsoluteFile();
        return topoDir;
    }

    private static File calculateAbsoluteDeploymentsDir(GatewayConfig config) {
        File deployDir = new File(config.getGatewayDeploymentDir());
        deployDir = deployDir.getAbsoluteFile();
        return deployDir;
    }

    private File calculateAbsoluteTopologiesDir() {
        return calculateAbsoluteTopologiesDir(config);
    }

    private File calculateAbsoluteDeploymentsDir() {
        return calculateAbsoluteDeploymentsDir(config);
    }

    private File calculateDeploymentDir(Topology topology) {
        File warDir = new File(calculateAbsoluteDeploymentsDir(), calculateDeploymentName(topology));
        return warDir;
    }

    private String calculateDeploymentName(Topology topology) {
        String name = topology.getName() + ".war." + Long.toHexString(topology.getTimestamp());
        return name;
    }

    private static void checkAddressAvailability(InetSocketAddress address) throws IOException {
        ServerSocket socket = new ServerSocket();
        socket.bind(address);
        socket.close();
    }

    private class WarDirFilter implements FilenameFilter {

        Pattern pattern;

        WarDirFilter(String regex) {
            pattern = Pattern.compile(regex);
        }

        @Override
        public boolean accept(File dir, String name) {
            return pattern.matcher(name).matches();
        }
    }

}