/*
 * 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.brooklyn.entity.java;

import static org.apache.brooklyn.util.JavaGroovyEquivalents.groovyTruth;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.core.effector.EffectorTasks;
import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.EntityInternal;
import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.internal.Primitives;

import org.apache.brooklyn.location.ssh.SshMachineLocation;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.core.internal.ssh.ShellTool;
import org.apache.brooklyn.util.core.task.DynamicTasks;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.core.task.ssh.SshTasks;
import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.ssh.BashCommands;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.text.StringEscapes.BashStringEscapes;

/**
 * The SSH implementation of the {@link org.apache.brooklyn.entity.java.JavaSoftwareProcessDriver}.
 */
public abstract class JavaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshDriver implements JavaSoftwareProcessDriver {

    public static final Logger log = LoggerFactory.getLogger(JavaSoftwareProcessSshDriver.class);

    public static final List<List<String>> MUTUALLY_EXCLUSIVE_OPTS = ImmutableList.<List<String>> of(ImmutableList.of("-client",
            "-server"));

    public static final List<String> KEY_VAL_OPT_PREFIXES = ImmutableList.of("-Xmx", "-Xms", "-Xss");

    public JavaSoftwareProcessSshDriver(EntityLocal entity, SshMachineLocation machine) {
        super(entity, machine);

        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFileLocation());
    }

    protected abstract String getLogFileLocation();

    public boolean isJmxEnabled() {
        return (entity instanceof UsesJmx) && (entity.getConfig(UsesJmx.USE_JMX));
    }

    public boolean isJmxSslEnabled() {
        return isJmxEnabled() && groovyTruth(entity.getConfig(UsesJmx.JMX_SSL_ENABLED));
    }

    /**
     * Sets all JVM options (-X.. -D..) in an environment var JAVA_OPTS.
     * <p>
     * That variable is constructed from {@link #getJavaOpts()}, then wrapped _unescaped_ in double quotes. An
     * error is thrown if there is an unescaped double quote in the string. All other unescaped
     * characters are permitted, but unless $var expansion or `command` execution is desired (although
     * this is not confirmed as supported) the generally caller should escape any such characters, for
     * example using {@link BashStringEscapes#escapeLiteralForDoubleQuotedBash(String)}.
     */
    @Override
    public Map<String, String> getShellEnvironment() {
        List<String> javaOpts = getJavaOpts();

        for (String it : javaOpts) {
            BashStringEscapes.assertValidForDoubleQuotingInBash(it);
        }
        // do not double quote here; the env var is double quoted subsequently;
        // spaces should be preceded by double-quote
        // (if dbl quotes are needed we could pass on the command-line instead of in an env var)
        String sJavaOpts = Joiner.on(' ').join(javaOpts);
        return MutableMap.<String, String>builder().putAll(super.getShellEnvironment()).put("JAVA_OPTS", sJavaOpts).build();
    }

    /**
     * arguments to pass to the JVM; this is the config options (e.g. -Xmx1024; only the contents of
     * {@link #getCustomJavaConfigOptions()} by default) and java system properties (-Dk=v; add custom
     * properties in {@link #getCustomJavaSystemProperties()})
     * <p>
     * See {@link #getShellEnvironment()} for discussion of quoting/escaping strategy.
     **/
    public List<String> getJavaOpts() {
        Iterable<String> sysprops = Iterables.transform(getJavaSystemProperties().entrySet(),
                new Function<Map.Entry<String, ?>, String>() {
                    public String apply(Map.Entry<String, ?> entry) {
                        String k = entry.getKey();
                        Object v = entry.getValue();
                        try {
                            if (v != null && Primitives.isWrapperType(v.getClass())) {
                                v = "" + v;
                            } else {
                                v = Tasks.resolveValue(v, Object.class, ((EntityInternal)entity).getExecutionContext());
                                if (v == null) {
                                } else if (v instanceof CharSequence) {
                                } else if (TypeCoercions.isPrimitiveOrBoxer(v.getClass())) {
                                    v = "" + v;
                                } else {
                                    // could do toString, but that's likely not what is desired;
                                    // probably a type mismatch,
                                    // post-processing should be specified (common types are accepted
                                    // above)
                                    throw new IllegalArgumentException("cannot convert value " + v + " of type " + v.getClass()
                                            + " to string to pass as JVM property; use a post-processor");
                                }
                            }
                            return "-D" + k + (v != null ? "=" + v : "");
                        } catch (Exception e) {
                            log.warn("Error resolving java option key {}, propagating: {}", k, e);
                            throw Throwables.propagate(e);
                        }
                    }
                });

        Set<String> result = MutableSet.<String> builder().
                addAll(getJmxJavaConfigOptions()).
                addAll(getCustomJavaConfigOptions()).
                addAll(sysprops).
            build();

        for (String customOpt : entity.getConfig(UsesJava.JAVA_OPTS)) {
            for (List<String> mutuallyExclusiveOpt : MUTUALLY_EXCLUSIVE_OPTS) {
                if (mutuallyExclusiveOpt.contains(customOpt)) {
                    result.removeAll(mutuallyExclusiveOpt);
                }
            }
            for (String keyValOptPrefix : KEY_VAL_OPT_PREFIXES) {
                if (customOpt.startsWith(keyValOptPrefix)) {
                    for (Iterator<String> iter = result.iterator(); iter.hasNext();) {
                        String existingOpt = iter.next();
                        if (existingOpt.startsWith(keyValOptPrefix)) {
                            iter.remove();
                        }
                    }
                }
            }
            if (customOpt.contains("=")) {
                String customOptPrefix = customOpt.substring(0, customOpt.indexOf("="));

                for (Iterator<String> iter = result.iterator(); iter.hasNext();) {
                    String existingOpt = iter.next();
                    if (existingOpt.startsWith(customOptPrefix)) {
                        iter.remove();
                    }
                }
            }
            result.add(customOpt);
        }

        return ImmutableList.copyOf(result);
    }

    /**
     * Returns the complete set of Java system properties (-D defines) to set for the application.
     * <p>
     * This is exposed to the JVM as the contents of the {@code JAVA_OPTS} environment variable. Default
     * set contains config key, custom system properties, and JMX defines.
     * <p>
     * Null value means to set -Dkey otherwise it is -Dkey=value.
     * <p>
     * See {@link #getShellEnvironment()} for discussion of quoting/escaping strategy.
     */
    protected Map<String,?> getJavaSystemProperties() {
        return MutableMap.<String,Object>builder()
                .putAll(getCustomJavaSystemProperties())
                .putAll(isJmxEnabled() ? getJmxJavaSystemProperties() : Collections.<String,Object>emptyMap())
                .putAll(entity.getConfig(UsesJava.JAVA_SYSPROPS))
                .build();
    }

    /**
     * Return extra Java system properties (-D defines) used by the application.
     *
     * Override as needed; default is an empty map.
     */
    protected Map getCustomJavaSystemProperties() {
        return Maps.newLinkedHashMap();
    }

    /**
     * Return extra Java config options, ie arguments starting with - which are passed to the JVM prior
     * to the class name.
     * <p>
     * Note defines are handled separately, in {@link #getCustomJavaSystemProperties()}.
     * <p>
     * Override as needed; default is an empty list.
     */
    protected List<String> getCustomJavaConfigOptions() {
        return Lists.newArrayList();
    }

    /** @deprecated since 0.6.0, the config key is always used instead of this */ @Deprecated
    public Integer getJmxPort() {
        return !isJmxEnabled() ? Integer.valueOf(-1) : entity.getAttribute(UsesJmx.JMX_PORT);
    }

    /** @deprecated since 0.6.0, the config key is always used instead of this */ @Deprecated
    public Integer getRmiRegistryPort() {
        return !isJmxEnabled() ? -1 : entity.getAttribute(UsesJmx.RMI_REGISTRY_PORT);
    }

    /** @deprecated since 0.6.0, the config key is always used instead of this */ @Deprecated
    public String getJmxContext() {
        return !isJmxEnabled() ? null : entity.getAttribute(UsesJmx.JMX_CONTEXT);
    }

    /**
     * Return the configuration properties required to enable JMX for a Java application.
     *
     * These should be set as properties in the {@code JAVA_OPTS} environment variable when calling the
     * run script for the application.
     */
    protected Map<String, ?> getJmxJavaSystemProperties() {
        MutableMap.Builder<String, Object> result = MutableMap.<String, Object> builder();

        if (isJmxEnabled()) {
            new JmxSupport(getEntity(), getRunDir()).applyJmxJavaSystemProperties(result);
        }

        return result.build();
    }

    /**
     * Return any JVM arguments required, other than the -D defines returned by {@link #getJmxJavaSystemProperties()}
     */
    protected List<String> getJmxJavaConfigOptions() {
        List<String> result = new ArrayList<String>();
        if (isJmxEnabled()) {
            result.addAll(new JmxSupport(getEntity(), getRunDir()).getJmxJavaConfigOptions());
        }
        return result;
    }

    /**
     * Checks for the presence of Java on the entity's location, installing if necessary.
     * @return true if the required version of Java was found on the machine or if it was installed correctly,
     * otherwise false.
     */
    protected boolean checkForAndInstallJava(String requiredVersion) {
        int requiredJavaMinor;
        if (requiredVersion.contains(".")) {
            List<String> requiredVersionParts = Splitter.on(".").splitToList(requiredVersion);
            requiredJavaMinor = Integer.valueOf(requiredVersionParts.get(1));
        } else if (requiredVersion.length() == 1) {
            requiredJavaMinor = Integer.valueOf(requiredVersion);
        } else {
            log.error("java version required {} is not supported", requiredVersion);
            throw new IllegalArgumentException("Required java version " + requiredVersion + " not supported");
        }
        Optional<String> installedJavaVersion = getInstalledJavaVersion();
        if (installedJavaVersion.isPresent()) {
            List<String> installedVersionParts = Splitter.on(".").splitToList(installedJavaVersion.get());
            int javaMajor = Integer.valueOf(installedVersionParts.get(0));
            int javaMinor = Integer.valueOf(installedVersionParts.get(1));
            if (javaMajor == 1 && javaMinor >= requiredJavaMinor) {
                log.debug("Java {} already installed at {}@{}", new Object[]{installedJavaVersion.get(), getEntity(), getLocation()});
                return true;
            }
        }
        return tryJavaInstall(requiredVersion, BashCommands.installJava(requiredJavaMinor)) == 0;
    }

    protected int tryJavaInstall(String version, String command) {
        getLocation().acquireMutex("installing", "installing Java at " + getLocation());
        try {
            log.debug("Installing Java {} at {}@{}", new Object[]{version, getEntity(), getLocation()});
            ProcessTaskFactory<Integer> taskFactory = SshTasks.newSshExecTaskFactory(getLocation(), command)
                    .summary("install java ("+version+")")
                    .configure(ShellTool.PROP_EXEC_ASYNC, true);
            ProcessTaskWrapper<Integer> installCommand = Entities.submit(getEntity(), taskFactory);
            int result = installCommand.get();
            if (result != 0) {
                log.warn("Installation of Java {} failed at {}@{}: {}",
                        new Object[]{version, getEntity(), getLocation(), installCommand.getStderr()});
            }
            return result;
        } finally {
            getLocation().releaseMutex("installing");
        }
    }

    /**
    * @deprecated since 0.7.0; instead use {@link #getInstalledJavaVersion()}
    */
    @Deprecated
    protected Optional<String> getCurrentJavaVersion() {
        return getInstalledJavaVersion();
    }

    /**
     * Checks for the version of Java installed on the entity's location over SSH.
     * @return An Optional containing the version portion of `java -version`, or absent if no Java found.
     */
    protected Optional<String> getInstalledJavaVersion() {
        log.debug("Checking Java version at {}@{}", getEntity(), getLocation());
        // sed gets stdin like 'java version "1.7.0_45"'
        ProcessTaskWrapper<Integer> versionCommand = Entities.submit(getEntity(), SshTasks.newSshExecTaskFactory(
                getLocation(), "java -version 2>&1 | grep \" version\" | sed 's/.*\"\\(.*\\).*\"/\\1/'"));
        versionCommand.get();
        String stdOut = versionCommand.getStdout().trim();
        if (!Strings.isBlank(stdOut)) {
            log.debug("Found Java version at {}@{}: {}", new Object[] {getEntity(), getLocation(), stdOut});
            return Optional.of(stdOut);
        } else {
            log.debug("Found no Java installed at {}@{}", getEntity(), getLocation());
            return Optional.absent();
        }
    }

    /**
     * Answers one of "OpenJDK", "Oracle", or other vendor info.
     */
    protected Optional<String> getCurrentJavaVendor() {
        // TODO Also handle IBM jvm
        log.debug("Checking Java vendor at {}@{}", getEntity(), getLocation());
        ProcessTaskWrapper<Integer> versionCommand = Entities.submit(getEntity(), SshTasks.newSshExecTaskFactory(
                getLocation(), "java -version 2>&1 | awk 'NR==2 {print $1}'"));
        versionCommand.get();
        String stdOut = versionCommand.getStdout().trim();
        if (Strings.isBlank(stdOut)) {
            log.debug("Found no Java installed at {}@{}", getEntity(), getLocation());
            return Optional.absent();
        } else if ("Java(TM)".equals(stdOut)) {
            log.debug("Found Java version at {}@{}: {}", new Object[] {getEntity(), getLocation(), stdOut});
            return Optional.of("Oracle");
        } else {
            return Optional.of(stdOut);
        }
    }

    /**
     * Checks for Java 6 or 7, installing Java 7 if neither are found. Override this method to
     * check for and install specific versions of Java.
     *
     * @see #checkForAndInstallJava(String)
     */
    public boolean installJava() {
        if (entity instanceof UsesJava) {
            String version = entity.getConfig(UsesJava.JAVA_VERSION_REQUIRED);
            return checkForAndInstallJava(version);
        }
        // by default it installs jdk7
        return checkForAndInstallJava("1.7");
    }

    public void installJmxSupport() {
        if (isJmxEnabled()) {
            newScript("JMX_SETUP_PREINSTALL").body.append("mkdir -p "+getRunDir()).execute();
            new JmxSupport(getEntity(), getRunDir()).install();
        }
    }

    public void checkJavaHostnameBug() {
        checkNoHostnameBug();

        try {
            ProcessTaskWrapper<Integer> hostnameTask = DynamicTasks.queue(SshEffectorTasks.ssh("echo FOREMARKER; hostname -f; echo AFTMARKER")).block();
            String stdout = Strings.getFragmentBetween(hostnameTask.getStdout(), "FOREMARKER", "AFTMARKER");
            if (hostnameTask.getExitCode() == 0 && Strings.isNonBlank(stdout)) {
                String hostname = stdout.trim();
                Integer len = hostname.length();
                if (len > 63) {
                    // likely to cause a java crash due to java bug 7089443 -- set a new short hostname
                    // http://mail.openjdk.java.net/pipermail/net-dev/2012-July/004603.html
                    String newHostname = "br-"+getEntity().getId().toLowerCase();
                    log.info("Detected likelihood of Java hostname bug with hostname length "+len+" for "+getEntity()+"; renaming "+getMachine()+"  to hostname "+newHostname);
                    DynamicTasks.queue(SshEffectorTasks.ssh(BashCommands.setHostname(newHostname, null))).block();
                }
            } else {
                log.debug("Hostname length could not be determined for location "+EffectorTasks.findSshMachine()+"; not doing Java hostname bug check");
            }
        } catch (Exception e) {
            Exceptions.propagateIfFatal(e);
            log.warn("Error checking/fixing Java hostname bug (continuing): "+e, e);
        }
    }

    @Override
    public void setup() {
        DynamicTasks.queue("install java", new Runnable() { public void run() {
            installJava();
        }});

        // TODO check java version

        if (getEntity().getConfig(UsesJava.CHECK_JAVA_HOSTNAME_BUG)) {
            DynamicTasks.queue("check java hostname bug", new Runnable() { public void run() {
                checkJavaHostnameBug(); }});
        }
    }

    @Override
    public void copyRuntimeResources() {
        super.copyRuntimeResources();

        if (isJmxEnabled()) {
            DynamicTasks.queue("install jmx", new Runnable() { public void run() {
                installJmxSupport(); }});
        }
    }

}
