001: /*
002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/main/CmsShell.java,v $
003: * Date : $Date: 2008-02-27 12:05:39 $
004: * Version: $Revision: 1.53 $
005: *
006: * This library is part of OpenCms -
007: * the Open Source Content Management System
008: *
009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010: *
011: * This library is free software; you can redistribute it and/or
012: * modify it under the terms of the GNU Lesser General Public
013: * License as published by the Free Software Foundation; either
014: * version 2.1 of the License, or (at your option) any later version.
015: *
016: * This library is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: * Lesser General Public License for more details.
020: *
021: * For further information about Alkacon Software GmbH, please see the
022: * company website: http://www.alkacon.com
023: *
024: * For further information about OpenCms, please see the
025: * project website: http://www.opencms.org
026: *
027: * You should have received a copy of the GNU Lesser General Public
028: * License along with this library; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031:
032: package org.opencms.main;
033:
034: import org.opencms.db.CmsUserSettings;
035: import org.opencms.file.CmsObject;
036: import org.opencms.i18n.CmsLocaleManager;
037: import org.opencms.i18n.CmsMessages;
038: import org.opencms.util.CmsDataTypeUtil;
039: import org.opencms.util.CmsFileUtil;
040: import org.opencms.util.CmsPropertyUtils;
041: import org.opencms.util.CmsStringUtil;
042:
043: import java.io.FileDescriptor;
044: import java.io.FileInputStream;
045: import java.io.IOException;
046: import java.io.InputStreamReader;
047: import java.io.LineNumberReader;
048: import java.io.StreamTokenizer;
049: import java.io.StringReader;
050: import java.lang.reflect.InvocationTargetException;
051: import java.lang.reflect.Method;
052: import java.lang.reflect.Modifier;
053: import java.util.ArrayList;
054: import java.util.Collection;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.Locale;
058: import java.util.Map;
059: import java.util.TreeMap;
060:
061: import org.apache.commons.collections.ExtendedProperties;
062:
063: /**
064: * A command line interface to access OpenCms functions which
065: * is used for the initial setup and also can be used to directly access the OpenCms
066: * repository without the Workplace.<p>
067: *
068: * The CmsShell has direct access to all methods in the "command objects".
069: * Currently the following classes are used as command objects:
070: * <code>{@link org.opencms.main.CmsShellCommands}</code>,
071: * <code>{@link org.opencms.file.CmsRequestContext}</code> and
072: * <code>{@link org.opencms.file.CmsObject}</code>.<p>
073: *
074: * Only public methods in the command objects that use supported data types
075: * as parameters can be called from the shell. Supported data types are:
076: * <code>String, {@link org.opencms.util.CmsUUID}, boolean, int, long, double, float</code>.<p>
077: *
078: * If a method name is ambiguous, i.e. the method name with the same number of parameter exist
079: * in more then one of the command objects, the method is only executed on the first matching method object.<p>
080: *
081: * @author Alexander Kandzior
082: *
083: * @version $Revision: 1.53 $
084: *
085: * @since 6.0.0
086: *
087: * @see org.opencms.main.CmsShellCommands
088: * @see org.opencms.file.CmsRequestContext
089: * @see org.opencms.file.CmsObject
090: */
091: public class CmsShell {
092:
093: /**
094: * Command object class.<p>
095: */
096: private class CmsCommandObject {
097:
098: /** The list of methods. */
099: private Map m_methods;
100:
101: /** The object to execute the methods on. */
102: private Object m_object;
103:
104: /**
105: * Creates a new command object.<p>
106: *
107: * @param object the object to execute the methods on
108: */
109: protected CmsCommandObject(Object object) {
110:
111: m_object = object;
112: initShellMethods();
113: }
114:
115: /**
116: * Tries to execute a method for the provided parameters on this command object.<p>
117: *
118: * If methods with the same name and number of parameters exist in this command object,
119: * the given parameters are tried to be converted from String to matching types.<p>
120: *
121: * @param command the command entered by the user in the shell
122: * @param parameters the parameters entered by the user in the shell
123: * @return true if a method was executed, false otherwise
124: */
125: protected boolean executeMethod(String command, List parameters) {
126:
127: // TODO: ensure that publishmanager, oumanager and rolemanager methods are accessible
128: int todo;
129:
130: // build the method lookup
131: String lookup = buildMethodLookup(command, parameters
132: .size());
133:
134: // try to look up the methods of this command object
135: List possibleMethods = (List) m_methods.get(lookup);
136: if (possibleMethods == null) {
137: return false;
138: }
139:
140: // a match for the method name was found, now try to figure out if the parameters are ok
141: Method onlyStringMethod = null;
142: Method foundMethod = null;
143: Object[] params = null;
144: Iterator i;
145:
146: // first check if there is one method with only has String parameters, make this the fall back
147: i = possibleMethods.iterator();
148: while (i.hasNext()) {
149: Method method = (Method) i.next();
150: Class[] clazz = method.getParameterTypes();
151: boolean onlyString = true;
152: for (int j = 0; j < clazz.length; j++) {
153: if (!(clazz[j].equals(String.class))) {
154: onlyString = false;
155: break;
156: }
157: }
158: if (onlyString) {
159: onlyStringMethod = method;
160: break;
161: }
162: }
163:
164: // now check a method matches the provided parameters
165: // if so, use this method, else continue searching
166: i = possibleMethods.iterator();
167: while (i.hasNext()) {
168: Method method = (Method) i.next();
169: if (method == onlyStringMethod) {
170: // skip the String only signature because this would always match
171: continue;
172: }
173: // now try to convert the parameters to the required types
174: Class[] clazz = method.getParameterTypes();
175: Object[] converted = new Object[clazz.length];
176: boolean match = true;
177: for (int j = 0; j < clazz.length; j++) {
178: String value = (String) parameters.get(j);
179: try {
180: converted[j] = CmsDataTypeUtil.parse(value,
181: clazz[j]);
182: } catch (Throwable t) {
183: match = false;
184: break;
185: }
186: }
187: if (match) {
188: // we found a matching method signature
189: params = converted;
190: foundMethod = method;
191: break;
192: }
193:
194: }
195:
196: if ((foundMethod == null) && (onlyStringMethod != null)) {
197: // no match found but String only signature available, use this
198: params = parameters.toArray();
199: foundMethod = onlyStringMethod;
200: }
201:
202: if ((params == null) || (foundMethod == null)) {
203: // no match found at all
204: return false;
205: }
206:
207: // now try to invoke the method
208: try {
209: Object result = foundMethod.invoke(m_object, params);
210: if (result != null) {
211: if (result instanceof Collection) {
212: Collection c = (Collection) result;
213: System.out.println(c.getClass().getName()
214: + " (size: " + c.size() + ")");
215: int count = 0;
216: if (result instanceof Map) {
217: Map m = (Map) result;
218: Iterator j = m.entrySet().iterator();
219: while (j.hasNext()) {
220: Map.Entry entry = (Map.Entry) j.next();
221: System.out.println(count++ + ": "
222: + entry.getKey() + "= "
223: + entry.getValue());
224: }
225: } else {
226: Iterator j = c.iterator();
227: while (j.hasNext()) {
228: System.out.println(count++ + ": "
229: + j.next());
230: }
231: }
232: } else {
233: System.out.println(result.toString());
234: }
235: }
236: } catch (InvocationTargetException ite) {
237: System.out
238: .println(Messages
239: .get()
240: .getBundle(getLocale())
241: .key(
242: Messages.GUI_SHELL_EXEC_METHOD_1,
243: new Object[] { foundMethod
244: .getName() }));
245: ite.getTargetException().printStackTrace(System.out);
246: } catch (Throwable t) {
247: System.out
248: .println(Messages
249: .get()
250: .getBundle(getLocale())
251: .key(
252: Messages.GUI_SHELL_EXEC_METHOD_1,
253: new Object[] { foundMethod
254: .getName() }));
255: t.printStackTrace(System.out);
256: }
257:
258: return true;
259: }
260:
261: /**
262: * Returns a signature overview of all methods containing the given search String.<p>
263: *
264: * If no method name matches the given search String, the empty String is returned.<p>
265: *
266: * @param searchString the String to search for, if null all methods are shown
267: *
268: * @return a signature overview of all methods containing the given search String
269: */
270: protected String getMethodHelp(String searchString) {
271:
272: StringBuffer buf = new StringBuffer(512);
273: Iterator i = m_methods.keySet().iterator();
274: while (i.hasNext()) {
275: List l = (List) m_methods.get(i.next());
276: Iterator j = l.iterator();
277: while (j.hasNext()) {
278: Method method = (Method) j.next();
279: if ((searchString == null)
280: || (method.getName().toLowerCase().indexOf(
281: searchString.toLowerCase()) > -1)) {
282: buf.append("* ");
283: buf.append(method.getName());
284: buf.append("(");
285: Class[] params = method.getParameterTypes();
286: for (int k = 0; k < params.length; k++) {
287: String par = params[k].getName();
288: par = par
289: .substring(par.lastIndexOf('.') + 1);
290: if (k != 0) {
291: buf.append(", ");
292: }
293: buf.append(par);
294: }
295: buf.append(")\n");
296: }
297: }
298: }
299: return buf.toString();
300: }
301:
302: /**
303: * Returns the object to execute the methods on.<p>
304: *
305: * @return the object to execute the methods on
306: */
307: protected Object getObject() {
308:
309: return m_object;
310: }
311:
312: /**
313: * Builds a method lookup String.<p>
314: *
315: * @param methodName the name of the method
316: * @param paramCount the parameter count of the method
317: *
318: * @return a method lookup String
319: */
320: private String buildMethodLookup(String methodName,
321: int paramCount) {
322:
323: StringBuffer buf = new StringBuffer(32);
324: buf.append(methodName.toLowerCase());
325: buf.append(" [");
326: buf.append(paramCount);
327: buf.append("]");
328: return buf.toString();
329: }
330:
331: /**
332: * Initializes the map of accessible methods.<p>
333: */
334: private void initShellMethods() {
335:
336: Map result = new TreeMap();
337:
338: Method[] methods = m_object.getClass().getMethods();
339: for (int i = 0; i < methods.length; i++) {
340: // only public methods directly declared in the base class can be used in the shell
341: if ((methods[i].getDeclaringClass() == m_object
342: .getClass())
343: && (methods[i].getModifiers() == Modifier.PUBLIC)) {
344:
345: // check if the method signature only uses primitive data types
346: boolean onlyPrimitive = true;
347: Class[] clazz = methods[i].getParameterTypes();
348: for (int j = 0; j < clazz.length; j++) {
349: if (!CmsDataTypeUtil.isParseable(clazz[j])) {
350: // complex data type methods can not be called from the shell
351: onlyPrimitive = false;
352: break;
353: }
354: }
355:
356: if (onlyPrimitive) {
357: // add this method to the set of methods that can be called from the shell
358: String lookup = buildMethodLookup(methods[i]
359: .getName(), methods[i]
360: .getParameterTypes().length);
361: List l;
362: if (result.containsKey(lookup)) {
363: l = (List) result.get(lookup);
364: } else {
365: l = new ArrayList(1);
366: }
367: l.add(methods[i]);
368: result.put(lookup, l);
369: }
370: }
371: }
372: m_methods = result;
373: }
374: }
375:
376: /** Prefix for "base" parameter. */
377: public static final String SHELL_PARAM_BASE = "-base=";
378:
379: /** Prefix for "servletMapping" parameter. */
380: public static final String SHELL_PARAM_DEFAULT_WEB_APP = "-defaultWebApp=";
381:
382: /** Prefix for "script" parameter. */
383: public static final String SHELL_PARAM_SCRIPT = "-script=";
384:
385: /** Prefix for "servletMapping" parameter. */
386: public static final String SHELL_PARAM_SERVLET_MAPPING = "-servletMapping=";
387:
388: /** The OpenCms context object. */
389: protected CmsObject m_cms;
390:
391: /** Additional shell commands object. */
392: private I_CmsShellCommands m_additionaShellCommands;
393:
394: /** All shell callable objects. */
395: private List m_commandObjects;
396:
397: /** If set to true, all commands are echoed. */
398: private boolean m_echo;
399:
400: /** Indicates if the 'exit' command has been called. */
401: private boolean m_exitCalled;
402:
403: /** The messages object. */
404: private CmsMessages m_messages;
405:
406: /** The OpenCms system object. */
407: private OpenCmsCore m_opencms;
408:
409: /** The shell prompt format. */
410: private String m_prompt;
411:
412: /** The current users settings. */
413: private CmsUserSettings m_settings;
414:
415: /** Internal shell command object. */
416: private I_CmsShellCommands m_shellCommands;
417:
418: /**
419: * Creates a new CmsShell.<p>
420: *
421: * @param webInfPath the path to the 'WEB-INF' folder of the OpenCms installation
422: * @param servletMapping the mapping of the servlet (or <code>null</code> to use the default <code>"/opencms/*"</code>)
423: * @param defaultWebAppName the name of the default web application (or <code>null</code> to use the default <code>"ROOT"</code>)
424: * @param prompt the prompt format to set
425: * @param additionalShellCommands optional object for additional shell commands, or null
426: */
427: public CmsShell(String webInfPath, String servletMapping,
428: String defaultWebAppName, String prompt,
429: I_CmsShellCommands additionalShellCommands) {
430:
431: setPrompt(prompt);
432: if (CmsStringUtil.isEmpty(servletMapping)) {
433: servletMapping = "/opencms/*";
434: }
435: if (CmsStringUtil.isEmpty(defaultWebAppName)) {
436: defaultWebAppName = "ROOT";
437: }
438: try {
439: // first initialize runlevel 1
440: m_opencms = OpenCmsCore.getInstance();
441: // Externalization: get Locale: will be the System default since no CmsObject is up before
442: // runlevel 2
443: Locale locale = getLocale();
444: m_messages = Messages.get().getBundle(locale);
445: // search for the WEB-INF folder
446: if (CmsStringUtil.isEmpty(webInfPath)) {
447: System.out
448: .println(m_messages
449: .key(Messages.GUI_SHELL_NO_HOME_FOLDER_SPECIFIED_0));
450: System.out.println();
451: webInfPath = CmsFileUtil.searchWebInfFolder(System
452: .getProperty("user.dir"));
453: if (CmsStringUtil.isEmpty(webInfPath)) {
454: System.err.println(m_messages
455: .key(Messages.GUI_SHELL_HR_0));
456: System.err
457: .println(m_messages
458: .key(Messages.GUI_SHELL_NO_HOME_FOLDER_FOUND_0));
459: System.err.println();
460: System.err.println(m_messages
461: .key(Messages.GUI_SHELL_START_DIR_LINE1_0));
462: System.err.println(m_messages
463: .key(Messages.GUI_SHELL_START_DIR_LINE2_0));
464: System.err.println(m_messages
465: .key(Messages.GUI_SHELL_HR_0));
466: return;
467: }
468: }
469: System.out.println(Messages.get().getBundle(locale).key(
470: Messages.GUI_SHELL_WEB_INF_PATH_1, webInfPath));
471: // set the path to the WEB-INF folder (the 2nd and 3rd parameters are just reasonable dummies)
472: m_opencms.getSystemInfo().init(webInfPath, servletMapping,
473: null, defaultWebAppName, null);
474:
475: // now read the configuration properties
476: String propertyPath = m_opencms.getSystemInfo()
477: .getConfigurationFileRfsPath();
478: System.out.println(m_messages.key(
479: Messages.GUI_SHELL_CONFIG_FILE_1, propertyPath));
480: System.out.println();
481: ExtendedProperties configuration = CmsPropertyUtils
482: .loadProperties(propertyPath);
483:
484: // now upgrade to runlevel 2
485: m_opencms = m_opencms.upgradeRunlevel(configuration);
486:
487: // create a context object with 'Guest' permissions
488: m_cms = m_opencms.initCmsObject(m_opencms.getDefaultUsers()
489: .getUserGuest());
490:
491: // initialize the settings of the user
492: m_settings = initSettings();
493:
494: // initialize shell command object
495: m_shellCommands = new CmsShellCommands();
496: m_shellCommands.initShellCmsObject(m_cms, this );
497:
498: // initialize additional shell command object
499: if (additionalShellCommands != null) {
500: m_additionaShellCommands = additionalShellCommands;
501: m_additionaShellCommands
502: .initShellCmsObject(m_cms, null);
503: m_additionaShellCommands.shellStart();
504: } else {
505: m_shellCommands.shellStart();
506: }
507:
508: m_commandObjects = new ArrayList();
509: if (m_additionaShellCommands != null) {
510: // get all shell callable methods from the additional shell command object
511: m_commandObjects.add(new CmsCommandObject(
512: m_additionaShellCommands));
513: }
514: // get all shell callable methods from the CmsShellCommands
515: m_commandObjects.add(new CmsCommandObject(m_shellCommands));
516: // get all shell callable methods from the CmsRequestContext
517: m_commandObjects.add(new CmsCommandObject(m_cms
518: .getRequestContext()));
519: // get all shell callable methods from the CmsObject
520: m_commandObjects.add(new CmsCommandObject(m_cms));
521: } catch (Throwable t) {
522: t.printStackTrace(System.err);
523: }
524: }
525:
526: /**
527: * Main program entry point when started via the command line.<p>
528: *
529: * @param args parameters passed to the application via the command line
530: */
531: public static void main(String[] args) {
532:
533: boolean wrongUsage = false;
534: String webInfPath = null;
535: String script = null;
536: String servletMapping = null;
537: String defaultWebApp = null;
538:
539: if (args.length > 4) {
540: wrongUsage = true;
541: } else {
542: for (int i = 0; i < args.length; i++) {
543: String arg = args[i];
544: if (arg.startsWith(SHELL_PARAM_BASE)) {
545: webInfPath = arg.substring(SHELL_PARAM_BASE
546: .length());
547: } else if (arg.startsWith(SHELL_PARAM_SCRIPT)) {
548: script = arg.substring(SHELL_PARAM_SCRIPT.length());
549: } else if (arg.startsWith(SHELL_PARAM_SERVLET_MAPPING)) {
550: servletMapping = arg
551: .substring(SHELL_PARAM_SERVLET_MAPPING
552: .length());
553: } else if (arg.startsWith(SHELL_PARAM_DEFAULT_WEB_APP)) {
554: defaultWebApp = arg
555: .substring(SHELL_PARAM_DEFAULT_WEB_APP
556: .length());
557: } else {
558: System.out.println(Messages.get().getBundle().key(
559: Messages.GUI_SHELL_WRONG_USAGE_0));
560: wrongUsage = true;
561: }
562: }
563: }
564: if (wrongUsage) {
565: System.out.println(Messages.get().getBundle().key(
566: Messages.GUI_SHELL_USAGE_1,
567: CmsShell.class.getName()));
568: } else {
569: FileInputStream stream = null;
570: if (script != null) {
571: try {
572: stream = new FileInputStream(script);
573: } catch (IOException exc) {
574: System.out.println(Messages.get().getBundle()
575: .key(Messages.GUI_SHELL_ERR_SCRIPTFILE_1,
576: script));
577: }
578: }
579: if (stream == null) {
580: // no script-file, use standard input stream
581: stream = new FileInputStream(FileDescriptor.in);
582: }
583: CmsShell shell = new CmsShell(webInfPath, servletMapping,
584: defaultWebApp,
585: "${user}@${project}:${siteroot}|${uri}>", null);
586: shell.start(stream);
587: }
588: }
589:
590: /**
591: * Exits this shell and destroys the OpenCms instance.<p>
592: */
593: public void exit() {
594:
595: if (m_exitCalled) {
596: return;
597: }
598: m_exitCalled = true;
599: try {
600: if (m_additionaShellCommands != null) {
601: m_additionaShellCommands.shellExit();
602: } else {
603: m_shellCommands.shellExit();
604: }
605: } catch (Throwable t) {
606: t.printStackTrace();
607: }
608: try {
609: m_opencms.shutDown();
610: } catch (Throwable t) {
611: t.printStackTrace();
612: }
613: }
614:
615: /**
616: * Private internal helper for localization to the current user's locale
617: * within OpenCms. <p>
618: *
619: * @return the current user's <code>Locale</code>.
620: */
621: public Locale getLocale() {
622:
623: if (getSettings() == null) {
624: return CmsLocaleManager.getDefaultLocale();
625: }
626: return getSettings().getLocale();
627: }
628:
629: /**
630: * Returns the localized messages object for the current user.<p>
631: *
632: * @return the localized messages object for the current user
633: */
634: public CmsMessages getMessages() {
635:
636: return m_messages;
637: }
638:
639: /**
640: * Obtain the additional settings related to the current user.
641: *
642: * @return the additional settings related to the current user.
643: */
644: public CmsUserSettings getSettings() {
645:
646: return m_settings;
647: }
648:
649: /**
650: * Prints the shell prompt.<p>
651: */
652: public void printPrompt() {
653:
654: String prompt = m_prompt;
655: try {
656: prompt = CmsStringUtil.substitute(prompt, "${user}", m_cms
657: .getRequestContext().currentUser().getName());
658: prompt = CmsStringUtil.substitute(prompt, "${siteroot}",
659: m_cms.getRequestContext().getSiteRoot());
660: prompt = CmsStringUtil.substitute(prompt, "${project}",
661: m_cms.getRequestContext().currentProject()
662: .getName());
663: prompt = CmsStringUtil.substitute(prompt, "${uri}", m_cms
664: .getRequestContext().getUri());
665: } catch (Throwable t) {
666: // ignore
667: }
668: System.out.print(prompt);
669: }
670:
671: /**
672: * Sets the locale of the current user.<p>
673: *
674: * @param locale the locale to set
675: *
676: * @throws CmsException in case the locale of the current user can not be stored
677: */
678: public void setLocale(Locale locale) throws CmsException {
679:
680: CmsUserSettings settings = getSettings();
681: if (settings != null) {
682: settings.setLocale(locale);
683: settings.save(m_cms);
684: m_messages = Messages.get().getBundle(locale);
685: }
686: }
687:
688: /**
689: * Starts this CmsShell.<p>
690: *
691: * @param fileInputStream a (file) input stream from which commands are read
692: */
693: public void start(FileInputStream fileInputStream) {
694:
695: try {
696: // execute the commands from the input stream
697: executeCommands(fileInputStream);
698: } catch (Throwable t) {
699: t.printStackTrace(System.err);
700: }
701: }
702:
703: /**
704: * Shows the signature of all methods containing the given search String.<p>
705: *
706: * @param searchString the String to search for in the methods, if null all methods are shown
707: */
708: protected void help(String searchString) {
709:
710: String commandList;
711: boolean foundSomething = false;
712: System.out.println();
713:
714: Iterator i = m_commandObjects.iterator();
715: while (i.hasNext()) {
716: CmsCommandObject cmdObj = (CmsCommandObject) i.next();
717: commandList = cmdObj.getMethodHelp(searchString);
718: if (!CmsStringUtil.isEmpty(commandList)) {
719: System.out.println(m_messages.key(
720: Messages.GUI_SHELL_AVAILABLE_METHODS_1, cmdObj
721: .getObject().getClass().getName()));
722: System.out.println(commandList);
723: foundSomething = true;
724: }
725: }
726:
727: if (!foundSomething) {
728: System.out.println(m_messages.key(
729: Messages.GUI_SHELL_MATCH_SEARCHSTRING_1,
730: searchString));
731: }
732: }
733:
734: /**
735: * Initializes the internal <code>CmsWorkplaceSettings</code> that contain (amongst other
736: * information) important information additional information about the current user
737: * (an instance of {@link CmsUserSettings}).<p>
738: *
739: * This step is performed within the <code>CmsShell</code> constructor directly after
740: * switching to run-level 2 and obtaining the <code>CmsObject</code> for the guest user as
741: * well as when invoking the CmsShell command <code>login</code>.<p>
742: *
743: * @return the user settings for the current user.
744: */
745: protected CmsUserSettings initSettings() {
746:
747: m_settings = new CmsUserSettings(m_cms);
748: return m_settings;
749: }
750:
751: /**
752: * Sets the echo status.<p>
753: *
754: * @param echo the echo status to set
755: */
756: protected void setEcho(boolean echo) {
757:
758: m_echo = echo;
759: }
760:
761: /**
762: * Sets the current shell prompt.<p>
763: *
764: * To set the prompt, the following variables are available:<p>
765: *
766: * <code>$u</code> the current user name<br>
767: * <code>$s</code> the current site root<br>
768: * <code>$p</code> the current project name<p>
769: *
770: * @param prompt the prompt to set
771: */
772: protected void setPrompt(String prompt) {
773:
774: m_prompt = prompt;
775: }
776:
777: /**
778: * Executes a shell command with a list of parameters.<p>
779: *
780: * @param command the command to execute
781: * @param parameters the list of parameters for the command
782: */
783: private void executeCommand(String command, List parameters) {
784:
785: if (m_echo) {
786: // echo the command to STDOUT
787: System.out.print(command);
788: for (int i = 0; i < parameters.size(); i++) {
789: System.out.print(" " + parameters.get(i));
790: }
791: System.out.println();
792: }
793:
794: // prepare to lookup a method in CmsObject or CmsShellCommands
795: boolean executed = false;
796: Iterator i = m_commandObjects.iterator();
797: while (!executed && i.hasNext()) {
798: CmsCommandObject cmdObj = (CmsCommandObject) i.next();
799: executed = cmdObj.executeMethod(command, parameters);
800: }
801:
802: if (!executed) {
803: // method not found
804: System.out.println();
805: StringBuffer commandMsg = new StringBuffer(command)
806: .append("(");
807: for (int j = 0; j < parameters.size(); j++) {
808: commandMsg.append("value");
809: if (j < parameters.size() - 1) {
810: commandMsg.append(", ");
811: }
812: }
813: commandMsg.append(")");
814:
815: System.out.println(m_messages.key(
816: Messages.GUI_SHELL_METHOD_NOT_FOUND_1, commandMsg
817: .toString()));
818: System.out.println(m_messages.key(Messages.GUI_SHELL_HR_0));
819: ((CmsShellCommands) m_shellCommands).help();
820: }
821: }
822:
823: /**
824: * Executes all commands read from the given input stream.<p>
825: *
826: * @param fileInputStream a file input stream from which the commands are read
827: */
828: private void executeCommands(FileInputStream fileInputStream) {
829:
830: try {
831: LineNumberReader lnr = new LineNumberReader(
832: new InputStreamReader(fileInputStream));
833: while (!m_exitCalled) {
834: printPrompt();
835: String line = lnr.readLine();
836: if (line == null) {
837: // if null the file has been read to the end
838: try {
839: Thread.sleep(500);
840: } catch (Throwable t) {
841: // noop
842: }
843: break;
844: }
845: if (line.trim().startsWith("#")) {
846: System.out.println(line);
847: continue;
848: }
849: StringReader reader = new StringReader(line);
850: StreamTokenizer st = new StreamTokenizer(reader);
851: st.eolIsSignificant(true);
852:
853: // put all tokens into a List
854: List parameters = new ArrayList();
855: while (st.nextToken() != StreamTokenizer.TT_EOF) {
856: if (st.ttype == StreamTokenizer.TT_NUMBER) {
857: parameters.add(Integer.toString(new Double(
858: st.nval).intValue()));
859: } else {
860: parameters.add(st.sval);
861: }
862: }
863: reader.close();
864:
865: // extract command and arguments
866: if (parameters.size() == 0) {
867: if (m_echo) {
868: System.out.println();
869: }
870: continue;
871: }
872: String command = (String) parameters.get(0);
873: parameters = parameters.subList(1, parameters.size());
874:
875: // execute the command
876: executeCommand(command, parameters);
877: }
878: } catch (Throwable t) {
879: t.printStackTrace(System.err);
880: }
881: }
882: }
|