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

org.jumpmind.symmetric.web.SymmetricEngineHolder Maven / Gradle / Ivy

There is a newer version: 3.5.19
Show 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 General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) 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.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.jumpmind.db.util.BasicDataSourcePropertyConstants;
import org.jumpmind.properties.TypedProperties;
import org.jumpmind.security.ISecurityService;
import org.jumpmind.security.SecurityConstants;
import org.jumpmind.security.SecurityServiceFactory;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.AbstractCommandLauncher;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.model.Node;
import org.jumpmind.symmetric.model.NodeGroup;
import org.jumpmind.symmetric.model.NodeGroupLink;
import org.jumpmind.symmetric.model.NodeGroupLinkAction;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IRegistrationService;
import org.jumpmind.symmetric.service.ITriggerRouterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SymmetricEngineHolder {

    final Logger log = LoggerFactory.getLogger(getClass());
    
    private static Map staticEngines = new HashMap();

    private static Set staticEnginesStarting = new HashSet();

    private Map engines = new HashMap();

    private Set enginesStarting = new HashSet();

    private boolean staticEnginesMode = false;
    
    private boolean multiServerMode = false;

    private boolean autoStart = true;
    
    private boolean autoCreate = true;

    private String singleServerPropertiesFile;

    private static Date createTime = new Date();

    private int engineCount;

    private String deploymentType = "server";

    public Map getEngines() {
        return engines;
    }

    public void setDeploymentType(String deploymentType) {
        this.deploymentType = deploymentType;
    }

    public void setMultiServerMode(boolean multiServerMode) {
        this.multiServerMode = multiServerMode;
    }

    public boolean isMultiServerMode() {
        return multiServerMode;
    }
    
    public void setAutoCreate(boolean autoCreate) {
		this.autoCreate = autoCreate;
	}
    
    public boolean isAutoCreate() {
		return autoCreate;
	}
    
    public void setStaticEnginesMode(boolean staticEnginesMode) {
		this.staticEnginesMode = staticEnginesMode;
	}
    
    public boolean isStaticEnginesMode() {
		return staticEnginesMode;
	}

    public void setSingleServerPropertiesFile(String singleServerPropertiesFile) {
        this.singleServerPropertiesFile = singleServerPropertiesFile;
    }

    public String getSingleServerPropertiesFile() {
        return singleServerPropertiesFile;
    }

    public boolean areEnginesConfigured() {
        return enginesStarting.size() > 0 || engines.size() > 0;
    }

    public int getNumerOfEnginesStarting() {
        return enginesStarting.size();
    }

    public void setAutoStart(boolean autoStart) {
        this.autoStart = autoStart;
    }

    public boolean isAutoStart() {
        return autoStart;
    }

    public synchronized void stop() {
        Set engineNames = engines.keySet();
        for (String engineName : engineNames) {
            engines.get(engineName).destroy();
        }
        engines.clear();
    }

    public void start() {
    	if (staticEnginesMode) {
    		log.info("In static engine mode");
    	    engines = staticEngines;
    	    enginesStarting = staticEnginesStarting;
    	}
    	
		if (autoCreate) {
			if (isMultiServerMode()) {
				File enginesDir = new File(
						AbstractCommandLauncher.getEnginesDir());
				File[] files = null;

				if (enginesDir != null) {
					files = enginesDir.listFiles();
				}

				if (files == null) {
					String firstAttempt = enginesDir.getAbsolutePath();
					enginesDir = new File(".");
					log.warn(
							"Unable to retrieve engine properties files from {}.  Trying current working directory {}",
							firstAttempt, enginesDir.getAbsolutePath());

					if (enginesDir != null) {
						files = enginesDir.listFiles();
					}
				}

				if (files != null) {
					for (int i = 0; i < files.length; i++) {
						engineCount++;
						File file = files[i];
						if (file.getName().endsWith(".properties")) {
							enginesStarting.add(new EngineStarter(file
									.getAbsolutePath()));
						}
					}
				} else {
					log.error("Unable to retrieve engine properties files from default location or from current working directory.  No engines to start.");
				}

			} else {
				engineCount++;
				enginesStarting.add(new EngineStarter(
						singleServerPropertiesFile));
			}

			for (EngineStarter starter : enginesStarting) {
				starter.start();
			}

		}

    }

    public int getEngineCount() {
        return engineCount;
    }

    protected ISymmetricEngine create(String propertiesFile) {
        ServerSymmetricEngine engine = null;
        try {
            engine = new ServerSymmetricEngine(propertiesFile != null ? new File(propertiesFile)
                    : null);
            engine.setDeploymentType(deploymentType);
            if (!engines.containsKey(engine.getEngineName())) {
                engines.put(engine.getEngineName(), engine);
            } else {
                log.error(
                        "An engine with the name of {} was not started because an engine of the same name has already been started.  Please set the engine.name property in the properties file to a unique name.",
                        engine.getEngineName());
            }
            return engine;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    public ISymmetricEngine install(Properties passedInProperties) throws Exception {
        TypedProperties properties = new TypedProperties(passedInProperties);
        String password = properties.getProperty(BasicDataSourcePropertyConstants.DB_POOL_PASSWORD);
        if (StringUtils.isNotBlank(password) && !password.startsWith(SecurityConstants.PREFIX_ENC)) {
            try {
                ISecurityService service = SecurityServiceFactory.create(SecurityServiceType.CLIENT, properties);
                properties.setProperty(BasicDataSourcePropertyConstants.DB_POOL_PASSWORD,
                        SecurityConstants.PREFIX_ENC + service.encrypt(password));
            } catch (Exception ex) {
                log.warn("Could not encrypt password", ex);
            }
        }

        String engineName = validateRequiredProperties(properties);
        passedInProperties.setProperty(ParameterConstants.ENGINE_NAME, engineName);
        if (engines.get(engineName) != null) {
            try {
                engines.get(engineName).stop();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            engines.remove(engineName);
        }

        File enginesDir = new File(AbstractCommandLauncher.getEnginesDir());
        File symmetricProperties = new File(enginesDir, engineName + ".properties");
        FileOutputStream fileOs = null;
        try {
            fileOs = new FileOutputStream(symmetricProperties);
            properties.store(fileOs, "Updated by SymmetricDS Pro");
        } catch (IOException ex) {
            throw new RuntimeException("Failed to write symmetric.properties to engine directory",
                    ex);
        } finally {
            IOUtils.closeQuietly(fileOs);
        }

        ISymmetricEngine engine = null;
        try {

            String registrationUrl = properties.getProperty(ParameterConstants.REGISTRATION_URL);
            if (StringUtils.isNotBlank(registrationUrl)) {
                Collection servers = getEngines().values();
                for (ISymmetricEngine symmetricWebServer : servers) {
                    if (symmetricWebServer.getParameterService().getSyncUrl()
                            .equals(registrationUrl)) {
                        String serverNodeGroupId = symmetricWebServer.getParameterService()
                                .getNodeGroupId();
                        String clientNodeGroupId = properties
                                .getProperty(ParameterConstants.NODE_GROUP_ID);
                        String externalId = properties.getProperty(ParameterConstants.EXTERNAL_ID);

                        IConfigurationService configurationService = symmetricWebServer
                                .getConfigurationService();
                        ITriggerRouterService triggerRouterService = symmetricWebServer.
                                getTriggerRouterService();
                        List groups = configurationService.getNodeGroups();
                        boolean foundGroup = false;
                        for (NodeGroup nodeGroup : groups) {
                            if (nodeGroup.getNodeGroupId().equals(clientNodeGroupId)) {
                                foundGroup = true;
                            }
                        }

                        if (!foundGroup) {
                            configurationService.saveNodeGroup(new NodeGroup(clientNodeGroupId));
                        }

                        boolean foundLink = false;
                        List links = configurationService
                                .getNodeGroupLinksFor(serverNodeGroupId);
                        for (NodeGroupLink nodeGroupLink : links) {
                            if (nodeGroupLink.getTargetNodeGroupId().equals(clientNodeGroupId)) {
                                foundLink = true;
                            }
                        }

                        if (!foundLink) {
                            configurationService.saveNodeGroupLink(new NodeGroupLink(
                                    serverNodeGroupId, clientNodeGroupId, NodeGroupLinkAction.W));
                            triggerRouterService.syncTriggers();
                        }

                        IRegistrationService registrationService = symmetricWebServer
                                .getRegistrationService();
                        if (!registrationService.isAutoRegistration()
                                && !registrationService.isRegistrationOpen(clientNodeGroupId,
                                        externalId)) {
                            Node node = new Node(properties);
                            registrationService.openRegistration(node);
                        }
                    }
                }
            }

            engine = create(symmetricProperties.getAbsolutePath());
            if (engine != null && autoStart) {
                engine.start();
            } else {
                log.warn("The engine could not be created.  It will not be started");
            }
            return engine;

        } catch (RuntimeException ex) {
            if (engine != null) {
                engine.destroy();
            }
            FileUtils.deleteQuietly(symmetricProperties);
            throw ex;
        }

    }

    public boolean areEnginesStarting() {
        return enginesStarting.size() > 0;
    }

    public String getEngineName(Properties properties) {
        String engineName = properties.getProperty(ParameterConstants.ENGINE_NAME);
        if (StringUtils.isBlank(engineName)) {
            String externalId = properties.getProperty(ParameterConstants.EXTERNAL_ID, "");
            String groupId = properties.getProperty(ParameterConstants.NODE_GROUP_ID, "");
            if (externalId.equals(groupId)) {
                engineName = groupId;
            } else {
                engineName = groupId + "-" + externalId;
            }
            engineName = properties.getProperty(ParameterConstants.ENGINE_NAME, engineName);
            String engineExt = "";
            int engineNumber = 0;
            while (new File(AbstractCommandLauncher.getEnginesDir(), engineName + engineExt
                    + ".properties").exists()) {
                engineNumber++;
                engineExt = "-" + engineNumber;
            }
            engineName = engineName + engineExt;
        }
        return engineName;
    }

    public String validateRequiredProperties(Properties properties) {
        String externalId = properties.getProperty(ParameterConstants.EXTERNAL_ID);
        if (StringUtils.isBlank(externalId)) {
            throw new IllegalStateException("Missing property " + ParameterConstants.EXTERNAL_ID);
        }

        String groupId = properties.getProperty(ParameterConstants.NODE_GROUP_ID);
        if (StringUtils.isBlank(groupId)) {
            throw new IllegalStateException("Missing property " + ParameterConstants.NODE_GROUP_ID);
        }

        String engineName = getEngineName(properties);
        properties.setProperty(ParameterConstants.ENGINE_NAME, engineName);

        if (StringUtils.isBlank(properties.getProperty(ParameterConstants.SYNC_URL))) {
            throw new IllegalStateException("Missing property " + ParameterConstants.SYNC_URL);
        }
        if (StringUtils.isBlank(properties
                .getProperty(BasicDataSourcePropertyConstants.DB_POOL_DRIVER))) {
            throw new IllegalStateException("Missing property "
                    + BasicDataSourcePropertyConstants.DB_POOL_DRIVER);
        }
        if (StringUtils.isBlank(properties
                .getProperty(BasicDataSourcePropertyConstants.DB_POOL_URL))) {
            throw new IllegalStateException("Missing property "
                    + BasicDataSourcePropertyConstants.DB_POOL_URL);
        }
        if (!properties.containsKey(BasicDataSourcePropertyConstants.DB_POOL_USER)) {
            throw new IllegalStateException("Missing property "
                    + BasicDataSourcePropertyConstants.DB_POOL_USER);
        }
        if (!properties.containsKey(BasicDataSourcePropertyConstants.DB_POOL_PASSWORD)) {
            throw new IllegalStateException("Missing property "
                    + BasicDataSourcePropertyConstants.DB_POOL_PASSWORD);
        }
        if (!properties.containsKey(ParameterConstants.REGISTRATION_URL)) {
            properties.setProperty(ParameterConstants.REGISTRATION_URL, "");
        }
        return engineName;
    }

    public static Date getCreateTime() {
        return createTime;
    }

    class EngineStarter extends Thread {

        String propertiesFile;

        public EngineStarter(String propertiesFile) {
            super("symmetric-startup");
            this.propertiesFile = propertiesFile;
        }

        @Override
        public void run() {
            ISymmetricEngine engine = create(propertiesFile);        	
            if (engine != null && autoStart) {
                engine.start();
            }
            enginesStarting.remove(this);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy