blob: 2fd57b31f49abe4274bbbaf0b79deb4f993024fc [file] [log] [blame]
/*
* 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 java.lang.String.format;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.brooklyn.entity.software.base.lifecycle.ScriptHelper;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.file.ArchiveBuilder;
import org.apache.brooklyn.util.core.file.ArchiveUtils;
import org.apache.brooklyn.util.core.internal.ssh.SshTool;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.net.Urls;
import org.apache.brooklyn.util.os.Os;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.text.StringEscapes.BashStringEscapes;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* The SSH implementation of the {@link VanillaJavaAppDriver}.
*/
public class VanillaJavaAppSshDriver extends JavaSoftwareProcessSshDriver implements VanillaJavaAppDriver {
// FIXME this should be a config, either on the entity or -- probably better --
// an alternative / override timeout on the SshTool for file copy commands
final static int NUM_RETRIES_FOR_COPYING = 4;
public VanillaJavaAppSshDriver(VanillaJavaAppImpl entity, SshMachineLocation machine) {
super(entity, machine);
}
@Override
public VanillaJavaAppImpl getEntity() {
return (VanillaJavaAppImpl) super.getEntity();
}
@Override
protected String getLogFileLocation() {
return Os.mergePathsUnix(getRunDir(), "console");
}
@Override
public void install() {
newScript(INSTALLING).execute();
}
@Override
public void customize() {
newScript(CUSTOMIZING)
.body.append(format("mkdir -p %s/lib", getRunDir()))
.failOnNonZeroResultCode()
.execute();
SshMachineLocation machine = getMachine();
VanillaJavaApp entity = getEntity();
for (String entry : entity.getClasspath()) {
// If a local folder, then create archive from contents first
if (Urls.isDirectory(entry)) {
File jarFile = ArchiveBuilder.jar().addDirContentsAt(new File(entry), "").create();
entry = jarFile.getAbsolutePath();
}
// Determine filename
String destFile = entry.contains("?") ? entry.substring(0, entry.indexOf('?')) : entry;
destFile = destFile.substring(destFile.lastIndexOf('/') + 1);
ArchiveUtils.deploy(MutableMap.<String, Object>of(), entry, machine, getRunDir(), Os.mergePaths(getRunDir(), "lib"), destFile);
}
ScriptHelper helper = newScript(CUSTOMIZING+"-classpath")
.body.append(String.format("ls -1 \"%s\"", Os.mergePaths(getRunDir(), "lib")))
.gatherOutput();
helper.setFlag(SshTool.PROP_NO_EXTRA_OUTPUT, true);
int result = helper.execute();
if (result != 0) {
throw new IllegalStateException("Error listing classpath files: " + helper.getResultStderr());
}
String stdout = helper.getResultStdout();
// Transform stdout into list of files in classpath
if (Strings.isBlank(stdout)) {
getEntity().setAttribute(VanillaJavaApp.CLASSPATH_FILES, ImmutableList.of(Os.mergePaths(getRunDir(), "lib")));
} else {
// FIXME Cannot handle spaces in paths properly
Iterable<String> lines = Splitter.on(CharMatcher.BREAKING_WHITESPACE).omitEmptyStrings().trimResults().split(stdout);
Iterable<String> files = Iterables.transform(lines, new Function<String, String>() {
@Override
public String apply(@Nullable String input) {
return Os.mergePathsUnix(getRunDir(), "lib", input);
}
});
getEntity().setAttribute(VanillaJavaApp.CLASSPATH_FILES, ImmutableList.copyOf(files));
}
}
public String getClasspath() {
@SuppressWarnings("unchecked")
List<String> files = getEntity().getAttribute(VanillaJavaApp.CLASSPATH_FILES);
if (files == null || files.isEmpty()) {
return null;
} else {
return Joiner.on(":").join(files);
}
}
@Override
public void launch() {
String clazz = getEntity().getMainClass();
String args = getArgs();
newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
.body.append(
format("echo \"launching: java $JAVA_OPTS %s %s\"", clazz, args),
format("java $JAVA_OPTS -cp \"%s\" %s %s >> %s/console 2>&1 </dev/null &", getClasspath(), clazz, args, getRunDir())
)
.execute();
}
public String getArgs(){
List<Object> args = getEntity().getConfig(VanillaJavaApp.ARGS);
StringBuilder sb = new StringBuilder();
Iterator<Object> it = args.iterator();
while (it.hasNext()) {
Object argO = it.next();
try {
String arg = Tasks.resolveValue(argO, String.class, getEntity().getExecutionContext());
BashStringEscapes.assertValidForDoubleQuotingInBash(arg);
sb.append(format("\"%s\"",arg));
} catch (Exception e) {
throw Exceptions.propagate(e);
}
if (it.hasNext()) {
sb.append(" ");
}
}
return sb.toString();
}
@Override
public boolean isRunning() {
int result = newScript(MutableMap.of(USE_PID_FILE, true), CHECK_RUNNING).execute();
return result == 0;
}
@Override
public void stop() {
newScript(MutableMap.of(USE_PID_FILE, true), STOPPING).execute();
}
@Override
public void kill() {
newScript(MutableMap.of(USE_PID_FILE, true), KILLING).execute();
}
@Override
protected Map getCustomJavaSystemProperties() {
return MutableMap.builder()
.putAll(super.getCustomJavaSystemProperties())
.putAll(getEntity().getJvmDefines())
.build();
}
@Override
protected List<String> getCustomJavaConfigOptions() {
return MutableList.<String>builder()
.addAll(super.getCustomJavaConfigOptions())
.addAll(getEntity().getJvmXArgs())
.build();
}
@Override
public Map<String,String> getShellEnvironment() {
return MutableMap.<String,String>builder()
.putAll(super.getShellEnvironment())
.putIfNotNull("CLASSPATH", getClasspath())
.build();
}
}