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