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.api.Framework; 042import org.nuxeo.runtime.model.ComponentContext; 043import org.nuxeo.runtime.model.ComponentInstance; 044import org.nuxeo.runtime.model.DefaultComponent; 045 046/** 047 * POJO implementation of the {@link CommandLineExecutorService} interface. Also handles the Extension Point logic. 048 * 049 * @author tiry 050 */ 051public class CommandLineExecutorComponent extends DefaultComponent implements CommandLineExecutorService { 052 053 public static final String EP_ENV = "environment"; 054 055 public static final String EP_CMD = "command"; 056 057 public static final String EP_CMDTESTER = "commandTester"; 058 059 public static final String DEFAULT_TESTER = "DefaultCommandTester"; 060 061 public static final String DEFAULT_EXECUTOR = "ShellExecutor"; 062 063 protected Map<String, CommandLineDescriptor> commandDescriptors = new HashMap<>(); 064 065 protected EnvironmentDescriptor env = new EnvironmentDescriptor(); 066 067 protected Map<String, EnvironmentDescriptor> envDescriptors = new HashMap<>(); 068 069 protected Map<String, CommandTester> testers = new HashMap<>(); 070 071 protected Map<String, Executor> executors = new HashMap<>(); 072 073 private static final Log log = LogFactory.getLog(CommandLineExecutorComponent.class); 074 075 @Override 076 public void activate(ComponentContext context) { 077 commandDescriptors = new HashMap<>(); 078 env = new EnvironmentDescriptor(); 079 testers = new HashMap<>(); 080 executors = new HashMap<>(); 081 executors.put(DEFAULT_EXECUTOR, new ShellExecutor()); 082 } 083 084 @Override 085 public void deactivate(ComponentContext context) { 086 commandDescriptors = null; 087 env = null; 088 testers = null; 089 executors = null; 090 } 091 092 @Override 093 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 094 if (EP_ENV.equals(extensionPoint)) { 095 EnvironmentDescriptor desc = (EnvironmentDescriptor) contribution; 096 String name = desc.getName(); 097 if (name == null) { 098 env.merge(desc); 099 } else { 100 for (String envName : name.split(",")) { 101 if (envDescriptors.containsKey(envName)) { 102 envDescriptors.get(envName).merge(desc); 103 } else { 104 envDescriptors.put(envName, desc); 105 } 106 } 107 } 108 } else if (EP_CMD.equals(extensionPoint)) { 109 CommandLineDescriptor desc = (CommandLineDescriptor) contribution; 110 String name = desc.getName(); 111 112 log.debug("Registering command: " + name); 113 114 if (!desc.isEnabled()) { 115 commandDescriptors.remove(name); 116 log.info("Command configured to not be enabled: " + name); 117 return; 118 } 119 120 String testerName = desc.getTester(); 121 if (testerName == null) { 122 testerName = DEFAULT_TESTER; 123 log.debug("Using default tester for command: " + name); 124 } 125 126 CommandTester tester = testers.get(testerName); 127 boolean cmdAvailable = false; 128 if (tester == null) { 129 log.error("Unable to find tester '" + testerName + "', command will not be available: " + name); 130 } else { 131 log.debug("Using tester '" + testerName + "' for command: " + name); 132 CommandTestResult testResult = tester.test(desc); 133 cmdAvailable = testResult.succeed(); 134 if (cmdAvailable) { 135 log.info("Registered command: " + name); 136 } else { 137 desc.setInstallErrorMessage(testResult.getErrorMessage()); 138 log.warn("Command not available: " + name + " (" + desc.getInstallErrorMessage() + ". " 139 + desc.getInstallationDirective() + ')'); 140 } 141 } 142 desc.setAvailable(cmdAvailable); 143 commandDescriptors.put(name, desc); 144 } else if (EP_CMDTESTER.equals(extensionPoint)) { 145 CommandTesterDescriptor desc = (CommandTesterDescriptor) contribution; 146 CommandTester tester; 147 try { 148 tester = (CommandTester) desc.getTesterClass().getDeclaredConstructor().newInstance(); 149 } catch (ReflectiveOperationException e) { 150 throw new RuntimeException(e); 151 } 152 testers.put(desc.getName(), tester); 153 } 154 } 155 156 @Override 157 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 158 } 159 160 /* 161 * Service interface 162 */ 163 @Override 164 public ExecResult execCommand(String commandName, CmdParameters params) throws CommandNotAvailable { 165 CommandAvailability availability = getCommandAvailability(commandName); 166 if (!availability.isAvailable()) { 167 throw new CommandNotAvailable(availability); 168 } 169 170 CommandLineDescriptor cmdDesc = commandDescriptors.get(commandName); 171 Executor executor = executors.get(cmdDesc.getExecutor()); 172 EnvironmentDescriptor environment = new EnvironmentDescriptor().merge(env).merge( 173 envDescriptors.getOrDefault(commandName, envDescriptors.get(cmdDesc.getCommand()))); 174 return executor.exec(cmdDesc, params, environment); 175 } 176 177 @Override 178 public CommandAvailability getCommandAvailability(String commandName) { 179 if (!commandDescriptors.containsKey(commandName)) { 180 return new CommandAvailability(commandName + " is not a registered command"); 181 } 182 183 CommandLineDescriptor desc = commandDescriptors.get(commandName); 184 if (desc.isAvailable()) { 185 return new CommandAvailability(); 186 } else { 187 return new CommandAvailability(desc.getInstallationDirective(), desc.getInstallErrorMessage()); 188 } 189 } 190 191 @Override 192 public List<String> getRegistredCommands() { 193 List<String> cmds = new ArrayList<>(); 194 cmds.addAll(commandDescriptors.keySet()); 195 return cmds; 196 } 197 198 @Override 199 public List<String> getAvailableCommands() { 200 List<String> cmds = new ArrayList<>(); 201 202 for (String cmdName : commandDescriptors.keySet()) { 203 CommandLineDescriptor cmd = commandDescriptors.get(cmdName); 204 if (cmd.isAvailable()) { 205 cmds.add(cmdName); 206 } 207 } 208 return cmds; 209 } 210 211 @Override 212 public CommandLineDescriptor getCommandLineDescriptor(String commandName) { 213 return commandDescriptors.get(commandName); 214 } 215 216 // ****************************************** 217 // for testing 218 219 /** @deprecated since 11.4, use instance method {@link #getCommandLineDescriptor} instead */ 220 @Deprecated 221 public static CommandLineDescriptor getCommandDescriptor(String commandName) { 222 return Framework.getService(CommandLineExecutorService.class).getCommandLineDescriptor(commandName); 223 } 224 225 @Override 226 public CmdParameters getDefaultCmdParameters() { 227 CmdParameters params = new CmdParameters(); 228 params.addNamedParameter("java.io.tmpdir", System.getProperty("java.io.tmpdir")); 229 params.addNamedParameter(Environment.NUXEO_TMP_DIR, Environment.getDefault().getTemp().getPath()); 230 return params; 231 } 232 233}