Java tutorial
/* * Copyright 2015 Adaptris Ltd. * * 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 com.adaptris.core.services.system; import java.io.OutputStream; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.validation.Valid; import javax.validation.constraints.NotNull; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteWatchdog; import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; import com.adaptris.annotation.AdapterComponent; import com.adaptris.annotation.AdvancedConfig; import com.adaptris.annotation.AutoPopulated; import com.adaptris.annotation.ComponentProfile; import com.adaptris.annotation.DisplayOrder; import com.adaptris.core.AdaptrisMessage; import com.adaptris.core.CoreException; import com.adaptris.core.ServiceException; import com.adaptris.core.ServiceImp; import com.adaptris.core.util.Args; import com.adaptris.core.util.ExceptionHelper; import com.adaptris.util.TimeInterval; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * Service that runs the specified system executable with the provided arguments, optionally capturing the output. * * <p> * Note that no checking is peformed on the command to be executed; it will be executed as-is. If used in combination with * {@link com.adaptris.core.services.dynamic.DynamicServiceExecutor} or {@link * com.adaptris.core.services.dynamic.DynamicServiceLocator} then you might have a large security hole if it is improperly * configured or validated. * </p> * <p> * The following behaviour is non-configurable: * <ul> * <li>The exitcode is stored against the metadata key {@value #COMMAND_RETURN_VALUE_METADATA_KEY} if the service does not throw an * exception.</li> * <li>If a timeout occurs then a ServiceException is thrown, output that was captured before the timeout should still be * available</li> * </ul> * </p> * * @config system-command-executor * */ @XStreamAlias("system-command-executor") @AdapterComponent @ComponentProfile(summary = "Execute an arbitrary system command (DANGER!)", tag = "service") @DisplayOrder(order = { "commandBuilder", "outputCapture", "timeout" }) public class SystemCommandExecutorService extends ServiceImp { public static final String COMMAND_RETURN_VALUE_METADATA_KEY = "SystemCommandExecutorService.ReturnValue"; private static final TimeInterval DEFAULT_TIMEOUT = new TimeInterval(30L, TimeUnit.SECONDS); @Valid @AdvancedConfig private TimeInterval timeout; @NotNull @AutoPopulated @Valid private CommandBuilder commandBuilder; @NotNull @Valid @AutoPopulated private CommandOutputCapture outputCapture; public SystemCommandExecutorService() { this(new DefaultCommandBuilder(), new IgnoreOutput()); } public SystemCommandExecutorService(CommandBuilder builder, CommandOutputCapture capture) { setCommandBuilder(builder); setOutputCapture(capture); } /** * Invokes the command line executable * @see com.adaptris.core.Service#doService(com.adaptris.core.AdaptrisMessage) */ @Override public void doService(AdaptrisMessage msg) throws ServiceException { try (OutputStream out = getOutputCapture().startCapture(msg)) { Executor cmd = getCommandBuilder().configure(new DefaultExecutor()); ExecuteWatchdog watchdog = new ExecuteWatchdog(timeoutMs()); cmd.setWatchdog(watchdog); CommandLine cl = getCommandBuilder().createCommandLine(msg); Map<String, String> env = getCommandBuilder().createEnvironment(msg); PumpStreamHandler pump = new PumpStreamHandler(out); cmd.setStreamHandler(pump); log.trace("Executing {}", cl); int exit = cmd.execute(cl, env); msg.addMetadata(COMMAND_RETURN_VALUE_METADATA_KEY, "" + exit); } catch (Exception e) { throw ExceptionHelper.wrapServiceException(e); } } @Override protected void initService() throws CoreException { } @Override protected void closeService() { } public CommandBuilder getCommandBuilder() { return commandBuilder; } /** * Set the command builder. * * @param builder the {@link CommandBuilder} implementation * @see DefaultCommandBuilder */ public void setCommandBuilder(CommandBuilder builder) { this.commandBuilder = Args.notNull(builder, "commandBuilder"); } @Override public void prepare() throws CoreException { } /** * Specifies a maximum time for the executable to run, after which it will be terminated. * * @param t the timeout; default if not configured is 30 seconds. */ public void setTimeout(TimeInterval t) { this.timeout = t; } long timeoutMs() { return TimeInterval.toMillisecondsDefaultIfNull(getTimeout(), DEFAULT_TIMEOUT); } public TimeInterval getTimeout() { return timeout; } public CommandOutputCapture getOutputCapture() { return outputCapture; } public void setOutputCapture(CommandOutputCapture outputCapture) { this.outputCapture = Args.notNull(outputCapture, "outputCapture"); } }