org.lilyproject.lilyservertestfw.LilyProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.lilyproject.lilyservertestfw.LilyProxy.java

Source

/*
 * Copyright 2010 Outerthought bvba
 *
 * 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 org.lilyproject.lilyservertestfw;

import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Collections;

import com.ngdata.hbaseindexer.Main;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.PrefixFileFilter;
import org.lilyproject.hadooptestfw.HBaseProxy;
import org.lilyproject.lilyservertestfw.launcher.HbaseIndexerLauncherService;
import org.lilyproject.solrtestfw.SolrDefinition;
import org.lilyproject.solrtestfw.SolrProxy;
import org.lilyproject.util.io.Closer;
import org.lilyproject.util.test.TestHomeUtil;

public class LilyProxy {
    private static final String TEMP_DIR_PREFIX = "lily-proxy-";
    private HBaseProxy hbaseProxy;
    private LilyServerProxy lilyServerProxy;
    private SolrProxy solrProxy;
    private HbaseIndexerLauncherService hbaseIndexerLauncherService;
    private Mode mode;
    private File testHome;
    private boolean started = false;
    private boolean hasBeenStarted = false;
    private boolean clearData = true;

    public enum Mode {
        EMBED, CONNECT, HADOOP_CONNECT
    }

    public static String MODE_PROP_NAME = "lily.lilyproxy.mode";
    public static String TESTHOME_PROP_NAME = "lily.lilyproxy.dir";
    public static String CLEARDATA_PROP_NAME = "lily.lilyproxy.clear";
    public static String RESTORE_TEMPLATE_DIR_PROP_NAME = "lily.lilyproxy.restoretemplatedir";

    public LilyProxy() throws IOException {
        this(null);
    }

    public LilyProxy(Mode mode) throws IOException {
        this(mode, null, null);
    }

    public LilyProxy(Mode mode, File testHome, Boolean clearData) throws IOException {
        this(mode, testHome, clearData, Boolean.FALSE);
    }

    /**
     * Creates a new LilyProxy
     *
     * @param mode      either EMBED, CONNECT or HADOOP_CONNECT
     * @param testHome  the directory in which to store data and logfiles. Can only be used in EMBED mode.
     * @param clearData if true, clear the data when stopping the LilyProxy.
     *                  Should be used together with the testHome parameter and can only be used in EMBED mode.
     * @param enableSolrCloud if true, solr will be started in cloud mode
     * @throws IOException
     */
    public LilyProxy(Mode mode, File testHome, Boolean clearData, Boolean enableSolrCloud) throws IOException {
        if (mode == null) {
            String modeProp = System.getProperty(MODE_PROP_NAME);
            if (modeProp == null || modeProp.equals("") || modeProp.equals("embed")) {
                this.mode = Mode.EMBED;
            } else if (modeProp.equals("connect")) {
                this.mode = Mode.CONNECT;
            } else if (modeProp.equals("hadoop-connect")) {
                this.mode = Mode.HADOOP_CONNECT;
            } else {
                throw new RuntimeException("Unexpected value for " + MODE_PROP_NAME + ": " + modeProp);
            }
        } else {
            this.mode = mode;
        }

        if (testHome != null) {
            setTestHome(testHome);
        } else {
            String testHomeProp = System.getProperty(TESTHOME_PROP_NAME);
            if (testHomeProp != null) {
                setTestHome(new File(testHomeProp));
            }
        }

        if (clearData != null) {
            this.clearData = clearData;
        } else {
            this.clearData = Boolean.parseBoolean(System.getProperty(CLEARDATA_PROP_NAME, "true"));
        }

        HBaseProxy.Mode hbaseMode;
        SolrProxy.Mode solrMode;
        LilyServerProxy.Mode lilyServerMode;

        // LilyProxy imposes its mode on all of the specific Proxy's. This is because the special resetLilyState
        // operation in case of connect requires they are all in the same mode.
        // The special HADOOP_CONNECT mode is mainly intended for Lily's own tests: many tests suppose only
        // hadoop is running externally because they launch specific parts of the Lily implementation themselves,
        // combined with the fact that the mode should be the same for all tests.
        switch (this.mode) {
        case EMBED:
            hbaseMode = HBaseProxy.Mode.EMBED;
            solrMode = SolrProxy.Mode.EMBED;
            lilyServerMode = LilyServerProxy.Mode.EMBED;
            break;
        case CONNECT:
            hbaseMode = HBaseProxy.Mode.CONNECT;
            solrMode = SolrProxy.Mode.CONNECT;
            lilyServerMode = LilyServerProxy.Mode.CONNECT;
            break;
        case HADOOP_CONNECT:
            hbaseMode = HBaseProxy.Mode.CONNECT;
            solrMode = SolrProxy.Mode.EMBED;
            lilyServerMode = LilyServerProxy.Mode.EMBED;
            break;
        default:
            throw new RuntimeException("Unexpected mode: " + this.mode);
        }

        hbaseProxy = new HBaseProxy(hbaseMode, this.clearData);
        if (this.mode == Mode.CONNECT) {
            // we'll do the reset through the special JMX call
            hbaseProxy.setCleanStateOnConnect(false);
        }
        hbaseProxy.setEnableMapReduce(true);
        solrProxy = new SolrProxy(solrMode, this.clearData, enableSolrCloud);
        lilyServerProxy = new LilyServerProxy(lilyServerMode, this.clearData, hbaseProxy);
        hbaseIndexerLauncherService = new HbaseIndexerLauncherService();
    }

    public Mode getMode() {
        return mode;
    }

    public void start() throws Exception {
        start(null, null);
    }

    public void start(byte[] solrSchemaData) throws Exception {
        start(solrSchemaData, null);
    }

    public void start(byte[] solrSchemaData, byte[] solrConfigData) throws Exception {
        if (solrSchemaData != null || solrConfigData != null) {
            start(new SolrDefinition(solrSchemaData, solrConfigData));
        } else {
            start((SolrDefinition) null);
        }
    }

    public void start(SolrDefinition solrDef) throws Exception {
        if (started) {
            throw new IllegalStateException("LilyProxy is already started.");
        } else {
            started = true;
        }

        cleanOldTmpDirs();

        if (hasBeenStarted && this.mode == Mode.EMBED) {
            // In embed mode, we can't support multiple start-stop sequences since
            // HBase/Hadoop does not shut down all processes synchronously.
            throw new IllegalStateException("LilyProxy can only be started once in a JVM when using embed mode.");
        } else {
            hasBeenStarted = true;
        }

        System.out.println("LilyProxy mode: " + mode);

        if (mode == Mode.CONNECT) {
            // First reset the state
            System.out.println("Calling reset state flag on externally launched Lily...");
            try {
                String hostport = "localhost:10102";
                JMXServiceURL url = new JMXServiceURL(
                        "service:jmx:rmi://" + hostport + "/jndi/rmi://" + hostport + "/jmxrmi");
                JMXConnector connector = JMXConnectorFactory.connect(url);
                connector.connect();
                ObjectName lilyLauncher = new ObjectName("LilyLauncher:name=Launcher");
                connector.getMBeanServerConnection().invoke(lilyLauncher, "resetLilyState", new Object[0],
                        new String[0]);
                connector.close();
            } catch (Exception e) {
                throw new Exception("Resetting Lily state failed.", e);
            }
            System.out.println("State reset done.");
        }

        if (mode == Mode.EMBED || mode == Mode.HADOOP_CONNECT) {
            if (testHome == null) {
                testHome = TestHomeUtil.createTestHome(TEMP_DIR_PREFIX);
            }

            if (mode == Mode.EMBED) {
                hbaseProxy.setTestHome(new File(testHome, TemplateDir.HADOOP_DIR));
            }
            solrProxy.setTestHome(new File(testHome, TemplateDir.SOLR_DIR));
            lilyServerProxy.setTestHome(new File(testHome, TemplateDir.LILYSERVER_DIR));
        }

        if (mode == Mode.EMBED
                && Boolean.parseBoolean(System.getProperty(RESTORE_TEMPLATE_DIR_PROP_NAME, "true"))) {
            TemplateDir.restoreTemplateDir(testHome);
        }

        hbaseProxy.start();
        solrProxy.start(solrDef);
        lilyServerProxy.start();
        hbaseIndexerLauncherService.start(Collections.<String>emptyList());
    }

    public void stop() throws Exception {
        Closer.close(hbaseIndexerLauncherService);
        Closer.close(lilyServerProxy);
        Closer.close(solrProxy);
        Closer.close(hbaseProxy);

        if (clearData && testHome != null) {
            try {
                FileUtils.deleteDirectory(testHome);
            } catch (IOException e) {
                // We're logging this instead of throwing the exception
                // since deleting the folder often fails in Windows.
                // Throwing the exception would also fail the testcase although
                // it is only the cleanup of the temporary folder that failed.
                System.out.println("Warning! LilyProxy.stop() failed to delete folder: "
                        + testHome.getAbsolutePath() + ", " + e.getMessage());
            }
        }

        started = false;
    }

    public void setTestHome(File testHome) throws IOException {
        if (mode != Mode.EMBED) {
            throw new RuntimeException("testHome should only be set when mode is EMBED");
        }
        this.testHome = testHome;
        System.setProperty("test.build.data", testHome.getAbsolutePath());
    }

    public File getTestHome() {
        return testHome;
    }

    public void cleanOldTmpDirs() {
        if (clearData) {
            File tempDirectory = FileUtils.getTempDirectory();
            File[] files = tempDirectory.listFiles((FilenameFilter) new PrefixFileFilter(TEMP_DIR_PREFIX));
            for (File file : files) {
                FileUtils.deleteQuietly(file);
            }
        }
    }

    public HBaseProxy getHBaseProxy() {
        return hbaseProxy;
    }

    public LilyServerProxy getLilyServerProxy() {
        return lilyServerProxy;
    }

    public SolrProxy getSolrProxy() {
        return solrProxy;
    }

    /**
     * Waits for all SEP events to be processed and if successful commits the solr index.
     *
     * <p>The canonical usage in tests is along these lines:</p>
     *
     * <pre>Assert.assertTrue("Processing events took too long", lilyProxy.waitSepEventsProcessed(60000L));</pre>
     *
     * @param timeout the maximum time to wait
     * @return false if the timeout was reached before all events were processed
     */
    public boolean waitSepEventsProcessed(long timeout) throws Exception {
        return waitSepEventsProcessed(timeout, true);
    }

    /**
     * Waits for all SEP events to be processed and optionally commits the solr index.
     *
     * @param timeout the maximum time to wait
     * @return false if the timeout was reached before all events were processed
     */
    public boolean waitSepEventsProcessed(long timeout, boolean commitSolr) throws Exception {
        boolean success = hbaseProxy.waitOnReplication(timeout);
        if (success && commitSolr) {
            solrProxy.commit();
        }
        return success;
    }

    public Main getHBaseIndexerService() {
        return hbaseIndexerLauncherService.getHbaseIndexerService();
    }
}