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

org.jumpmind.symmetric.SymmetricWebServer Maven / Gradle / Ivy

Go to download

SymmetricDS is an open source database synchronization solution. It is platform-independent, web-enabled, and database-agnostic. SymmetricDS was first built to replicate changes between 'retail store' databases and ad centralized 'corporate' database.

The newest version!
/*
 * Licensed to JumpMind Inc under one or more contributor 
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding 
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU Lesser General Public License (the
 * "License"); you may not use this file except in compliance
 * with the License. 
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see           
 * .
 * 
 * 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.jumpmind.symmetric;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;

import javax.management.Attribute;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.servlet.ServletContext;

import mx4j.tools.adaptor.http.HttpAdaptor;
import mx4j.tools.adaptor.http.XSLTProcessor;

import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.http.security.Constraint;
import org.eclipse.jetty.http.security.Password;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.bio.SocketConnector;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.webapp.WebAppContext;
import org.jumpmind.symmetric.common.Constants;
import org.jumpmind.symmetric.common.SecurityConstants;
import org.jumpmind.symmetric.common.SystemConstants;
import org.jumpmind.symmetric.common.logging.ILog;
import org.jumpmind.symmetric.common.logging.LogFactory;
import org.jumpmind.symmetric.util.AppUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * Start up SymmetricDS through an embedded Jetty instance.
 * 
 * @see SymmetricLauncher#main(String[])
 *
 * 
 */
public class SymmetricWebServer {

    protected static final ILog log = LogFactory.getLog(SymmetricWebServer.class);
    
    protected static final String DEFAULT_WEBAPP_DIR = "../web";

    /**
     * The type of HTTP connection to create for this SymmetricDS web server
     */
    public enum Mode {
        HTTP, HTTPS, MIXED;
    }

    private Server server;
    
    private WebAppContext webapp;

    protected boolean join = true;

    protected boolean createJmxServer = true;

    protected String webHome = "/sync";

    protected int maxIdleTime = 7200000;

    protected int httpPort = -1;

    protected int httpsPort = -1;
    
    protected String basicAuthUsername = null;
    
    protected String basicAuthPassword = null;

    protected String propertiesFile = null;

    protected String host = null;
    
    protected boolean noNio = false;
    
    protected boolean noDirectBuffer = false;
    
    protected String webAppDir = DEFAULT_WEBAPP_DIR;    

    public SymmetricWebServer() {
    }
    
    public SymmetricWebServer(String propertiesUrl) {
        this(propertiesUrl, DEFAULT_WEBAPP_DIR);
    }

    public SymmetricWebServer(String propertiesUrl, String webappDir) {
        this.propertiesFile = propertiesUrl ;
        this.webAppDir = webappDir;
    }

    public SymmetricWebServer(int maxIdleTime, String propertiesUrl, boolean join, boolean noNio, boolean noDirectBuffer) {
        this(propertiesUrl, DEFAULT_WEBAPP_DIR);
        this.maxIdleTime = maxIdleTime;
        this.join = join;
        this.noDirectBuffer = noDirectBuffer;
        this.noNio = noNio;
    }

    public SymmetricWebServer(int maxIdleTime, String propertiesUrl) {
        this(propertiesUrl, DEFAULT_WEBAPP_DIR);
        this.maxIdleTime = maxIdleTime;
    }

    public SymmetricWebServer start(int port, String propertiesUrl) throws Exception {
        this.propertiesFile = propertiesUrl ;
        return start(port);
    }

    public SymmetricWebServer start() throws Exception {
        if (httpPort > 0 && httpsPort > 0) {
            return startMixed(httpPort, httpsPort);
        } else if (httpPort > 0) {
            return start(httpPort);
        } else if (httpsPort > 0) {
            return startSecure(httpsPort);
        } else {
            throw new IllegalStateException("Either an http or https port needs to be set before starting the server.");
        }
    }

    public SymmetricWebServer start(int port) throws Exception {
        return start(port, 0, Mode.HTTP);
    }

    public SymmetricWebServer startSecure(int port) throws Exception {
        return start(0, port, Mode.HTTPS);
    }

    public SymmetricWebServer startMixed(int port, int securePort) throws Exception {
        return start(port, securePort, Mode.MIXED);
    }

    public SymmetricWebServer start(int port, int securePort, Mode mode) throws Exception {
        server = new Server();

        server.setConnectors(getConnectors(port, securePort, mode));
        setupBasicAuthIfNeeded(server);

        // Configure JMX for Jetty
//        MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
//        server.getContainer().addEventListener(mbContainer);
//        server.addBean(mbContainer);
//        mbContainer.addBean(Log.getLog());
        
        webapp = new WebAppContext();
        webapp.setContextPath(webHome);
        webapp.setWar(webAppDir);
        
        server.setHandler(webapp);

        if (!StringUtils.isBlank(propertiesFile)) {
            System.setProperty(Constants.OVERRIDE_PROPERTIES_FILE_1, propertiesFile);    
        }
        
        server.start();

        if (createJmxServer) {
            int httpJmxPort = port != 0 ? port + 1 : securePort + 1;
            registerHttpJmxAdaptor(httpJmxPort);
        }

        if (join) {
            server.join();
        }

        return this;
    }
    
    protected ServletContext getServletContext() {
        return webapp != null ? webapp.getServletContext() : null;
    }
    
    public ISymmetricEngine getEngine() {
        ISymmetricEngine engine = null;
        ServletContext servletContext = getServletContext();
        if (servletContext != null) {
           ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
           engine = appContext.getBean(ISymmetricEngine.class);
        }
        return engine;
    }

    protected void setupBasicAuthIfNeeded(Server server) {
        if (StringUtils.isNotBlank(basicAuthUsername) ) {
            ConstraintSecurityHandler sh = new ConstraintSecurityHandler();

            Constraint constraint = new Constraint();
            constraint.setName(Constraint.__BASIC_AUTH);;
            constraint.setRoles(new String[]{SecurityConstants.EMBEDDED_WEBSERVER_DEFAULT_ROLE});
            constraint.setAuthenticate(true);
    
            ConstraintMapping cm = new ConstraintMapping();
            cm.setConstraint(constraint);
            cm.setPathSpec("/*");
            //sh.setConstraintMappings(new ConstraintMapping[] {cm});
            sh.addConstraintMapping(cm);
    
            sh.setAuthenticator(new BasicAuthenticator());
            
            HashLoginService loginService = new HashLoginService();
            loginService.putUser(basicAuthUsername, new Password(basicAuthPassword), null);
            sh.setLoginService(loginService);

            server.setHandler(sh);
            
        }
    }

    protected Connector[] getConnectors(int port, int securePort, Mode mode) {
        ArrayList connectors = new ArrayList();
        String keyStoreFile = System.getProperty(SecurityConstants.SYSPROP_KEYSTORE);

        if (mode.equals(Mode.HTTP) || mode.equals(Mode.MIXED)) {
            Connector connector = null;
            if (noNio) {
              connector = new SocketConnector();                
            } else {
              SelectChannelConnector nioConnector = new SelectChannelConnector();              
              nioConnector.setUseDirectBuffers(!noDirectBuffer);
              connector = nioConnector;
            }
            connector.setPort(port);
            connector.setHost(host);
            connector.setMaxIdleTime(maxIdleTime);            
            connectors.add(connector);  
            log.info("WebServerStarting", port);
        }
        if (mode.equals(Mode.HTTPS) || mode.equals(Mode.MIXED)) {
            Connector connector = new SslSocketConnector();
            String keyStorePassword = System.getProperty(SecurityConstants.SYSPROP_KEYSTORE_PASSWORD);
            keyStorePassword = (keyStorePassword != null) ? keyStorePassword : SecurityConstants.KEYSTORE_PASSWORD;
            ((SslSocketConnector) connector).setKeystore(keyStoreFile);
            ((SslSocketConnector) connector).setKeyPassword(keyStorePassword);
            ((SslSocketConnector) connector).setMaxIdleTime(maxIdleTime);
            connector.setPort(securePort);
            connector.setHost(host);
            connectors.add(connector);
            log.info("WebServerSecureStarting", securePort);
        }
        return connectors.toArray(new Connector[connectors.size()]);
    }

    protected void registerHttpJmxAdaptor(int jmxPort) throws Exception {
        if (AppUtils.isSystemPropertySet(SystemConstants.JMX_HTTP_CONSOLE_ENABLED, true)) {
            log.info("JMXConsoleStarting", jmxPort);
            MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
            ObjectName name = getHttpJmxAdaptorName();
            mbeanServer.createMBean(HttpAdaptor.class.getName(), name);
            if (!AppUtils.isSystemPropertySet(SystemConstants.JMX_HTTP_CONSOLE_LOCALHOST_ENABLED, true)) {
                mbeanServer.setAttribute(name, new Attribute("Host", "0.0.0.0"));
            }
            mbeanServer.setAttribute(name, new Attribute("Port", new Integer(jmxPort)));
            ObjectName processorName = getXslJmxAdaptorName();
            mbeanServer.createMBean(XSLTProcessor.class.getName(), processorName);
            mbeanServer.setAttribute(name, new Attribute("ProcessorName", processorName));
            mbeanServer.invoke(name, "start", null, null);
        }
    }

    protected ObjectName getHttpJmxAdaptorName() throws MalformedObjectNameException {
        return new ObjectName("Server:name=HttpAdaptor");
    }

    protected ObjectName getXslJmxAdaptorName() throws MalformedObjectNameException {
        return new ObjectName("Server:name=XSLTProcessor");
    }

    protected void removeHttpJmxAdaptor() {
        if (AppUtils.isSystemPropertySet(SystemConstants.JMX_HTTP_CONSOLE_ENABLED, true)) {
            try {
                MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
                mbeanServer.unregisterMBean(getHttpJmxAdaptorName());
                mbeanServer.unregisterMBean(getXslJmxAdaptorName());
            } catch (Exception e) {
                log.warn("JMXAdaptorUnregisterFailed");
            }
        }
    }

    public void stop() throws Exception {
        if (server != null) {
            if (createJmxServer) {
                removeHttpJmxAdaptor();
            }
            server.stop();
        }
    }

    public static void main(String[] args) throws Exception {
        new SymmetricWebServer().start(8080);
    }

    public boolean isJoin() {
        return join;
    }

    public void setJoin(boolean join) {
        this.join = join;
    }

    public void setWebHome(String webHome) {
        this.webHome = webHome;
    }

    public int getMaxIdleTime() {
        return maxIdleTime;
    }

    public void setMaxIdleTime(int maxIdleTime) {
        this.maxIdleTime = maxIdleTime;
    }

    public void setHttpPort(int httpPort) {
        this.httpPort = httpPort;
    }

    public void setHttpsPort(int httpsPort) {
        this.httpsPort = httpsPort;
    }

    public void setPropertiesFile(String propertiesFile) {
        this.propertiesFile = propertiesFile;
    }

    public void setCreateJmxServer(boolean createJmxServer) {
        this.createJmxServer = createJmxServer;
    }

    public void setHost(String host) {
        this.host = host;
    }
    
    public void setBasicAuthPassword(String basicAuthPassword) {
        this.basicAuthPassword = basicAuthPassword;
    }

    public void setBasicAuthUsername(String basicAuthUsername) {
        this.basicAuthUsername = basicAuthUsername;
    }
    
    public void setWebAppDir(String webAppDir) {
        this.webAppDir = webAppDir;
    }
    
    public void setNoNio(boolean noNio) {
        this.noNio = noNio;
    }
    
    public void setNoDirectBuffer(boolean noDirectBuffer) {
        this.noDirectBuffer = noDirectBuffer;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy