View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.gshell.cli;
21  
22  import org.apache.geronimo.gshell.ansi.Ansi;
23  import org.apache.geronimo.gshell.application.model.ApplicationModel;
24  import org.apache.geronimo.gshell.artifact.ArtifactResolver;
25  import org.apache.geronimo.gshell.artifact.transfer.monitor.ProgressSpinnerMonitor;
26  import org.apache.geronimo.gshell.clp.Argument;
27  import org.apache.geronimo.gshell.clp.CommandLineProcessor;
28  import org.apache.geronimo.gshell.clp.Option;
29  import org.apache.geronimo.gshell.clp.Printer;
30  import org.apache.geronimo.gshell.i18n.MessageSource;
31  import org.apache.geronimo.gshell.i18n.ResourceBundleMessageSource;
32  import org.apache.geronimo.gshell.io.IO;
33  import org.apache.geronimo.gshell.notification.ExitNotification;
34  import org.apache.geronimo.gshell.shell.Shell;
35  import org.apache.geronimo.gshell.terminal.AutoDetectedTerminal;
36  import org.apache.geronimo.gshell.terminal.UnixTerminal;
37  import org.apache.geronimo.gshell.terminal.UnsupportedTerminal;
38  import org.apache.geronimo.gshell.terminal.WindowsTerminal;
39  import org.apache.geronimo.gshell.wisdom.builder.ShellBuilder;
40  import org.apache.geronimo.gshell.wisdom.builder.ShellBuilderImpl;
41  
42  import java.util.List;
43  import java.util.concurrent.atomic.AtomicReference;
44  
45  /**
46   * Command-line bootstrap for GShell.
47   *
48   * @version $Rev: 721603 $ $Date: 2008-11-29 01:58:59 +0100 (Sat, 29 Nov 2008) $
49   */
50  public class Main
51  {
52      private static final boolean BYPASS_EXIT = Boolean.getBoolean(Main.class.getName() + ".bypassExit");
53  
54      //
55      // NOTE: Do not use logging from this class, as it is used to configure
56      //       the logging level with System properties, which will only get
57      //       picked up on the initial loading of Log4j
58      //
59  
60      private final IO io = new IO();
61  
62      private final MessageSource messages = new ResourceBundleMessageSource(getClass());
63      
64      //
65      // TODO: Add flag to capture output to log file
66      //       https://issues.apache.org/jira/browse/GSHELL-47
67      //
68  
69      //
70      // TODO: Add --file <file>, which will run: source <file> 
71      //
72  
73      //
74      // FIXME: Really need to allow the location of the application.xml to be passed in!
75      //
76  
77      @Option(name="-h", aliases={"--help"}, requireOverride=true)
78      private boolean help;
79  
80      @Option(name="-V", aliases={"--version"}, requireOverride=true)
81      private boolean version;
82  
83      @Option(name="-i", aliases={"--interactive"})
84      private boolean interactive = true;
85  
86      private void setConsoleLogLevel(final String level) {
87          System.setProperty("gshell.log.console.level", level);
88      }
89  
90      @Option(name="-e", aliases={"--exception"})
91      private void setException(boolean flag) {
92      	if (flag) {
93      		System.setProperty("gshell.show.stacktrace","true");
94      	}
95      }
96      
97      @Option(name="-d", aliases={"--debug"})
98      private void setDebug(boolean flag) {
99          if (flag) {
100             setConsoleLogLevel("DEBUG");
101             io.setVerbosity(IO.Verbosity.DEBUG);
102         }
103     }
104 
105     @Option(name="-X", aliases={"--trace"})
106     private void setTrace(boolean flag) {
107         if (flag) {
108             setConsoleLogLevel("TRACE");
109             io.setVerbosity(IO.Verbosity.DEBUG);
110         }
111     }
112 
113     @Option(name="-v", aliases={"--verbose"})
114     private void setVerbose(boolean flag) {
115         if (flag) {
116             setConsoleLogLevel("INFO");
117             io.setVerbosity(IO.Verbosity.VERBOSE);
118         }
119     }                                                 
120 
121     @Option(name="-q", aliases={"--quiet"})
122     private void setQuiet(boolean flag) {
123         if (flag) {
124             setConsoleLogLevel("ERROR");
125             io.setVerbosity(IO.Verbosity.QUIET);
126         }
127     }
128 
129     @Option(name="-c", aliases={"--commands"})
130     private String commands;
131 
132     @Argument
133     private List<String> commandArgs = null;
134 
135     @Option(name="-D", aliases={"--define"})
136     private void setSystemProperty(final String nameValue) {
137         assert nameValue != null;
138 
139         String name, value;
140         int i = nameValue.indexOf("=");
141 
142         if (i == -1) {
143             name = nameValue;
144             value = Boolean.TRUE.toString();
145         }
146         else {
147             name = nameValue.substring(0, i);
148             value = nameValue.substring(i + 1, nameValue.length());
149         }
150         name = name.trim();
151 
152         System.setProperty(name, value);
153     }
154 
155     @Option(name="-C", aliases={"--color"}, argumentRequired=true)
156     private void enableAnsiColors(final boolean flag) {
157         Ansi.setEnabled(flag);
158     }
159 
160     @Option(name="-T", aliases={"--terminal"}, argumentRequired=true)
161     private void setTerminalType(String type) {
162         type = type.toLowerCase();
163 
164         if ("auto".equals(type)) {
165             type = AutoDetectedTerminal.class.getName();
166         }
167         else if ("unix".equals(type)) {
168             type = UnixTerminal.class.getName();
169         }
170         else if ("win".equals(type) || "windows".equals("type")) {
171             type = WindowsTerminal.class.getName();
172         }
173         else if ("false".equals(type) || "off".equals(type) || "none".equals(type)) {
174             type = UnsupportedTerminal.class.getName();
175         }
176 
177         System.setProperty("jline.terminal", type);
178     }
179 
180     public int boot(final String[] args) throws Exception {
181         assert args != null;
182 
183         System.setProperty("jline.terminal", AutoDetectedTerminal.class.getName());
184 
185         // Default is to be quiet
186         setConsoleLogLevel("WARN");
187 
188         CommandLineProcessor clp = new CommandLineProcessor(this);
189         clp.setStopAtNonOption(true);
190         clp.process(args);
191 
192         // Setup a refereence for our exit code so our callback thread can tell if we've shutdown normally or not
193         final AtomicReference<Integer> codeRef = new AtomicReference<Integer>();
194         int code = ExitNotification.DEFAULT_CODE;
195 
196         Runtime.getRuntime().addShutdownHook(new Thread("GShell Shutdown Hook") {
197             public void run() {
198                 if (codeRef.get() == null) {
199                     // Give the user a warning when the JVM shutdown abnormally, normal shutdown
200                     // will set an exit code through the proper channels
201 
202                     if (!io.isSilent()) {
203                         io.err.println();
204                         io.err.println(messages.getMessage("warning.abnormalShutdown"));
205                     }
206                 }
207 
208                 io.flush();
209             }
210         });
211 
212         try {
213             ShellBuilder builder = new ShellBuilderImpl();
214             builder.setClassLoader(getClass().getClassLoader());
215             builder.setIo(io);
216 
217             if (!io.isQuiet() && !io.isSilent()) {
218                 // Configure the download monitor
219                 ArtifactResolver artifactResolver = builder.getContainer().getBean(ArtifactResolver.class);
220                 artifactResolver.setTransferListener(new ProgressSpinnerMonitor(io));
221             }
222 
223             // --help and --version need access to the application's information, so we have to handle these options late
224             if (help|version) {
225                 ApplicationModel applicationModel = builder.getApplicationModel();
226 
227                 if (help) {
228                     Printer printer = new Printer(clp);
229                     printer.setMessageSource(messages);
230                     printer.printUsage(io.out, applicationModel.getBranding().getProgramName());
231                 }
232                 else if (version) {
233                     io.out.println(applicationModel.getVersion());
234                 }
235 
236                 io.out.flush();
237 
238                 throw new ExitNotification();
239             }
240 
241             // Build the shell instance
242             Shell gshell = builder.create();
243 
244             // clp gives us a list, but we need an array
245             String[] _args = {};
246             if (commandArgs != null) {
247                 _args = commandArgs.toArray(new String[commandArgs.size()]);
248             }
249 
250             if (commands != null) {
251                 gshell.execute(commands);
252             }
253             else if (interactive) {
254                 gshell.run(_args);
255             }
256             else {
257                 gshell.execute(_args);
258             }
259         }
260         catch (ExitNotification n) {
261             code = n.code;
262         }
263 
264         codeRef.set(code);
265 
266         return code;
267     }
268 
269     public static void main(final String[] args) throws Exception {
270         Main main = new Main();
271 
272         int code = main.boot(args);
273 
274         if (!BYPASS_EXIT) {
275             System.exit(code);
276         }
277     }
278 }
279