View Javadoc
1   /**
2    * Copyright 2014 Internet2
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  /*
17   * Copyright (C) 2006-2007 blair christensen.
18   * All Rights Reserved.
19   *
20   * You may use and distribute under the same terms as Grouper itself.
21   */
22  
23  package edu.internet2.middleware.grouper.app.gsh;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.lang.reflect.Method;
27  import java.util.ArrayList;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  
32  import jline.TerminalFactory;
33  
34  import org.apache.commons.lang.exception.ExceptionUtils;
35  import org.apache.commons.lang3.ArrayUtils;
36  import org.apache.commons.lang3.StringUtils;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.codehaus.groovy.control.CompilerConfiguration;
40  import org.codehaus.groovy.tools.shell.ExitNotification;
41  import org.codehaus.groovy.tools.shell.Groovysh;
42  import org.codehaus.groovy.tools.shell.IO;
43  import org.codehaus.groovy.tools.shell.util.Logger;
44  
45  import bsh.Interpreter;
46  import edu.internet2.middleware.grouper.GrouperSession;
47  import edu.internet2.middleware.grouper.SubjectFinder;
48  import edu.internet2.middleware.grouper.app.gsh.jline.WindowsTerminal;
49  import edu.internet2.middleware.grouper.app.gsh.template.GshTemplateReturnException;
50  import edu.internet2.middleware.grouper.app.loader.GrouperLoader;
51  import edu.internet2.middleware.grouper.audit.GrouperEngineBuiltin;
52  import edu.internet2.middleware.grouper.cfg.GrouperConfig;
53  import edu.internet2.middleware.grouper.hibernate.GrouperContext;
54  import edu.internet2.middleware.grouper.hibernate.HibernateSession;
55  import edu.internet2.middleware.grouper.hooks.beans.GrouperContextTypeBuiltIn;
56  import edu.internet2.middleware.grouper.misc.GrouperStartup;
57  import edu.internet2.middleware.grouper.util.GrouperUtil;
58  import edu.internet2.middleware.grouper.xml.export.XmlExportGsh;
59  import edu.internet2.middleware.grouper.xml.importXml.XmlImportGsh;
60  
61  /**
62   * Grouper Management Shell.
63   * <p/>
64   * @author  blair christensen.
65   * @version $Id: GrouperShell.java,v 1.18 2009-11-02 03:50:51 mchyzer Exp $
66   * @since   0.0.1
67   */
68  public class GrouperShell {
69    
70    /** if we should exit on failure */ 
71    static boolean exitOnFailure = false;
72    
73    private static Map<String, String> mainLookups = new HashMap<String, String>();
74    //TODO config file?
75    static {
76  	  mainLookups.put("-xmlimportold", 
77  			  "edu.internet2.middleware.grouper.xml.XmlImporter");
78  	  
79  	  mainLookups.put("-xmlexportold", 
80  			  "edu.internet2.middleware.grouper.xml.XmlExporter");
81  	  
82      mainLookups.put("-xmlimport", 
83        XmlImportGsh.class.getName());
84  
85      mainLookups.put("-xmlexport", 
86        XmlExportGsh.class.getName());
87  
88  	  mainLookups.put("-test",      
89  			  "edu.internet2.middleware.grouper.AllTests");
90  	  
91  	  mainLookups.put("-loader",    
92  			  "edu.internet2.middleware.grouper.app.loader.GrouperLoader");
93  	  
94  	  mainLookups.put("-usdu",      
95  			  "edu.internet2.middleware.grouper.app.usdu.USDU");
96  	  
97  	  mainLookups.put("-registry",  
98  			  "edu.internet2.middleware.grouper.registry.RegistryInitializeSchema");
99  	  
100 	  mainLookups.put("-findbadmemberships",  
101 			  "edu.internet2.middleware.grouper.misc.FindBadMemberships");
102 
103     mainLookups.put("-ldappc",  
104       "edu.internet2.middleware.ldappc.Ldappc");
105     
106     mainLookups.put("-ldappcng",
107         "edu.internet2.middleware.ldappc.spml.PSPCLI");
108     
109     mainLookups.put("-psp",
110         "edu.internet2.middleware.psp.PspCLI");
111     
112     mainLookups.put("-pspngattributestoprovisioningattributes",
113         "edu.internet2.middleware.grouper.app.provisioning.PspngToNewProvisioningAttributeConversion");
114 
115   }
116   
117   // PROTECTED CLASS CONSTANTS //
118   protected static final String NAME    = "gsh";
119 
120 
121   // PRIVATE CLASS CONSTANTS //
122   private static final String GSH_DEBUG   = "GSH_DEBUG";
123   private static final String GSH_DEVEL   = "GSH_DEVEL";
124   private static final String GSH_HISTORY = "_GSH_HISTORY";
125   private static final String GSH_OURS    = "_GSH_OURS";
126   private static final String GSH_SESSION = "_GSH_GROUPER_SESSION";
127   private static final String GSH_TIMER   = "GSH_TIMER";
128   
129 
130   // PRIVATE INSTANCE VARIABLES //
131   private Interpreter   interpreter = null;
132   private CommandReader r = null;
133 
134   /** if running from GSH */
135   public static boolean runFromGsh = false;
136   
137   /** if running from GSH interactively */
138   private static boolean runFromGshInteractive = false;
139   
140   private static ThreadLocal<String> groovyPreloadString = new ThreadLocal<String>();
141   
142   // MAIN //
143 
144   /**
145    * Run {@link GrouperShell}.
146    * <pre class="eg">
147    * // Launch GrouperShell in interactive mode
148    * % gsh.sh
149    *
150    * // Run GrouperShell script
151    * % gsh.sh script.gsh
152    * 
153    * // Read commands from STDIN
154    * % gsh.sh - 
155    * </pre>
156    * @param args 
157    * @since 0.0.1
158    */
159   public static void main(String args[]) {
160     //set this and leave it...
161     @SuppressWarnings("unused")
162     GrouperContext grouperContext = GrouperContext.createNewDefaultContext(
163         GrouperEngineBuiltin.GSH, false, true);
164     
165     boolean wasSpecialCase = handleSpecialCase(args);
166     if(wasSpecialCase) {
167     	return;
168     }
169 	  runFromGsh = true;
170 	
171     GrouperStartup.runFromMain = true;
172     GrouperStartup.startup();
173     GrouperStartup.waitForGrouperStartup();
174 
175     //turn on logging
176     Log bshLogger = LogFactory.getLog("bsh");
177     if (bshLogger.isTraceEnabled()) {
178       Interpreter.TRACE = true;
179     }
180     if (bshLogger.isDebugEnabled()) {
181       Interpreter.DEBUG = true;
182     }
183     exitOnFailure = true;
184     try {
185       grouperShellHelper(args, null);
186     }
187     catch (GrouperShellException eGS) {
188       eGS.printStackTrace();
189       LOG.error("GSH is exiting: " + eGS.getMessage(), eGS);
190       System.exit(1);
191     } catch (UnsatisfiedLinkError e) {
192       if (e.getMessage() != null && e.getMessage().contains("jansi")) {
193         System.err.println("\n\n\nUnable to start GSH.  Your tmpdir " + System.getProperty("java.io.tmpdir") + " may have the noexec flag set.  If so, set this environment variable: export GSH_JVMARGS=\"-Dlibrary.jansi.path=/some/other/temp/path/with/exec\"\n\n\n");
194       }
195       
196       throw new RuntimeException(e);
197     }
198     System.exit(0);
199   } // public static void main(args)
200   
201   
202  /**
203  * Avoid GSH initialisation for special cases 
204  * @param args - command line arguments
205  * @return whether this was handled as a special case
206  */
207 private static boolean handleSpecialCase(String[] args) {
208 	  if(args == null || args.length==0) {
209 		  return false;
210 	  }
211 	  if("-h".equalsIgnoreCase(args[0])||"-help".equalsIgnoreCase(args[0])) {
212 		  System.out.println(_getUsage());
213 		  return true;
214 	  }
215 	  
216 	  if("-nocheck".equalsIgnoreCase(args[0])) {
217 		  GrouperStartup.ignoreCheckConfig = true;
218 		  return false;
219 	  }
220 	  boolean isLoader = StringUtils.equals("-loader", args[0].toLowerCase());
221 	  String mainClass = mainLookups.get(args[0].toLowerCase());
222 	  if(mainClass==null) {
223 		  return false;
224 	  }
225 	  String[] mainArgs = new String[args.length -1];
226 	  for(int i=1;i<args.length;i++) {
227 		  mainArgs[i-1] = args[i];
228 	  }
229 	  
230 	  try {
231 		  Class claz = Class.forName(mainClass);
232 		  
233 		  Method method = claz.getMethod("main", String[].class);
234 		  method.invoke(null, (Object)mainArgs);
235 	  }catch(Exception e) {
236 	    if (ExceptionUtils.getFullStackTrace(e).contains("PSPCLI")) {
237 	      String error = "Make sure you have run 'ant dist' in ldappcng, and 'ant ldappcng' in grouper to copy the libs over";
238         LOG.fatal(error);
239         System.err.println(error);
240 	    }
241 		  if(e instanceof RuntimeException) {
242 			  throw (RuntimeException)e;
243 		  }
244 		  throw new RuntimeException(e);
245 	  } finally {
246 	    if (!isLoader) {
247 	      try {
248 	        GrouperLoader.shutdownIfStarted();
249 	      } catch (Exception e) {
250 	        LOG.error("error shutting down loader", e);
251 	      }
252 	    }
253 	  }
254 	  
255 	  return true;
256   } //private static boolean handleSpecialCase(args)
257  
258   /**
259    * helper method to kick off GSH without exiting
260    * @param args
261    * @param inputStreamParam if passing in an inputStream
262    * @throws GrouperShellException
263    */
264   static void grouperShellHelper(String args[], InputStream inputStreamParam) throws GrouperShellException {
265 
266     System.out.println("Type help() for instructions");
267     
268     GrouperContextTypeBuiltIn.setDefaultContext(GrouperContextTypeBuiltIn.GSH);
269     
270     boolean forceLegacyGsh = false;
271     if (args != null && args.length > 0 && args[0].equalsIgnoreCase("-forceLegacyGsh")) {
272       forceLegacyGsh = true;
273       args = ArrayUtils.remove(args, 0);
274     }
275     
276     boolean lightweightProfile = false;
277     if (args != null && args.length > 0 && args[0].equalsIgnoreCase("-lightWeightProfile")) {
278       lightweightProfile = true;
279       args = ArrayUtils.remove(args, 0);
280     }
281     
282     if (forceLegacyGsh || GrouperConfig.retrieveConfig().propertyValueBoolean("gsh.useLegacy", false)) {
283       new GrouperShell( new ShellCommandReader(args, inputStreamParam )).run();
284     } else {
285       
286       TerminalFactory.registerFlavor(TerminalFactory.Flavor.WINDOWS, WindowsTerminal.class);
287       
288       StringBuilder body = new StringBuilder();
289       
290       if (lightweightProfile) {
291         if (args != null && args.length > 0 && !args[0].equalsIgnoreCase("-check") && !args[0].equals("-runarg")) {
292           body.append(":load '" + GrouperUtil.fileFromResourceName("groovysh_lightWeightWithFile.profile").getAbsolutePath() + "'");
293         } else {
294           body.append(":load '" + GrouperUtil.fileFromResourceName("groovysh_lightWeight.profile").getAbsolutePath() + "'");
295         }
296       } else {
297         body.append(":load '" + GrouperUtil.fileFromResourceName("groovysh.profile").getAbsolutePath() + "'");
298       }
299       if (args != null && args.length > 0 && !args[0].equalsIgnoreCase("-check")) {
300         
301         if (args[0].equals("-main")) {
302           if (args.length == 1) {
303             throw new RuntimeException("When passing -main, pass at least one more argument, the class to run");
304           }
305           
306           // ok running a main method and exiting          
307           body.append("\n" + args[1] + ".main(");
308           
309           for(int i = 2; i < args.length; i++) {
310             body.append("\"" + args[i] + "\"");
311             if ((i + 1) < args.length) {
312               body.append(", ");
313             }
314           }
315           
316           body.append(")");
317         } else if (args[0].equals("-runarg")) {
318           if (args.length == 1) {
319             throw new RuntimeException("When passing -runarg, pass one other argument, the gsh command to run");
320           }
321           
322           String commands = args[1];
323           //if \\n was in there, then make it a newline...
324           commands = commands.replace("\\n", "\n");
325           body.append("\n" + commands);
326         } else {
327           body.append("\n" + ":gshFileLoad '" + args[0] + "'");
328         }
329         
330         body.append("\n:exit");
331       } else if (inputStreamParam != null) {
332         throw new RuntimeException("Unexpected (for now at least)");
333       } else {
334         runFromGshInteractive = true;
335       }
336       
337       groovyPreloadString.set(body.toString());
338       //org.codehaus.groovy.tools.shell.Main.main(new String[] { "-e", body.toString() });
339       
340       boolean exitOnError = !GrouperShell.runFromGshInteractive && GrouperConfig.retrieveConfig().propertyValueBoolean("gsh.exitOnNonInteractiveError", false);
341       
342       org.codehaus.groovy.tools.shell.Main.setTerminalType(TerminalFactory.AUTO, false);
343       IO io = new IO();
344       CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
345       Logger.io = io;
346       compilerConfiguration.setParameters(false);
347 
348       final Groovysh shell = new GrouperGroovysh(io, compilerConfiguration, exitOnError);
349       
350       Runtime.getRuntime().addShutdownHook(new Thread() {
351         public void run() {
352           try {
353             if (shell.getHistory() != null) {
354               shell.getHistory().flush();
355             }
356           } catch (IOException e) {
357             System.err.println("Error flushing GSH history: " + ExceptionUtils.getFullStackTrace(e));
358           }
359         }
360       });
361       
362       int code = 0;
363       try {        
364         code = shell.run(body.toString());
365       } catch (GshTemplateReturnException e) {
366       }
367 
368       System.exit(code);
369     }
370   }
371   
372   /**
373    * @param command
374    * @param t
375    */
376   public static void handleFileLoadError(String command, Throwable t) {
377     if (t instanceof GshTemplateReturnException) {
378       return;
379     }
380     // This gets called when loading a file.
381     // Note that this gets invoked (mostly) during a caught exception.  If an exception is thrown here, the gsh error handle (displayError) will end up being called.
382     // If we just print the error, then the processing will continue (e.g. next line of gsh file).
383     boolean exitOnNonInteractiveError = !GrouperShell.runFromGshInteractive && GrouperConfig.retrieveConfig().propertyValueBoolean("gsh.exitOnNonInteractiveError", false);
384     String error = "Error while running command (" + command +  ")";
385     if (exitOnNonInteractiveError) {
386       // note this doesnt always get logged
387       LOG.error("Error in command '" + command + "'", t);
388       throw new RuntimeException(error, t);
389     }
390       
391     System.err.println(error + ": " + ExceptionUtils.getFullStackTrace(t));
392   }
393   
394   /**
395    * @return groovy string to preload
396    */
397   public static String getGroovyPreloadString() {
398     return groovyPreloadString.get();
399   }
400 
401   // CONSTRUCTORS //
402 
403   // @since   0.1.1
404   protected GrouperShell(CommandReader r) 
405     throws  GrouperShellException
406   {
407     this.interpreter  = r.getInterpreter();
408     this.r  = r;
409   } // protected GrouperShell()
410 
411 
412   // PROTECTED CLASS METHODS //
413 
414   // @since   0.0.1
415   protected static void error(Interpreter i, Exception e) {
416     error(i, e, e.getMessage());
417   } // protected static void error(i, e)
418 
419   // @since   0.0.1
420   protected static void error(Interpreter interpreter, Exception e, String msg) {
421     interpreter.error(msg);
422     LOG.error("Error in GSH: " + msg, e);
423     if (isDebug(interpreter)) {
424       e.printStackTrace();
425     }
426     if (ShellHelper.closeOpenTransactions(interpreter, e)) {
427       ShellHelper.exitDueToOpenTransaction(interpreter);
428     }
429   } // protected static void error(i, e, msg)
430 
431   // @since   0.0.1
432   protected static Object get(Interpreter i, String key) 
433     throws  bsh.EvalError
434   {
435     return i.get(key);
436   } // protected static Object set(i, key)
437 
438   // @since   0.0.1
439   protected static List getHistory(Interpreter i) 
440     throws  bsh.EvalError
441   {
442     List history = (ArrayList) GrouperShell.get(i, GSH_HISTORY);
443     if (history == null) {
444       history = new ArrayList();
445     }
446     return history;
447   } // protected static List getHistory(i)
448 
449   // @since   0.0.1
450   protected static GrouperSession getSession(Interpreter i) 
451     throws  GrouperShellException
452   {
453     try {
454       //get static first
455       GrouperSession s = null;
456       
457       if (GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.gsh.useStaticGrouperSessionFirst", true)) {
458         s = GrouperSession.staticGrouperSession(false);
459       }
460       if (s==null) {
461         s = (GrouperSession) GrouperShell.get(i, GSH_SESSION);
462       }
463       if (s != null && s.getSubjectDb() == null) {
464         s = null;
465         GrouperShell.set(i, GSH_SESSION, s);
466       }
467       if (s == null) {
468         s = GrouperSession.staticGrouperSession(false);
469         
470         if (s == null) {
471           s = GrouperSession.start(
472             SubjectFinder.findRootSubject()
473           );
474         }
475         GrouperShell.set(i, GSH_SESSION, s);
476       }
477       return s;
478     }
479     catch (Exception e) {
480       if (i != null) {
481         i.error(e.getMessage());
482       }
483       throw new GrouperShellException(e);
484     }
485   } // protected static GrouperSession getSession(i)
486 
487   // @since   0.0.1
488   protected static boolean isDebug(Interpreter i) {
489     return _isTrue(i, GSH_DEBUG);
490   } // protected static boolean isDebug(i)
491 
492   // @return  True if last command run was a GrouperShell command.
493   // @since   0.0.1
494   protected static boolean isOurCommand(Interpreter i) {
495     return _isTrue(i, GSH_OURS);
496   } // protected static boolean isOurCommand()
497 
498   // @return  True if commands should be timed.
499   // @since   0.0.1
500   protected static boolean isTimed(Interpreter i) {
501     return _isTrue(i, GSH_TIMER);
502   } // protected static boolean isTimed()
503 
504   // @since   0.0.1
505   protected static void set(Interpreter i, String key, Object obj) 
506     throws  bsh.EvalError
507   {
508     i.set(key, obj);  
509   } // protected static void set(i, key, obj)
510 
511   // @since   0.0.1
512   protected static boolean isDevel(Interpreter i) {
513     return _isTrue(i, GSH_DEVEL);
514   } // protected static boolean isDevel(i)
515 
516   // @since   0.0.1
517   protected static void setHistory(Interpreter i, int cnt, String cmd) 
518     throws  bsh.EvalError
519   {
520     List history = GrouperShell.getHistory(i);
521     history.add(cnt, cmd);
522     GrouperShell.set(i, GSH_HISTORY, history);
523   } // protected static void setHistory(i, cnt, cmd)
524 
525   // @since   0.0.1
526   public static void setOurCommand(Interpreter i, boolean b) {
527     try {
528       GrouperShell.set(i, GSH_OURS, Boolean.valueOf(b));
529     }
530     catch (bsh.EvalError eBEE) {
531       i.error(eBEE.getMessage());
532     }
533   } // protected static void setOurCommand(i, b)
534 
535 
536   // PROTECTED INSTANCE METHODS //
537 
538   // @since   0.1.1
539   protected void run() 
540     throws  GrouperShellException
541   {
542     String cmd = new String();
543     try {
544       this.interpreter.eval(  "importCommands(\"edu.internet2.middleware.grouper\")");
545       this.interpreter.eval(  "importCommands(\"edu.internet2.middleware.grouper.app.gsh\")");
546       this.interpreter.eval(  "importCommands(\"edu.internet2.middleware.grouper.app.misc\")");
547       this.interpreter.eval(  "importCommands(\"edu.internet2.middleware.grouper.privs\")");
548       //this.i.eval(  "importCommands(\"edu.internet2.middleware.grouper.registry\")");
549       this.interpreter.eval(  "importCommands(\"edu.internet2.middleware.subject\")");
550       this.interpreter.eval(  "importCommands(\"edu.internet2.middleware.subject.provider\")");
551       this.interpreter.eval(  "import edu.internet2.middleware.grouper.*;");
552       this.interpreter.eval(  "import edu.internet2.middleware.grouper.authentication.*;");
553       this.interpreter.eval(  "import edu.internet2.middleware.grouper.app.loader.ldap.*;");
554       this.interpreter.eval(  "import edu.internet2.middleware.grouper.attr.*;");
555       this.interpreter.eval(  "import edu.internet2.middleware.grouper.attr.assign.*;");
556       this.interpreter.eval(  "import edu.internet2.middleware.grouper.attr.finder.*;");
557       this.interpreter.eval(  "import edu.internet2.middleware.grouper.attr.value.*;");
558       this.interpreter.eval(  "import edu.internet2.middleware.grouper.audit.*;");
559       this.interpreter.eval(  "import edu.internet2.middleware.grouper.client.*;");
560       this.interpreter.eval(  "import edu.internet2.middleware.grouper.entity.*;");
561       this.interpreter.eval(  "import edu.internet2.middleware.grouper.externalSubjects.*;");
562       this.interpreter.eval(  "import edu.internet2.middleware.grouper.group.*;");
563       this.interpreter.eval(  "import edu.internet2.middleware.grouper.ldap.*;");
564       this.interpreter.eval(  "import edu.internet2.middleware.grouper.app.loader.*;");
565       this.interpreter.eval(  "import edu.internet2.middleware.grouper.xml.*;");
566       this.interpreter.eval(  "import edu.internet2.middleware.grouper.registry.*;");
567       this.interpreter.eval(  "import edu.internet2.middleware.grouper.app.usdu.*;");
568       this.interpreter.eval(  "import edu.internet2.middleware.grouper.app.provisioning.*;");
569       this.interpreter.eval(  "import edu.internet2.middleware.grouper.app.gsh.*;");
570       this.interpreter.eval(  "import edu.internet2.middleware.grouper.app.misc.*;");
571       this.interpreter.eval(  "import edu.internet2.middleware.grouper.privs.*;");
572       this.interpreter.eval(  "import edu.internet2.middleware.grouper.rules.*;");
573       this.interpreter.eval(  "import edu.internet2.middleware.grouper.misc.*;");
574       this.interpreter.eval(  "import edu.internet2.middleware.grouper.hibernate.*;");
575       this.interpreter.eval(  "import edu.internet2.middleware.grouper.permissions.*;");
576       this.interpreter.eval(  "import edu.internet2.middleware.grouper.util.*;");
577       this.interpreter.eval(  "import edu.internet2.middleware.grouper.xml.export.*;");
578       this.interpreter.eval(  "import edu.internet2.middleware.subject.*;");
579       this.interpreter.eval(  "import edu.internet2.middleware.subject.provider.*;");
580       this.interpreter.eval(  "import edu.internet2.middleware.grouper.userData.*;");
581       this.interpreter.eval(  "import edu.internet2.middleware.grouper.messaging.*;");
582       
583     }
584     catch (bsh.EvalError eBBB) {
585       throw new GrouperShellException(GshErrorMessages.I_IMPORT + eBBB.getMessage(), eBBB);
586     }
587     while ( ( cmd = r.getNext() ) != null) {
588       if ( this._isComment(cmd) ) {
589         continue;
590       }
591       if ( this._isTimeToExit(cmd) ) {
592         int txSize = HibernateSession._internal_staticSessions().size();
593         boolean hasTransactions = txSize>0;
594         if (hasTransactions) {
595           String error = "Exiting in the middle of " + txSize + " open transactions, they will be rolled back and closed";
596           this.interpreter.println(error);
597           LOG.error(error);
598           HibernateSession._internal_closeAllHibernateSessions(new RuntimeException());
599         }
600         this._stopSession();
601         if (hasTransactions) {
602           ShellHelper.exitDueToOpenTransaction(this.interpreter);
603         }
604         break;
605       }
606       // Now try to eval the command
607       cmd = ShellHelper.eval(interpreter, cmd);
608     }
609   } 
610 
611   /** logger */
612   private static final Log LOG = GrouperUtil.getLog(GrouperShell.class);
613 
614   /**
615    * 
616    * @param i
617    * @param var
618    * @return true if istrue
619    */
620   private static boolean _isTrue(Interpreter i, String var) {
621     boolean rv = false;
622     try {
623       Object  obj = GrouperShell.get(i, var);
624     if (
625                 (obj != null)
626             &&  (obj instanceof Boolean)
627             &&  (Boolean.TRUE.equals( obj ))
628          )
629       {
630         rv = true;
631       }
632     }
633     catch (bsh.EvalError eBEE) {
634       i.error(eBEE.getMessage());
635     }
636     return rv;
637   } // private static boolean _isTrue(i, var)
638 
639 
640   // PRIVATE INSTANCE METHODS //
641 
642   // I'm not sure if this is the best place for this but...
643   // @since   1.1.0
644   private boolean _isComment(String cmd) {
645     if ( cmd.startsWith("#") || cmd.startsWith("//") ) {
646       return true;
647     }
648     return false;
649   } // private boolean _isComment(cmd)
650 
651   // I'm not sure if this is the best place for this but...
652   // @since   1.1.0
653   private boolean _isTimeToExit(String cmd) {
654     if ( cmd.equals("exit") || cmd.equals("quit") ) {
655       return true;
656     }
657     return false;
658   } // private boolean _isTimeToExit(cmd)
659 
660   // @since   0.0.1
661   private void _stopSession() 
662     throws  GrouperShellException
663   {
664     try {
665       // `GrouperShell.getSession()` will start the session if it doesn't exist.
666       // That's just slow.  And wrong.
667       GrouperSession../../../../../edu/internet2/middleware/grouper/GrouperSession.html#GrouperSession">GrouperSession s = (GrouperSession) GrouperShell.get(this.interpreter, GSH_SESSION);
668       if (s != null) {
669         s.stop();
670         this.interpreter.unset(GSH_SESSION);
671       }
672     }
673     catch (Exception e) {
674       if (interpreter != null) {
675         this.interpreter.error(e.getMessage());
676       }
677       throw new GrouperShellException(e);
678     }
679   } // private void _stopSession()
680   
681   private static String _getUsage() {
682 	    return  "Usage:"                                                                   + GrouperConfig.NL
683 	            + "args: -h,               Prints this message"                            + GrouperConfig.NL
684 	            + "args: <filename>,       Execute commands in specified file"             + GrouperConfig.NL
685 	            + "no args:                Enters an interactive shell"                    + GrouperConfig.NL
686 	            + "args: -lightWeightProfile"                                              + GrouperConfig.NL
687 	            + "       Use alternate init script (classes/groovysh_lightWeight.profile)" + GrouperConfig.NL
688 	            + "       which has less imports and may improve startup performance"      + GrouperConfig.NL
689 	            + "args: -nocheck,         Skips startup check and enters an "          + GrouperConfig.NL
690 	            + "                        interactive shell"                              + GrouperConfig.NL
691 	            + "args: -runarg <command> Run command (use \\\\n to separate commands)"   + GrouperConfig.NL
692 	            + "args: -main <class> [args...]                                    "      + GrouperConfig.NL
693 	            + "   class,               Full class name (must have main method)"        + GrouperConfig.NL
694 	            + "   args,                args as required by main method of class"       + GrouperConfig.NL
695 	            + "args: -initEnv [<configDir>]"                                           + GrouperConfig.NL
696 	            + "       On Windows sets GROUPER_HOME and adds GROUPER_HOME/bin to path"  + GrouperConfig.NL
697 	            + "       For *nix 'source gsh.sh' for the same result"                    + GrouperConfig.NL
698 	            + "       configDir optionally adds an alternative conf directory than"    + GrouperConfig.NL 
699 	            + "       GROUPER_HOME/conf to the classpath"                              + GrouperConfig.NL
700 	            + "args: (-xmlimport | -xmlexport | -loader | -test | -registry | -usdu |"   + GrouperConfig.NL
701 	            + "       -findbadmemberships | -ldappc | pspngAttributesToProvisioningAttributes) "
702 	            + "                        Enter option to get additional usage for that " + GrouperConfig.NL
703 	            + "                        option "                                        + GrouperConfig.NL
704 	            
705 	            + "  -xmlimport,           Invokes XmlImporter*"                           + GrouperConfig.NL
706 	            + "                        *XML format has changed in v1.6. To import"     + GrouperConfig.NL
707 	            + "                        the original XML format use -xmlimportold"      + GrouperConfig.NL
708 	            + "  -xmlexport,           Invokes XmlExporter"                            + GrouperConfig.NL
709 	            + "  -loader,              Invokes GrouperLoader"                          + GrouperConfig.NL
710 	            + "  -registry,            Manipulate the Grouper schema and install"      + GrouperConfig.NL
711 	            + "                        bootstrap data"                                 + GrouperConfig.NL
712 	            + "  -test,                Run JUnit tests"                                + GrouperConfig.NL
713 	             
714 	            + "  -usdu,                Invoke USDU - Unresolvable Subject Deletion "   + GrouperConfig.NL
715 	            + "                        Utility"                                        + GrouperConfig.NL
716 	            + "  -pspngAttributesToProvisioningAttributes Copies pspng attributes to provisioning"  + GrouperConfig.NL
717 	           
718 	            + "  -findbadmemberships,  Check for membership data inconsistencies    "  + GrouperConfig.NL
719                 + "  -ldappc,              Run the grouper ldap provisioning connector to send data to ldap    "  + GrouperConfig.NL
720 	            ;
721 	  } // private static String _getUsage()
722 
723 } // public class GrouperShell
724