001/* 002 * (C) Copyright 2006-2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 */ 020 021package org.nuxeo.ecm.platform.commandline.executor.service; 022 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030 031import org.nuxeo.common.Environment; 032import org.nuxeo.ecm.platform.commandline.executor.api.CmdParameters; 033import org.nuxeo.ecm.platform.commandline.executor.api.CommandAvailability; 034import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService; 035import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable; 036import org.nuxeo.ecm.platform.commandline.executor.api.ExecResult; 037import org.nuxeo.ecm.platform.commandline.executor.service.cmdtesters.CommandTestResult; 038import org.nuxeo.ecm.platform.commandline.executor.service.cmdtesters.CommandTester; 039import org.nuxeo.ecm.platform.commandline.executor.service.executors.Executor; 040import org.nuxeo.ecm.platform.commandline.executor.service.executors.ShellExecutor; 041import org.nuxeo.runtime.model.ComponentContext; 042import org.nuxeo.runtime.model.ComponentInstance; 043import org.nuxeo.runtime.model.DefaultComponent; 044 045/** 046 * POJO implementation of the {@link CommandLineExecutorService} interface. Also handles the Extension Point logic. 047 * 048 * @author tiry 049 */ 050public class CommandLineExecutorComponent extends DefaultComponent implements CommandLineExecutorService { 051 052 public static final String EP_ENV = "environment"; 053 054 public static final String EP_CMD = "command"; 055 056 public static final String EP_CMDTESTER = "commandTester"; 057 058 public static final String DEFAULT_TESTER = "DefaultCommandTester"; 059 060 public static final String DEFAULT_EXECUTOR = "ShellExecutor"; 061 062 protected static Map<String, CommandLineDescriptor> commandDescriptors = new HashMap<>(); 063 064 protected static EnvironmentDescriptor env = new EnvironmentDescriptor(); 065 066 protected static Map<String, EnvironmentDescriptor> envDescriptors = new HashMap<>(); 067 068 protected static Map<String, CommandTester> testers = new HashMap<>(); 069 070 protected static Map<String, Executor> executors = new HashMap<>(); 071 072 private static final Log log = LogFactory.getLog(CommandLineExecutorComponent.class); 073 074 @Override 075 public void activate(ComponentContext context) { 076 commandDescriptors = new HashMap<>(); 077 env = new EnvironmentDescriptor(); 078 testers = new HashMap<>(); 079 executors = new HashMap<>(); 080 executors.put(DEFAULT_EXECUTOR, new ShellExecutor()); 081 } 082 083 @Override 084 public void deactivate(ComponentContext context) { 085 commandDescriptors = null; 086 env = null; 087 testers = null; 088 executors = null; 089 } 090 091 @Override 092 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 093 if (EP_ENV.equals(extensionPoint)) { 094 EnvironmentDescriptor desc = (EnvironmentDescriptor) contribution; 095 String name = desc.getName(); 096 if (name == null) { 097 env.merge(desc); 098 } else { 099 for (String envName : name.split(",")) { 100 if (envDescriptors.containsKey(envName)) { 101 envDescriptors.get(envName).merge(desc); 102 } else { 103 envDescriptors.put(envName, desc); 104 } 105 } 106 } 107 } else if (EP_CMD.equals(extensionPoint)) { 108 CommandLineDescriptor desc = (CommandLineDescriptor) contribution; 109 String name = desc.getName(); 110 111 log.debug("Registering command: " + name); 112 113 if (!desc.isEnabled()) { 114 commandDescriptors.remove(name); 115 log.info("Command configured to not be enabled: " + name); 116 return; 117 } 118 119 String testerName = desc.getTester(); 120 if (testerName == null) { 121 testerName = DEFAULT_TESTER; 122 log.debug("Using default tester for command: " + name); 123 } 124 125 CommandTester tester = testers.get(testerName); 126 boolean cmdAvailable = false; 127 if (tester == null) { 128 log.error("Unable to find tester '" + testerName + "', command will not be available: " + name); 129 } else { 130 log.debug("Using tester '" + testerName + "' for command: " + name); 131 CommandTestResult testResult = tester.test(desc); 132 cmdAvailable = testResult.succeed(); 133 if (cmdAvailable) { 134 log.info("Registered command: " + name); 135 } else { 136 desc.setInstallErrorMessage(testResult.getErrorMessage()); 137 log.warn("Command not available: " + name + " (" + desc.getInstallErrorMessage() + ". " 138 + desc.getInstallationDirective() + ')'); 139 } 140 } 141 desc.setAvailable(cmdAvailable); 142 commandDescriptors.put(name, desc); 143 } else if (EP_CMDTESTER.equals(extensionPoint)) { 144 CommandTesterDescriptor desc = (CommandTesterDescriptor) contribution; 145 CommandTester tester; 146 try { 147 tester = (CommandTester) desc.getTesterClass().newInstance(); 148 } catch (ReflectiveOperationException e) { 149 throw new RuntimeException(e); 150 } 151 testers.put(desc.getName(), tester); 152 } 153 } 154 155 @Override 156 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 157 } 158 159 /* 160 * Service interface 161 */ 162 @Override 163 public ExecResult execCommand(String commandName, CmdParameters params) throws CommandNotAvailable { 164 CommandAvailability availability = getCommandAvailability(commandName); 165 if (!availability.isAvailable()) { 166 throw new CommandNotAvailable(availability); 167 } 168 169 CommandLineDescriptor cmdDesc = commandDescriptors.get(commandName); 170 Executor executor = executors.get(cmdDesc.getExecutor()); 171 EnvironmentDescriptor environment = new EnvironmentDescriptor().merge(env).merge( 172 envDescriptors.getOrDefault(commandName, envDescriptors.get(cmdDesc.getCommand()))); 173 return executor.exec(cmdDesc, params, environment); 174 } 175 176 @Override 177 public CommandAvailability getCommandAvailability(String commandName) { 178 if (!commandDescriptors.containsKey(commandName)) { 179 return new CommandAvailability(commandName + " is not a registered command"); 180 } 181 182 CommandLineDescriptor desc = commandDescriptors.get(commandName); 183 if (desc.isAvailable()) { 184 return new CommandAvailability(); 185 } else { 186 return new CommandAvailability(desc.getInstallationDirective(), desc.getInstallErrorMessage()); 187 } 188 } 189 190 @Override 191 public List<String> getRegistredCommands() { 192 List<String> cmds = new ArrayList<>(); 193 cmds.addAll(commandDescriptors.keySet()); 194 return cmds; 195 } 196 197 @Override 198 public List<String> getAvailableCommands() { 199 List<String> cmds = new ArrayList<>(); 200 201 for (String cmdName : commandDescriptors.keySet()) { 202 CommandLineDescriptor cmd = commandDescriptors.get(cmdName); 203 if (cmd.isAvailable()) { 204 cmds.add(cmdName); 205 } 206 } 207 return cmds; 208 } 209 210 // ****************************************** 211 // for testing 212 213 public static CommandLineDescriptor getCommandDescriptor(String commandName) { 214 return commandDescriptors.get(commandName); 215 } 216 217 @Override 218 public CmdParameters getDefaultCmdParameters() { 219 CmdParameters params = new CmdParameters(); 220 params.addNamedParameter("java.io.tmpdir", System.getProperty("java.io.tmpdir")); 221 params.addNamedParameter(Environment.NUXEO_TMP_DIR, Environment.getDefault().getTemp().getPath()); 222 return params; 223 } 224 225}