View Javadoc

1   /*
2   Copyright (C) 2000 - 2007 Grid Systems, S.A.
3   
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2, as
6   published by the Free Software Foundation.
7   
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17  
18  /*
19   * Project: KernelConfigurator
20   * Created on 25-feb-2004
21   *
22   * Copyright (c)2003 Grid Systems
23   */
24  package com.gridsystems.config.app;
25  
26  import java.io.IOException;
27  import java.text.MessageFormat;
28  import java.util.ArrayList;
29  import java.util.StringTokenizer;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  import com.gridsystems.config.Configurator;
35  import com.gridsystems.config.ConfiguratorModel;
36  import com.gridsystems.config.ConsoleConfiguratorView;
37  import com.gridsystems.config.modules.jvm.JVMConfigurator;
38  import com.gridsystems.config.tools.console.ConsoleTools;
39  
40  /**
41   * UI implementation for execution in a text console environment.
42   *
43   * @author <a href="mailto:rruiz@gridsystems.com">Rodrigo Ruiz Aguayo</a>
44   * @version 1.0
45   */
46  class ConsoleUI extends UI {
47    /**
48     * For this class logs.
49     */
50    private static Log log = LogFactory.getLog(ConsoleUI.class);
51  
52    /**
53     * Exit character.
54     */
55    private static final String EXIT_CHAR = "0";
56  
57    /**
58     * Execute character.
59     */
60    private static final String EXEC_CHAR = "X";
61  
62    /**
63     * Default view width in characters.
64     */
65    private static final int DEFAULT_VIEW_WIDTH = 70;
66  
67    /**
68     * Left padding in characters.
69     */
70    private static final int PADDING = 10;
71  
72    /**
73     * {@inheritDoc}
74     */
75    public boolean execute() {
76      Configurator.setViewMode(Configurator.MODE_CONSOLE);
77  
78      Configurator[] configs = UI.getConfigurators();
79  
80      ConfigNode menu = new ConfigNode("/", null);
81      for (int i = 0; i < configs.length; i++) {
82        ConfiguratorModel model = configs[i].getModel();
83        ConsoleConfiguratorView view = (ConsoleConfiguratorView)configs[i].getView();
84        if (view != null) {
85          try {
86            view.getValues(model);
87            menu.addConfigurator(configs[i]);
88          } catch (Exception e) {
89            String pattern = UI.getString("errors.apply_error");
90            String msg = MessageFormat.format(pattern,
91                                              new Object[] { configs[i].getName() });
92            log.error(msg + ":" + e.getMessage());
93          }
94        }
95      }
96  
97      try {
98        showMenu(menu, "/");
99      } catch (Exception e) {
100       e.printStackTrace();
101       System.exit(1);
102     }
103     JVMConfigurator jvmc = JVMConfigurator.getInstance();
104     // Applies all configurators
105     StringBuffer errors = new StringBuffer();
106     for (int i = 0; i < configs.length; i++) {
107       if (configs[i] != jvmc) {
108         try {
109           apply(configs[i]);
110         } catch (Exception e) {
111           String name;
112           try {
113             name = configs[i].getBundle().getString("config.name");
114           } catch (Exception be) {
115             name = configs[i].getClass().getName();
116             log.error("Cannot find in the class " + name
117                 + " the translation for 'config.name' key");
118             name = name.substring(name.lastIndexOf('.') + 1, name.length());
119           }
120           log.error("Error applying configuration for " + name, e);
121           errors.append("\n     - " + name + ": " + e.getMessage());
122         }
123       }
124     }
125     // Ensures JVM configurator is applied on exit
126     try {
127       apply(jvmc);
128     } catch (Exception e) {
129       String name = jvmc.getClass().getName();
130       log.error("Error applying configuration for " + name, e);
131       name = name.substring(name.lastIndexOf('.') + 1, name.length());
132       errors.append("\n     - " + name + ": " + e.getMessage());
133     }
134 
135     if (errors.length() != 0) {
136       StringBuffer errorMsg = new StringBuffer("\n\n");
137       ConsoleTools.fill(errorMsg, '=', 72);
138       errorMsg.append("\n");
139       errorMsg.append(UI.getString("messages.applyErrors"));
140       errorMsg.append(errors);
141       errorMsg.append("\n");
142       ConsoleTools.fill(errorMsg, '=', 72);
143       System.out.println(errorMsg.toString());
144       return false;
145     }
146     return true;
147   }
148 
149   /**
150    * Adds to list the children options of the specified node.
151    *
152    * @param menu The node
153    * @param path The path to the node
154    * @param list The list to add the children
155    */
156   private void addCommonOptions(ConfigNode menu, String path, ArrayList<String> list) {
157     StringBuffer sb = new StringBuffer("          ");
158 
159     // Child node options
160     int count = menu.getChildCount();
161     for (int i = 0; i < count; i++) {
162       ConfigNode child = menu.getChild(i);
163       sb.setLength(PADDING);
164       sb.append(i + 1).append(". ").append(child.getLabel());
165       if (child.getChildCount() != 0) {
166         sb.append(" (+)");
167       }
168       list.add(sb.toString());
169     }
170 
171     // Extra options
172     if (menu.getConfigurator() != null) {
173       list.add(sb.append(EXEC_CHAR).append(". ")
174                  .append(getString("console.menu.exec")).toString());
175     }
176     sb.setLength(PADDING);
177     if (path.equals("/")) {
178       list.add(sb.append(EXIT_CHAR).append(". ")
179           .append(getString("console.menu.exit")).toString());
180     } else {
181       list.add(sb.append(EXIT_CHAR).append(". ")
182           .append(getString("console.menu.back")).toString());
183     }
184 
185     list.add("");
186   }
187 
188   /**
189    * Displays a screen with the menu options for the specified ConfigNode tree node.
190    *
191    * @param menu The node to show
192    * @param path The menu tree path to the node
193    * @throws IOException In case of I/O error
194    */
195   private void showMenu(ConfigNode menu, String path) throws IOException {
196 
197     ArrayList<String> list = new ArrayList<String>();
198 
199     // Menu Head: Current Position in the menu tree, and options header
200     list.add("");
201     list.add(" " + getString("console.menu.location") + path);
202     list.add("");
203     list.add("-");
204     list.add(ConsoleTools.center(getString("console.menu.head"), DEFAULT_VIEW_WIDTH));
205     list.add("");
206 
207     // Child node options
208     addCommonOptions(menu, path, list);
209 
210     String[] contents = new String[list.size()];
211     list.toArray(contents);
212 
213     while (true) {
214       ConsoleTools.clear();
215       ConsoleTools.paintBox(getString("app.title"), contents, DEFAULT_VIEW_WIDTH);
216 
217       System.out.println();
218       String option = ConsoleTools.readLine(getString("console.menu.prompt"));
219 
220       if (option.equalsIgnoreCase(EXIT_CHAR)) {
221         return;
222       } else if (option.equalsIgnoreCase(EXEC_CHAR)) {
223         // Execute option
224         execNode(menu);
225       } else if (option.startsWith("exec:")) {
226         execPath(menu, option.substring("exec:".length()));
227       } else {
228         try {
229           int opt = Integer.parseInt(option);
230           if (opt >= 1 && opt <= menu.getChildCount()) {
231             ConfigNode child = menu.getChild(opt - 1);
232             if (child.getChildCount() != 0) {
233               showMenu(child, path + child.getLabel() + "/");
234             } else {
235               execNode(child);
236             }
237           }
238         } catch (Exception e) {
239           // Bad syntax, repeat loop
240           e.printStackTrace();
241         }
242       }
243     }
244   }
245 
246   /**
247    * Calls the node configurator execute() method, if the specified node is
248    * associated to a configurator.
249    *
250    * @param node The node whose configurator to execute
251    */
252   private static void execNode(ConfigNode node) {
253     Configurator config = node.getConfigurator();
254     if (config == null) {
255       return;
256     }
257 
258     ConsoleConfiguratorView view = (ConsoleConfiguratorView)config.getView();
259     if (view == null) {
260       return;
261     }
262 
263     view.execute();
264   }
265 
266   /**
267    * Executes the node in the specified path.
268    *
269    * @param root The root node
270    * @param path The path to the node to execute
271    */
272   private static void execPath(ConfigNode root, String path) {
273     StringTokenizer st = new StringTokenizer(path, ".");
274 
275     ConfigNode node = root;
276     while (st.hasMoreTokens()) {
277       String s = st.nextToken();
278       boolean found = false;
279       for (int i = 0; i < node.getChildCount(); i++) {
280         ConfigNode child = node.getChild(i);
281         if (child.getLabel().equalsIgnoreCase(s)) {
282           found = true;
283           node = child;
284           break;
285         }
286       }
287       if (!found) {
288         return;
289       }
290     }
291     execNode(node);
292   }
293   /**
294    * Stores and applies the model of the specified configuration instance.
295    *
296    * @param config The configuration instance whose model to apply
297    * @throws Exception if error
298    */
299   private void apply(Configurator config) throws Exception {
300     if (config != null) {
301       ConfiguratorModel model = config.getModel();
302       if (model != null) {
303         model.validate();
304         model.store();
305         model.apply();
306       }
307     }
308   }
309 }