| /* |
| */ |
| package org.taverna.server.master.localworker; |
| /* |
| * 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. |
| */ |
| |
| import static java.io.File.separator; |
| import static java.lang.System.getProperty; |
| import static java.rmi.registry.Registry.REGISTRY_PORT; |
| import static java.util.Arrays.asList; |
| import static java.util.Collections.emptyList; |
| import static java.util.Collections.unmodifiableList; |
| import static org.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS; |
| import static org.taverna.server.master.defaults.Default.PASSWORD_FILE; |
| import static org.taverna.server.master.defaults.Default.REGISTRY_JAR; |
| import static org.taverna.server.master.defaults.Default.RMI_PREFIX; |
| import static org.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES; |
| import static org.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT; |
| import static org.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR; |
| import static org.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR; |
| import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP; |
| import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT; |
| import static org.taverna.server.master.localworker.PersistedState.KEY; |
| import static org.taverna.server.master.localworker.PersistedState.makeInstance; |
| |
| import java.io.File; |
| import java.io.FilenameFilter; |
| import java.net.URI; |
| import java.util.List; |
| |
| import javax.annotation.PostConstruct; |
| import javax.jdo.annotations.PersistenceAware; |
| |
| import org.springframework.beans.factory.annotation.Required; |
| import org.taverna.server.master.common.Status; |
| import org.taverna.server.master.defaults.Default; |
| import org.taverna.server.master.utils.JDOSupport; |
| import org.taverna.server.master.worker.WorkerModel; |
| |
| /** |
| * The persistent state of a local worker factory. |
| * |
| * @author Donal Fellows |
| */ |
| @PersistenceAware |
| public class LocalWorkerState extends JDOSupport<PersistedState> implements |
| WorkerModel { |
| public LocalWorkerState() { |
| super(PersistedState.class); |
| } |
| |
| private LocalWorkerState self; |
| |
| @Required |
| public void setSelf(LocalWorkerState self) { |
| this.self = self; |
| } |
| |
| /** Initial lifetime of runs, in minutes. */ |
| int defaultLifetime; |
| /** |
| * Maximum number of runs to exist at once. Note that this includes when |
| * they are just existing for the purposes of file transfer ( |
| * {@link Status#Initialized}/{@link Status#Finished} states). |
| */ |
| int maxRuns; |
| /** |
| * Prefix to use for RMI names. |
| */ |
| String factoryProcessNamePrefix; |
| /** |
| * Full path name of the script used to start running a workflow; normally |
| * expected to be "<i>somewhere/</i><tt>executeWorkflow.sh</tt>". |
| */ |
| String executeWorkflowScript; |
| /** Default value for {@link #executeWorkflowScript}. */ |
| private transient String defaultExecuteWorkflowScript; |
| /** |
| * Full path name of the file containing the password used to launch workers |
| * as other users. The file is normally expected to contain a single line, |
| * the password, and to be thoroughly locked down so only the user running |
| * the server (e.g., "<tt>tomcat</tt>") can read it; it will probably reside |
| * in either the user's home directory or in a system configuration |
| * directory. |
| */ |
| String passwordFile; |
| /** Default value for {@link #passwordFile}. */ |
| private transient String defaultPasswordFile = PASSWORD_FILE; |
| /** |
| * The extra arguments to pass to the subprocess. |
| */ |
| String[] extraArgs; |
| /** |
| * How long to wait for subprocess startup, in seconds. |
| */ |
| int waitSeconds; |
| /** |
| * Polling interval to use during startup, in milliseconds. |
| */ |
| int sleepMS; |
| /** |
| * Full path name to the worker process's implementation JAR. |
| */ |
| String serverWorkerJar; |
| private static final String DEFAULT_WORKER_JAR = LocalWorkerState.class |
| .getClassLoader().getResource(SERVER_WORKER_IMPLEMENTATION_JAR) |
| .getFile(); |
| /** |
| * Full path name to the Java binary to use to run the subprocess. |
| */ |
| String javaBinary; |
| private static final String DEFAULT_JAVA_BINARY = getProperty("java.home") |
| + separator + "bin" + separator + "java"; |
| /** |
| * Full path name to the secure fork process's implementation JAR. |
| */ |
| String serverForkerJar; |
| private static final String DEFAULT_FORKER_JAR = LocalWorkerState.class |
| .getClassLoader().getResource(SECURE_FORK_IMPLEMENTATION_JAR) |
| .getFile(); |
| |
| String registryHost; |
| int registryPort; |
| |
| int operatingLimit; |
| |
| URI[] permittedWorkflows; |
| private String registryJar; |
| private static final String DEFAULT_REGISTRY_JAR = LocalWorkerState.class |
| .getClassLoader().getResource(REGISTRY_JAR).getFile(); |
| |
| @Override |
| public void setDefaultLifetime(int defaultLifetime) { |
| this.defaultLifetime = defaultLifetime; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public int getDefaultLifetime() { |
| return defaultLifetime < 1 ? RUN_LIFE_MINUTES : defaultLifetime; |
| } |
| |
| @Override |
| public void setMaxRuns(int maxRuns) { |
| this.maxRuns = maxRuns; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public int getMaxRuns() { |
| return maxRuns < 1 ? Default.RUN_COUNT_MAX : maxRuns; |
| } |
| |
| @Override |
| public int getOperatingLimit() { |
| return operatingLimit < 1 ? RUN_OPERATING_LIMIT : operatingLimit; |
| } |
| |
| @Override |
| public void setOperatingLimit(int operatingLimit) { |
| this.operatingLimit = operatingLimit; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) { |
| this.factoryProcessNamePrefix = factoryProcessNamePrefix; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getFactoryProcessNamePrefix() { |
| return factoryProcessNamePrefix == null ? RMI_PREFIX |
| : factoryProcessNamePrefix; |
| } |
| |
| @Override |
| public void setExecuteWorkflowScript(String executeWorkflowScript) { |
| this.executeWorkflowScript = executeWorkflowScript; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getExecuteWorkflowScript() { |
| return executeWorkflowScript == null ? defaultExecuteWorkflowScript |
| : executeWorkflowScript; |
| } |
| |
| private static String guessWorkflowScript() { |
| File utilDir = new File(DEFAULT_WORKER_JAR).getParentFile(); |
| File[] dirs = utilDir.listFiles(new FilenameFilter() { |
| @Override |
| public boolean accept(File dir, String name) { |
| // Support both taverna-commandline* (2.5) and |
| // taverna-command-line* (3.1) |
| return name.startsWith("taverna-command"); |
| } |
| }); |
| assert dirs.length > 0; |
| return new File(dirs[0], "executeworkflow.sh").toString(); |
| } |
| |
| /** |
| * Set what executeworkflow script to use by default. This is the value that |
| * is used if not overridden by the administration interface. |
| * |
| * @param defaultScript |
| * Full path to the script to use. |
| */ |
| public void setDefaultExecuteWorkflowScript(String defaultScript) { |
| if (defaultScript.startsWith("${") || defaultScript.equals("NONE")) { |
| this.defaultExecuteWorkflowScript = guessWorkflowScript(); |
| return; |
| } |
| this.defaultExecuteWorkflowScript = defaultScript; |
| } |
| |
| String getDefaultExecuteWorkflowScript() { |
| return defaultExecuteWorkflowScript; |
| } |
| |
| @Override |
| public void setExtraArgs(String[] extraArgs) { |
| this.extraArgs = extraArgs.clone(); |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String[] getExtraArgs() { |
| return extraArgs == null ? EXTRA_ARGUMENTS : extraArgs.clone(); |
| } |
| |
| @Override |
| public void setWaitSeconds(int waitSeconds) { |
| this.waitSeconds = waitSeconds; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public int getWaitSeconds() { |
| return waitSeconds < 1 ? SUBPROCESS_START_WAIT : waitSeconds; |
| } |
| |
| @Override |
| public void setSleepMS(int sleepMS) { |
| this.sleepMS = sleepMS; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public int getSleepMS() { |
| return sleepMS < 1 ? SUBPROCESS_START_POLL_SLEEP : sleepMS; |
| } |
| |
| @Override |
| public void setServerWorkerJar(String serverWorkerJar) { |
| this.serverWorkerJar = serverWorkerJar; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getServerWorkerJar() { |
| return serverWorkerJar == null ? DEFAULT_WORKER_JAR : serverWorkerJar; |
| } |
| |
| @Override |
| public void setServerForkerJar(String serverForkerJar) { |
| this.serverForkerJar = serverForkerJar; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getServerForkerJar() { |
| return serverForkerJar == null ? DEFAULT_FORKER_JAR : serverForkerJar; |
| } |
| |
| @Override |
| public void setJavaBinary(String javaBinary) { |
| this.javaBinary = javaBinary; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getJavaBinary() { |
| return javaBinary == null ? DEFAULT_JAVA_BINARY : javaBinary; |
| } |
| |
| @Override |
| public void setPasswordFile(String passwordFile) { |
| this.passwordFile = passwordFile; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getPasswordFile() { |
| return passwordFile == null ? defaultPasswordFile : passwordFile; |
| } |
| |
| void setDefaultPasswordFile(String defaultPasswordFile) { |
| this.defaultPasswordFile = defaultPasswordFile; |
| } |
| |
| @Override |
| public void setRegistryHost(String registryHost) { |
| this.registryHost = (registryHost == null ? "" : registryHost); |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public String getRegistryHost() { |
| return (registryHost == null || registryHost.isEmpty()) ? null |
| : registryHost; |
| } |
| |
| @Override |
| public void setRegistryPort(int registryPort) { |
| this.registryPort = ((registryPort < 1 || registryPort > 65534) ? REGISTRY_PORT |
| : registryPort); |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public int getRegistryPort() { |
| return registryPort == 0 ? REGISTRY_PORT : registryPort; |
| } |
| |
| @Override |
| public String getRegistryJar() { |
| return registryJar == null ? DEFAULT_REGISTRY_JAR : registryJar; |
| } |
| |
| @Override |
| public void setRegistryJar(String rmiRegistryJar) { |
| this.registryJar = (rmiRegistryJar == null || rmiRegistryJar.isEmpty()) ? null |
| : rmiRegistryJar; |
| if (loadedState) |
| self.store(); |
| } |
| |
| @Override |
| public List<URI> getPermittedWorkflowURIs() { |
| if (permittedWorkflows == null || permittedWorkflows.length == 0) |
| return emptyList(); |
| return unmodifiableList(asList(permittedWorkflows)); |
| } |
| |
| @Override |
| public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) { |
| if (permittedWorkflows == null || permittedWorkflows.isEmpty()) |
| this.permittedWorkflows = new URI[0]; |
| else |
| this.permittedWorkflows = permittedWorkflows |
| .toArray(new URI[permittedWorkflows.size()]); |
| if (loadedState) |
| self.store(); |
| } |
| |
| public static final boolean DEFAULT_GENERATE_PROVENANCE = false; |
| private Boolean generateProvenance; |
| |
| @Override |
| public boolean getGenerateProvenance() { |
| Boolean g = generateProvenance; |
| return g == null ? DEFAULT_GENERATE_PROVENANCE : (boolean) g; |
| } |
| |
| @Override |
| public void setGenerateProvenance(boolean generate) { |
| this.generateProvenance = generate; |
| if (loadedState) |
| self.store(); |
| } |
| |
| // -------------------------------------------------------------- |
| |
| private boolean loadedState; |
| |
| @PostConstruct |
| @WithinSingleTransaction |
| public void load() { |
| if (loadedState || !isPersistent()) |
| return; |
| WorkerModel state = getById(KEY); |
| if (state == null) { |
| store(); |
| return; |
| } |
| |
| defaultLifetime = state.getDefaultLifetime(); |
| executeWorkflowScript = state.getExecuteWorkflowScript(); |
| extraArgs = state.getExtraArgs(); |
| factoryProcessNamePrefix = state.getFactoryProcessNamePrefix(); |
| javaBinary = state.getJavaBinary(); |
| maxRuns = state.getMaxRuns(); |
| serverWorkerJar = state.getServerWorkerJar(); |
| serverForkerJar = state.getServerForkerJar(); |
| passwordFile = state.getPasswordFile(); |
| sleepMS = state.getSleepMS(); |
| waitSeconds = state.getWaitSeconds(); |
| registryHost = state.getRegistryHost(); |
| registryPort = state.getRegistryPort(); |
| operatingLimit = state.getOperatingLimit(); |
| List<URI> pwu = state.getPermittedWorkflowURIs(); |
| permittedWorkflows = (URI[]) pwu.toArray(new URI[pwu.size()]); |
| registryJar = state.getRegistryJar(); |
| generateProvenance = state.getGenerateProvenance(); |
| |
| loadedState = true; |
| } |
| |
| @WithinSingleTransaction |
| public void store() { |
| if (!isPersistent()) |
| return; |
| WorkerModel state = getById(KEY); |
| if (state == null) |
| state = persist(makeInstance()); |
| |
| state.setDefaultLifetime(defaultLifetime); |
| state.setExecuteWorkflowScript(executeWorkflowScript); |
| state.setExtraArgs(extraArgs); |
| state.setFactoryProcessNamePrefix(factoryProcessNamePrefix); |
| state.setJavaBinary(javaBinary); |
| state.setMaxRuns(maxRuns); |
| state.setServerWorkerJar(serverWorkerJar); |
| state.setServerForkerJar(serverForkerJar); |
| state.setPasswordFile(passwordFile); |
| state.setSleepMS(sleepMS); |
| state.setWaitSeconds(waitSeconds); |
| state.setRegistryHost(registryHost); |
| state.setRegistryPort(registryPort); |
| state.setOperatingLimit(operatingLimit); |
| if (permittedWorkflows != null) |
| state.setPermittedWorkflowURIs(asList(permittedWorkflows)); |
| state.setRegistryJar(registryJar); |
| if (generateProvenance != null) |
| state.setGenerateProvenance(generateProvenance); |
| |
| loadedState = true; |
| } |
| } |