001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.deployment.cli;
019    
020    import java.io.BufferedReader;
021    import java.io.File;
022    import java.io.FileReader;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.OutputStreamWriter;
026    import java.io.PrintWriter;
027    import java.util.Arrays;
028    import java.util.IdentityHashMap;
029    import java.util.Iterator;
030    import java.util.LinkedList;
031    import java.util.List;
032    
033    import javax.enterprise.deploy.spi.factories.DeploymentFactory;
034    
035    import org.apache.geronimo.cli.deployer.CommandArgs;
036    import org.apache.geronimo.cli.deployer.CommandFileCommandMetaData;
037    import org.apache.geronimo.cli.deployer.CommandMetaData;
038    import org.apache.geronimo.cli.deployer.DeployCommandMetaData;
039    import org.apache.geronimo.cli.deployer.DeployerCLParser;
040    import org.apache.geronimo.cli.deployer.DistributeCommandMetaData;
041    import org.apache.geronimo.cli.deployer.InstallLibraryCommandMetaData;
042    import org.apache.geronimo.cli.deployer.InstallPluginCommandMetaData;
043    import org.apache.geronimo.cli.deployer.ListModulesCommandMetaData;
044    import org.apache.geronimo.cli.deployer.ListTargetsCommandMetaData;
045    import org.apache.geronimo.cli.deployer.LoginCommandMetaData;
046    import org.apache.geronimo.cli.deployer.RedeployCommandMetaData;
047    import org.apache.geronimo.cli.deployer.RestartCommandMetaData;
048    import org.apache.geronimo.cli.deployer.SearchPluginsCommandMetaData;
049    import org.apache.geronimo.cli.deployer.StartCommandMetaData;
050    import org.apache.geronimo.cli.deployer.StopCommandMetaData;
051    import org.apache.geronimo.cli.deployer.UndeployCommandMetaData;
052    import org.apache.geronimo.common.DeploymentException;
053    import org.apache.geronimo.gbean.GBeanInfo;
054    import org.apache.geronimo.gbean.GBeanInfoBuilder;
055    import org.apache.geronimo.kernel.Kernel;
056    import org.apache.geronimo.kernel.util.Main;
057    import jline.ConsoleReader;
058    
059    
060    /**
061     * The main class for the CLI deployer.  Handles chunking the input arguments
062     * and formatting help text and maintaining the list of individual commands.
063     * Uses a ServerConnection to handle the server connection and arguments, and
064     * a list of DeployCommands to manage the details of the various available
065     * commands.
066     *
067     * Returns 0 normally, or 1 of any exceptions or error messages were generated
068     * (whether for syntax or other failure).
069     *
070     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
071     */
072    public class DeployTool implements Main {
073    
074        private static final IdentityHashMap<CommandMetaData, DeployCommand> commands = new IdentityHashMap<CommandMetaData, DeployCommand>();
075    
076        static {
077            commands.put(LoginCommandMetaData.META_DATA, new CommandLogin());
078            commands.put(DeployCommandMetaData.META_DATA, new CommandDeploy());
079            commands.put(DistributeCommandMetaData.META_DATA, new CommandDistribute());
080            commands.put(ListModulesCommandMetaData.META_DATA, new CommandListModules());
081            commands.put(ListTargetsCommandMetaData.META_DATA, new CommandListTargets());
082            commands.put(RedeployCommandMetaData.META_DATA, new CommandRedeploy());
083            commands.put(StartCommandMetaData.META_DATA, new CommandStart());
084            commands.put(StopCommandMetaData.META_DATA, new CommandStop());
085            commands.put(RestartCommandMetaData.META_DATA, new CommandRestart());
086            commands.put(UndeployCommandMetaData.META_DATA, new CommandUndeploy());
087            commands.put(SearchPluginsCommandMetaData.META_DATA, new CommandListConfigurations());
088            commands.put(InstallPluginCommandMetaData.META_DATA, new CommandInstallCAR());
089            commands.put(InstallLibraryCommandMetaData.META_DATA, new CommandInstallLibrary());
090        }
091    
092        private boolean failed = false;
093        String[] generalArgs = new String[0];
094        ServerConnection con = null;
095        private boolean multipleCommands = false;
096        private final Kernel kernel;
097        private final DeploymentFactory deploymentFactory;
098    
099        public DeployTool(Kernel kernel, DeploymentFactory deploymentFactory) {
100            if (null == kernel) {
101                throw new IllegalArgumentException("kernel is required");
102            } else if (null == deploymentFactory) {
103                throw new IllegalArgumentException("deploymentFactory is required");
104            }
105            this.kernel = kernel;
106            this.deploymentFactory = deploymentFactory;
107        }
108        
109        public int execute(Object opaque) {
110            if (! (opaque instanceof DeployerCLParser)) {
111                throw new IllegalArgumentException("Argument type is [" + opaque.getClass() + "]; expected [" + DeployerCLParser.class + "]");
112            }
113            DeployerCLParser parser = (DeployerCLParser) opaque;
114            
115            PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out), true);
116            InputStream in = System.in;
117    
118            CommandMetaData commandMetaData = parser.getCommandMetaData();
119            CommandArgs commandArgs = parser.getCommandArgs();
120            if(commandMetaData == CommandFileCommandMetaData.META_DATA) {
121                multipleCommands = true;
122                String arg = commandArgs.getArgs()[0];
123                File source = new File(arg);
124                if(!source.exists() || !source.canRead() || source.isDirectory()) {
125                    processException(out, new DeploymentSyntaxException("Cannot read command file "+source.getAbsolutePath()));
126                } else {
127                    try {
128                        BufferedReader commands = new BufferedReader(new FileReader(source));
129                        String line;
130                        boolean oneFailed = false;
131                        while((line = commands.readLine()) != null) {
132                            line = line.trim();
133                            if(!line.equals("")) {
134                                String[] lineArgs = splitCommand(line);
135                                if(failed) {
136                                    oneFailed = true;
137                                }
138                                failed = false;
139                                execute(lineArgs);
140                            }
141                        }
142                        failed = oneFailed;
143                    } catch (IOException e) {
144                        processException(out, new DeploymentException("Unable to read command file", e));
145                    } finally {
146                        try {
147                            con.close();
148                        } catch (DeploymentException e) {
149                            processException(out, e);
150                        }
151                    }
152                }
153            } else {
154                DeployCommand dc = commands.get(commandMetaData);
155                if(dc == null) {
156                    out.println();
157                    processException(out, new DeploymentSyntaxException("No such command: '"+commandMetaData+"'"));
158                } else {
159                    try {
160                        if(con == null) {
161                            con = new ServerConnection(parser, out, in, kernel, deploymentFactory);
162                        }
163                        try {
164                            dc.execute(new ConsoleReader(in, out), con, commandArgs);
165                        } catch (DeploymentSyntaxException e) {
166                            processException(out, e);
167                        } catch (DeploymentException e) {
168                            processException(out, e);
169                        } catch (IOException e) {
170                            processException(out, e);
171                        } finally {
172                            if(!multipleCommands) {
173                                try {
174                                    con.close();
175                                } catch(DeploymentException e) {
176                                    processException(out, e);
177                                }
178                            }
179                        }
180                    } catch(DeploymentException e) {
181                        processException(out, e);
182                    }
183                }
184            }
185            out.flush();
186            System.out.flush();
187            return failed ? 1 : 0;
188        }
189    
190        public static String[] splitCommand(String line) {
191            String[] chunks = line.split("\"");
192            List list = new LinkedList();
193            for (int i = 0; i < chunks.length; i++) {
194                String chunk = chunks[i];
195                if(i % 2 == 1) { // it's in quotes
196                    list.add(chunk);
197                } else { // it's not in quotes
198                    list.addAll(Arrays.asList(chunk.split("\\s")));
199                }
200            }
201            for (Iterator it = list.iterator(); it.hasNext();) {
202                String test = (String) it.next();
203                if(test.trim().equals("")) {
204                    it.remove();
205                }
206            }
207            return (String[]) list.toArray(new String[list.size()]);
208        }
209    
210        private void processException(PrintWriter out, Exception e) {
211            failed = true;
212            out.print(DeployUtils.reformat("Error: "+e.getMessage(),4,72));
213            if(e.getCause() != null) {
214                e.getCause().printStackTrace(out);
215            }
216        }
217    
218        public static final GBeanInfo GBEAN_INFO;
219        public static final String GBEAN_REF_DEPLOYMENT_FACTORY = "DeploymentFactory";
220        
221        static {
222            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("DeployTool", DeployTool.class, "DeployTool");
223    
224            infoBuilder.addReference(GBEAN_REF_DEPLOYMENT_FACTORY, DeploymentFactory.class);
225            infoBuilder.addInterface(Main.class);
226            
227            infoBuilder.setConstructor(new String[] {"kernel", GBEAN_REF_DEPLOYMENT_FACTORY});
228            
229            GBEAN_INFO = infoBuilder.getBeanInfo();
230        }
231        
232        public static GBeanInfo getGBeanInfo() {
233            return GBEAN_INFO;
234        }
235    
236    }