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    }