001 /*
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
005 *
006 * The contents of this file are subject to the terms of either the GNU
007 * General Public License Version 2 only ("GPL") or the Common Development
008 * and Distribution License("CDDL") (collectively, the "License"). You
009 * may not use this file except in compliance with the License. You can
010 * obtain a copy of the License at
011 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
012 * or packager/legal/LICENSE.txt. See the License for the specific
013 * language governing permissions and limitations under the License.
014 *
015 * When distributing the software, include this License Header Notice in each
016 * file and include the License file at packager/legal/LICENSE.txt.
017 *
018 * GPL Classpath Exception:
019 * Oracle designates this particular file as subject to the "Classpath"
020 * exception as provided by Oracle in the GPL Version 2 section of the License
021 * file that accompanied this code.
022 *
023 * Modifications:
024 * If applicable, add the following below the License Header, with the fields
025 * enclosed by brackets [] replaced by your own identifying information:
026 * "Portions Copyright [year] [name of copyright owner]"
027 *
028 * Contributor(s):
029 * If you wish your version of this file to be governed by only the CDDL or
030 * only the GPL Version 2, indicate your decision by adding "[Contributor]
031 * elects to include this software in this distribution under the [CDDL or GPL
032 * Version 2] license." If you don't indicate a single choice of license, a
033 * recipient has the option to distribute your version of this file under
034 * either the CDDL, the GPL Version 2 or to extend the choice of license to
035 * its licensees as provided above. However, if you add GPL Version 2 code
036 * and therefore, elected the GPL Version 2 license, then the option applies
037 * only if the new code is made subject to such option by the copyright
038 * holder.
039 */
040
041 package com.sun.enterprise.admin.cli.embeddable;
042
043 import com.sun.enterprise.admin.cli.CLIUtil;
044 import com.sun.enterprise.admin.cli.Parser;
045 import com.sun.enterprise.admin.cli.ProgramOptions;
046 import org.glassfish.api.ActionReport;
047 import org.glassfish.api.admin.CommandException;
048 import org.glassfish.api.admin.CommandModel;
049 import org.glassfish.api.admin.CommandRunner;
050 import org.glassfish.api.admin.ParameterMap;
051 import org.glassfish.embeddable.CommandResult;
052 import org.jvnet.hk2.annotations.ContractProvided;
053 import org.jvnet.hk2.annotations.Inject;
054 import org.jvnet.hk2.annotations.Scoped;
055 import org.jvnet.hk2.annotations.Service;
056 import org.jvnet.hk2.component.Habitat;
057 import org.jvnet.hk2.component.PerLookup;
058
059 import java.io.ByteArrayOutputStream;
060 import java.io.IOException;
061 import java.util.List;
062 import java.util.Map;
063 import java.util.logging.Logger;
064
065 /**
066 * @author bhavanishankar@dev.java.net
067 * @author sanjeeb.sahoo@sun.com
068 */
069 @Service()
070 @Scoped(PerLookup.class) // this is a PerLookup service
071 @ContractProvided(org.glassfish.embeddable.CommandRunner.class)
072 // bcos CommandRunner interface can't depend on HK2, we need ContractProvided here.
073
074 public class CommandExecutorImpl implements org.glassfish.embeddable.CommandRunner {
075
076 @Inject
077 CommandRunner commandRunner;
078
079 @Inject
080 Habitat habitat;
081
082 private boolean terse;
083
084 private Logger logger = Logger.getAnonymousLogger();
085
086 public CommandResult run(String command, String... args){
087 try {
088 ActionReport actionReport = executeCommand(command, args);
089 return convert(actionReport);
090 } catch (Exception e) {
091 return convert(e);
092 }
093 }
094
095 ParameterMap getParameters(String command, String[] args) throws CommandException {
096 CommandModel commandModel = commandRunner.getModel(command, logger);
097 if (command == null) {
098 throw new CommandException("No command called " + command);
099 }
100
101 // Filter out the global options.
102 // We are interested only in --passwordfile option. No other options are relevant when GlassFish is running in embedded mode.
103 Parser parser = new Parser(args, 0, ProgramOptions.getValidOptions(), true);
104 ParameterMap globalOptions = parser.getOptions();
105 List<String> operands = parser.getOperands();
106 String argv[] = operands.toArray(new String[operands.size()]);
107
108 parser = new Parser(argv, 0, commandModel.getParameters(), false);
109 ParameterMap options = parser.getOptions();
110 operands = parser.getOperands();
111 options.set("DEFAULT", operands);
112 // if command has a "terse" option, set it in options
113 if (commandModel.getModelFor("terse") != null)
114 options.set("terse", Boolean.toString(terse));
115
116 // Read the passwords from the password file and set it in command options.
117 if (globalOptions.size() > 0) {
118 String pwfile = globalOptions.getOne(ProgramOptions.PASSWORDFILE);
119 if (pwfile != null && pwfile.length() > 0) {
120 Map<String, String> passwords = CLIUtil.readPasswordFileOptions(pwfile, true);
121 for (CommandModel.ParamModel opt : commandModel.getParameters()) {
122 if (opt.getParam().password()) {
123 String pwdname = opt.getName();
124 String pwd = passwords.get(pwdname);
125 if (pwd != null) {
126 options.set(pwdname, pwd);
127 }
128 }
129 }
130 }
131 }
132
133 return options;
134 }
135
136 public void setTerse(boolean terse) {
137 this.terse = terse;
138 }
139
140 /* package */ ActionReport executeCommand(String command, String... args) throws CommandException {
141 ParameterMap commandParams = getParameters(command, args);
142 final ActionReport actionReport = createActionReport();
143
144 org.glassfish.api.admin.CommandRunner.CommandInvocation inv =
145 commandRunner.getCommandInvocation(command, actionReport);
146
147 inv.parameters(commandParams).execute();
148
149 return actionReport;
150 }
151
152 private CommandResult convert(final ActionReport actionReport) {
153 return new CommandResult(){
154 public ExitStatus getExitStatus() {
155 final ActionReport.ExitCode actionExitCode = actionReport.getActionExitCode();
156 switch (actionExitCode) {
157 case SUCCESS:
158 return ExitStatus.SUCCESS;
159 case WARNING:
160 return ExitStatus.WARNING;
161 case FAILURE:
162 return ExitStatus.FAILURE;
163 default:
164 throw new RuntimeException("Unknown exit code: " + actionExitCode);
165 }
166 }
167
168 public String getOutput() {
169 final ByteArrayOutputStream os = new ByteArrayOutputStream();
170 try {
171 actionReport.writeReport(os);
172 return os.toString();
173 } catch (IOException e) {
174 throw new RuntimeException(e);
175 } finally {
176 try {
177 os.close();
178 } catch (IOException e) {
179 // ignore
180 }
181 }
182 }
183
184 public Throwable getFailureCause() {
185 return actionReport.getFailureCause();
186 }
187 };
188 }
189
190 private CommandResult convert(final Exception e) {
191 return new CommandResult() {
192 public ExitStatus getExitStatus() {
193 return ExitStatus.FAILURE;
194 }
195
196 public String getOutput() {
197 return "Exception while executing command.";
198 }
199
200 public Throwable getFailureCause() {
201 return e;
202 }
203 };
204 }
205
206 ActionReport createActionReport() {
207 return habitat.getComponent(ActionReport.class, "plain");
208 }
209
210 CommandRunner getCommandRunner() {
211 return commandRunner;
212 }
213
214 }