net.revelc.code.zookeeper.maven.plugin.StartZooKeeperMojo.java Source code

Java tutorial

Introduction

Here is the source code for net.revelc.code.zookeeper.maven.plugin.StartZooKeeperMojo.java

Source

/*
 * 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 net.revelc.code.zookeeper.maven.plugin;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Properties;
import java.util.Scanner;
import java.util.UUID;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.codehaus.plexus.util.FileUtils;

/**
 * Starts a service which runs the ZooKeeper server.
 */
@Mojo(name = "start", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, threadSafe = true)
public class StartZooKeeperMojo extends AbstractZooKeeperMojo {

    /**
     * The directory to use to store plugin data and state.
     *
     * @since 1.1.0
     */
    @Parameter(alias = "directory", property = "zmp.directory", defaultValue = "${project.build.directory}/zmp")
    protected File zmpDir;

    /**
     * The port on which to run the ZooKeeper server.
     *
     * @since 1.0.0
     */
    @Parameter(alias = "clientPort", required = true, property = "zmp.clientPort", defaultValue = "2181")
    protected int clientPort;

    /**
     * The tickTime ZooKeeper option
     *
     * @since 1.0.0
     */
    @Parameter(alias = "tickTime", property = "zmp.tickTime", defaultValue = "2000")
    protected int tickTime;

    /**
     * The initLimit ZooKeeper option
     *
     * @since 1.0.0
     */
    @Parameter(alias = "initLimit", property = "zmp.initLimit", defaultValue = "10")
    protected int initLimit;

    /**
     * The syncLimit ZooKeeper option
     *
     * @since 1.0.0
     */
    @Parameter(alias = "syncLimit", property = "zmp.syncLimit", defaultValue = "5")
    protected int syncLimit;

    /**
     * The maximum number of concurrent client connections to ZooKeeper.
     *
     * @since 1.0.0
     */
    @Parameter(alias = "maxClientCnxns", property = "zmp.maxClientCnxns", defaultValue = "100")
    protected int maxClientCnxns;

    /**
     * Keep previous ZooKeeper data and state. Best used with non-default directory.
     *
     * @since 1.1.0
     */
    @Parameter(alias = "keepPreviousState", property = "zmp.keepPreviousState", defaultValue = "false")
    protected boolean keepPreviousState;

    private File baseDir;
    private File dataDir;

    @Override
    protected void runMojo() throws MojoExecutionException, MojoFailureException {
        parseConfig();

        ProcessBuilder builder = new ProcessBuilder();
        builder.command().add(getJavaCommand());

        String classpath = getClasspath();
        getLog().warn(classpath);
        if (!classpath.isEmpty()) {
            builder.command().add("-cp");
            builder.command().add(classpath);
        }

        builder.command().add(ZooKeeperLauncher.class.getName());
        builder.command().add("--shutdownPort");
        builder.command().add(Integer.toString(shutdownPort));
        builder.command().add("--shutdownString");
        builder.command().add(shutdownString);

        String token = UUID.randomUUID().toString();
        builder.command().add("--token");
        builder.command().add(token);

        File zooCfgFile = createZooCfg();
        builder.command().add("--zoocfg");
        builder.command().add(zooCfgFile.getAbsolutePath());

        builder.directory(project.getBasedir());
        getLog().info("Starting ZooKeeper");

        Process forkedProcess = null;
        try {
            // merge stderr and stdout from child
            builder.redirectErrorStream(true);
            forkedProcess = builder.start();
            try (Scanner scanner = new Scanner(forkedProcess.getInputStream(), UTF_8.name())) {
                getLog().info("Waiting for ZooKeeper service to start...");
                int checklines = 50;
                boolean verifiedStart = false;
                while (scanner.hasNextLine() && checklines > 0) {
                    String line = scanner.nextLine();
                    getLog().debug("LINE: " + line);
                    if (line.contains("Token: " + token)) {
                        verifiedStart = true;
                        break;
                    }
                    checklines--;
                }
                boolean canConnect = false;
                Watcher noopWatcher = new Watcher() {
                    @Override
                    public void process(WatchedEvent event) {
                    }
                };
                while (!canConnect) {
                    ZooKeeper zk = null;
                    try {
                        String address = clientPortAddress + ":" + clientPort;
                        getLog().info("Waiting for ZooKeeper on " + address + "...");
                        zk = new ZooKeeper(address, tickTime, noopWatcher);
                        zk.getChildren("/", false);
                        getLog().info("ZooKeeper is running on " + address + ".");
                        canConnect = true;
                    } catch (Exception e) {
                        getLog().info("ZooKeeper not yet ready: " + e.getMessage());
                        getLog().debug("ZooKeeper not yet ready: " + e.getMessage(), e);
                    } finally {
                        if (zk != null) {
                            try {
                                zk.close();
                            } catch (InterruptedException e) {
                                // don't care
                            }
                        }
                    }
                }
                if (verifiedStart) {
                    getLog().info("ZooKeeper service has started");
                } else {
                    getLog().warn("Unable to verify ZooKeeper service started");
                }
            }
        } catch (IOException e) {
            throw new MojoFailureException("Unable to start process (or verify that it has started)", e);
        }
    }

    private void parseConfig() throws MojoExecutionException {
        if (!zmpDir.mkdirs() && !zmpDir.isDirectory()) {
            throw new MojoExecutionException("Can't create " + "plugin directory: " + zmpDir.getAbsolutePath());
        }
        baseDir = new File(zmpDir, clientPortAddress + "_" + clientPort);
        if (!keepPreviousState) {
            try {
                FileUtils.deleteDirectory(baseDir);
            } catch (IOException e) {
                throw new MojoExecutionException("Can't clean " + "plugin directory: " + baseDir.getAbsolutePath());
            }
        }
        if (!baseDir.mkdirs() && !baseDir.isDirectory()) {
            throw new MojoExecutionException("Can't create plugin directory: " + baseDir.getAbsolutePath());
        }
        dataDir = new File(baseDir, "data");
        if (!keepPreviousState) {
            try {
                FileUtils.deleteDirectory(dataDir);
            } catch (IOException e) {
                throw new MojoExecutionException("Can't clean data directory: " + baseDir.getAbsolutePath());
            }
        }
    }

    private File createZooCfg() throws MojoExecutionException, MojoFailureException {
        File confDir = new File(baseDir, "conf");
        if (!confDir.mkdirs() && !confDir.isDirectory()) {
            throw new MojoExecutionException("Can't create configuration directory: " + confDir.getAbsolutePath());
        }

        File zooCfgFile = new File(confDir, "zoo.cfg");
        if (zooCfgFile.exists() && !zooCfgFile.delete()) {
            throw new MojoExecutionException(
                    "Can't delete existing configuration file: " + zooCfgFile.getAbsolutePath());
        }

        Properties zooCfg = new Properties();
        zooCfg.setProperty("tickTime", tickTime + "");
        zooCfg.setProperty("initLimit", initLimit + "");
        zooCfg.setProperty("syncLimit", syncLimit + "");
        zooCfg.setProperty("clientPortAddress", clientPortAddress);
        zooCfg.setProperty("clientPort", clientPort + "");
        zooCfg.setProperty("maxClientCnxns", maxClientCnxns + "");
        zooCfg.setProperty("dataDir", dataDir.getAbsolutePath());

        try (Writer fileWriter = new OutputStreamWriter(new FileOutputStream(zooCfgFile), UTF_8)) {
            zooCfg.store(fileWriter, null);
        } catch (IOException e) {
            throw new MojoFailureException("Unable to create " + zooCfgFile.getAbsolutePath(), e);
        }
        return zooCfgFile;
    }

    private String getJavaCommand() {
        return System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";

    }

    private String getClasspath() {
        StringBuilder classpath = new StringBuilder();
        String delim = File.pathSeparator;
        classpath.append(plugin.getPluginArtifact().getFile().getAbsolutePath());
        for (Artifact artifact : plugin.getArtifacts()) {
            if ("jar".equals(artifact.getType()) && !"provided".equals(artifact.getScope())) {
                classpath.append(delim).append(artifact.getFile().getAbsolutePath());
            }
        }
        return classpath.toString();
    }
}