View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.start;
20  
21  import static org.eclipse.jetty.start.UsageException.*;
22  
23  import java.io.File;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.nio.file.Path;
27  import java.util.ArrayList;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.ListIterator;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.StringTokenizer;
36  
37  import org.eclipse.jetty.start.Props.Prop;
38  import org.eclipse.jetty.start.config.ConfigSource;
39  import org.eclipse.jetty.start.config.ConfigSources;
40  import org.eclipse.jetty.start.config.DirConfigSource;
41  
42  /**
43   * The Arguments required to start Jetty.
44   */
45  public class StartArgs
46  {
47      public static final String VERSION;
48  
49      static
50      {
51          String ver = System.getProperty("jetty.version",null);
52  
53          if (ver == null)
54          {
55              Package pkg = StartArgs.class.getPackage();
56              if ((pkg != null) && "Eclipse.org - Jetty".equals(pkg.getImplementationVendor()) && (pkg.getImplementationVersion() != null))
57              {
58                  ver = pkg.getImplementationVersion();
59              }
60          }
61  
62          if (ver == null)
63          {
64              ver = "TEST";
65          }
66  
67          VERSION = ver;
68          System.setProperty("jetty.version",VERSION);
69      }
70  
71      private static final String SERVER_MAIN = "org.eclipse.jetty.xml.XmlConfiguration";
72  
73      /** List of enabled modules */
74      private Set<String> modules = new HashSet<>();
75      /** Map of enabled modules to the source of where that activation occurred */
76      private Map<String, List<String>> sources = new HashMap<>();
77      /** Map of properties to where that property was declared */
78      private Map<String, String> propertySource = new HashMap<>();
79      /** List of all active [files] sections from enabled modules */
80      private List<FileArg> files = new ArrayList<>();
81      /** List of all active [lib] sectinos from enabled modules */
82      private Classpath classpath;
83      /** List of all active [xml] sections from enabled modules */
84      private List<Path> xmls = new ArrayList<>();
85      /** JVM arguments, found via commmand line and in all active [exec] sections from enabled modules */
86      private List<String> jvmArgs = new ArrayList<>();
87  
88      /** List of all xml references found directly on command line or start.ini */
89      private List<String> xmlRefs = new ArrayList<>();
90  
91      /** List of all property references found directly on command line or start.ini */
92      private List<String> propertyFileRefs = new ArrayList<>();
93      
94      /** List of all property files */
95      private List<Path> propertyFiles = new ArrayList<>();
96  
97      private Props properties = new Props();
98      private Set<String> systemPropertyKeys = new HashSet<>();
99      private List<String> rawLibs = new ArrayList<>();
100 
101     // jetty.base - build out commands
102     /** --add-to-startd=[module,[module]] */
103     private List<String> addToStartdIni = new ArrayList<>();
104     /** --add-to-start=[module,[module]] */
105     private List<String> addToStartIni = new ArrayList<>();
106 
107     // module inspection commands
108     /** --write-module-graph=[filename] */
109     private String moduleGraphFilename;
110 
111     /** Collection of all modules */
112     private Modules allModules;
113     /** Should the server be run? */
114     private boolean run = true;
115     private boolean download = false;
116     private boolean help = false;
117     private boolean stopCommand = false;
118     private boolean listModules = false;
119     private boolean listClasspath = false;
120     private boolean listConfig = false;
121     private boolean version = false;
122     private boolean dryRun = false;
123 
124     private boolean exec = false;
125 
126     public StartArgs()
127     {
128         classpath = new Classpath();
129     }
130 
131     private void addFile(String uriLocation)
132     {
133         FileArg arg = new FileArg(uriLocation);
134         if (!files.contains(arg))
135         {
136             files.add(arg);
137         }
138     }
139 
140     public void addSystemProperty(String key, String value)
141     {
142         this.systemPropertyKeys.add(key);
143         System.setProperty(key,value);
144     }
145 
146     private void addUniqueXmlFile(String xmlRef, Path xmlfile) throws IOException
147     {
148         if (!FS.canReadFile(xmlfile))
149         {
150             throw new IOException("Cannot read file: " + xmlRef);
151         }
152         xmlfile = FS.toRealPath(xmlfile);
153         if (!xmls.contains(xmlfile))
154         {
155             xmls.add(xmlfile);
156         }
157     }
158     
159     private void addUniquePropertyFile(String propertyFileRef, Path propertyFile) throws IOException
160     {
161         if (!FS.canReadFile(propertyFile))
162         {
163             throw new IOException("Cannot read file: " + propertyFileRef);
164         }
165         propertyFile = FS.toRealPath(propertyFile);
166         if (!propertyFiles.contains(propertyFile))
167         {
168             propertyFiles.add(propertyFile);
169         }
170     }
171 
172     public void dumpActiveXmls(BaseHome baseHome)
173     {
174         System.out.println();
175         System.out.println("Jetty Active XMLs:");
176         System.out.println("------------------");
177         if (xmls.isEmpty())
178         {
179             System.out.println(" (no xml files specified)");
180             return;
181         }
182 
183         for (Path xml : xmls)
184         {
185             System.out.printf(" %s%n",baseHome.toShortForm(xml.toAbsolutePath()));
186         }
187     }
188 
189     public void dumpEnvironment(BaseHome baseHome)
190     {
191         // Java Details
192         System.out.println();
193         System.out.println("Java Environment:");
194         System.out.println("-----------------");
195         dumpSystemProperty("java.home");
196         dumpSystemProperty("java.vm.vendor");
197         dumpSystemProperty("java.vm.version");
198         dumpSystemProperty("java.vm.name");
199         dumpSystemProperty("java.vm.info");
200         dumpSystemProperty("java.runtime.name");
201         dumpSystemProperty("java.runtime.version");
202         dumpSystemProperty("java.io.tmpdir");
203         dumpSystemProperty("user.dir");
204         dumpSystemProperty("user.language");
205         dumpSystemProperty("user.country");
206 
207         // Jetty Environment
208         System.out.println();
209         System.out.println("Jetty Environment:");
210         System.out.println("-----------------");
211         dumpProperty("jetty.version");
212         dumpProperty("jetty.home");
213         dumpProperty("jetty.base");
214         
215         // Jetty Configuration Environment
216         System.out.println();
217         System.out.println("Config Search Order:");
218         System.out.println("--------------------");
219         for (ConfigSource config : baseHome.getConfigSources())
220         {
221             System.out.printf(" %s",config.getId());
222             if (config instanceof DirConfigSource)
223             {
224                 DirConfigSource dirsource = (DirConfigSource)config;
225                 if (dirsource.isPropertyBased())
226                 {
227                     System.out.printf(" -> %s",dirsource.getDir());
228                 }
229             }
230             System.out.println();
231         }
232         
233         // Jetty Se
234         System.out.println();
235     }
236 
237     public void dumpJvmArgs()
238     {
239         System.out.println();
240         System.out.println("JVM Arguments:");
241         System.out.println("--------------");
242         if (jvmArgs.isEmpty())
243         {
244             System.out.println(" (no jvm args specified)");
245             return;
246         }
247 
248         for (String jvmArgKey : jvmArgs)
249         {
250             String value = System.getProperty(jvmArgKey);
251             if (value != null)
252             {
253                 System.out.printf(" %s = %s%n",jvmArgKey,value);
254             }
255             else
256             {
257                 System.out.printf(" %s%n",jvmArgKey);
258             }
259         }
260     }
261 
262     public void dumpProperties()
263     {
264         System.out.println();
265         System.out.println("Properties:");
266         System.out.println("-----------");
267 
268         List<String> sortedKeys = new ArrayList<>();
269         for (Prop prop : properties)
270         {
271             if (prop.origin.equals(Props.ORIGIN_SYSPROP))
272             {
273                 continue; // skip
274             }
275             sortedKeys.add(prop.key);
276         }
277 
278         if (sortedKeys.isEmpty())
279         {
280             System.out.println(" (no properties specified)");
281             return;
282         }
283 
284         Collections.sort(sortedKeys);
285 
286         for (String key : sortedKeys)
287         {
288             dumpProperty(key);
289         }
290     }
291 
292     private void dumpProperty(String key)
293     {
294         Prop prop = properties.getProp(key);
295         if (prop == null)
296         {
297             System.out.printf(" %s (not defined)%n",key);
298         }
299         else
300         {
301             System.out.printf(" %s = %s%n",key,properties.expand(prop.value));
302             if (StartLog.isDebugEnabled())
303             {
304                 System.out.printf("   origin: %s%n",prop.origin);
305                 while (prop.overrides != null)
306                 {
307                     prop = prop.overrides;
308                     System.out.printf("   (overrides)%n");
309                     System.out.printf("     %s = %s%n",key,properties.expand(prop.value));
310                     System.out.printf("     origin: %s%n",prop.origin);
311                 }
312             }
313         }
314     }
315 
316     public void dumpSystemProperties()
317     {
318         System.out.println();
319         System.out.println("System Properties:");
320         System.out.println("------------------");
321 
322         if (systemPropertyKeys.isEmpty())
323         {
324             System.out.println(" (no system properties specified)");
325             return;
326         }
327 
328         List<String> sortedKeys = new ArrayList<>();
329         sortedKeys.addAll(systemPropertyKeys);
330         Collections.sort(sortedKeys);
331 
332         for (String key : sortedKeys)
333         {
334             String value = System.getProperty(key);
335             System.out.printf(" %s = %s%n",key,properties.expand(value));
336         }
337     }
338 
339     private void dumpSystemProperty(String key)
340     {
341         System.out.printf(" %s = %s%n",key,System.getProperty(key));
342     }
343 
344     /**
345      * Ensure that the System Properties are set (if defined as a System property, or start.config property, or start.ini property)
346      * 
347      * @param key
348      *            the key to be sure of
349      */
350     private void ensureSystemPropertySet(String key)
351     {
352         if (systemPropertyKeys.contains(key))
353         {
354             return; // done
355         }
356 
357         if (properties.containsKey(key))
358         {
359             String val = properties.expand(properties.getString(key));
360             if (val == null)
361             {
362                 return; // no value to set
363             }
364             // setup system property
365             systemPropertyKeys.add(key);
366             System.setProperty(key,val);
367         }
368     }
369 
370     /**
371      * Expand any command line added <code>--lib</code> lib references.
372      * 
373      * @param baseHome
374      * @throws IOException
375      */
376     public void expandLibs(BaseHome baseHome) throws IOException
377     {
378         for (String rawlibref : rawLibs)
379         {
380             StartLog.debug("rawlibref = " + rawlibref);
381             String libref = properties.expand(rawlibref);
382             StartLog.debug("expanded = " + libref);
383             
384             // perform path escaping (needed by windows)
385             libref = libref.replaceAll("\\\\([^\\\\])","\\\\\\\\$1");
386             
387             for (Path libpath : baseHome.getPaths(libref))
388             {
389                 classpath.addComponent(libpath.toFile());
390             }
391         }
392     }
393 
394     /**
395      * Build up the Classpath and XML file references based on enabled Module list.
396      * 
397      * @param baseHome
398      * @param activeModules
399      * @throws IOException
400      */
401     public void expandModules(BaseHome baseHome, List<Module> activeModules) throws IOException
402     {
403         for (Module module : activeModules)
404         {
405             // Find and Expand Libraries
406             for (String rawlibref : module.getLibs())
407             {
408                 StartLog.debug("rawlibref = " + rawlibref);
409                 String libref = properties.expand(rawlibref);
410                 StartLog.debug("expanded = " + libref);
411 
412                 for (Path libpath : baseHome.getPaths(libref))
413                 {
414                     classpath.addComponent(libpath.toFile());
415                 }
416             }
417 
418             for (String jvmArg : module.getJvmArgs())
419             {
420                 exec = true;
421                 jvmArgs.add(jvmArg);
422             }
423 
424             // Find and Expand XML files
425             for (String xmlRef : module.getXmls())
426             {
427                 // Straight Reference
428                 Path xmlfile = baseHome.getPath(xmlRef);
429                 addUniqueXmlFile(xmlRef,xmlfile);
430             }
431 
432             // Register Download operations
433             for (String file : module.getFiles())
434             {
435                 StartLog.debug("Adding module specified file: %s",file);
436                 addFile(file);
437             }
438         }
439     }
440 
441     public List<String> getAddToStartdIni()
442     {
443         return addToStartdIni;
444     }
445 
446     public List<String> getAddToStartIni()
447     {
448         return addToStartIni;
449     }
450 
451     public Modules getAllModules()
452     {
453         return allModules;
454     }
455 
456     public Classpath getClasspath()
457     {
458         return classpath;
459     }
460 
461     public Set<String> getEnabledModules()
462     {
463         return this.modules;
464     }
465 
466     public List<FileArg> getFiles()
467     {
468         return files;
469     }
470 
471     public List<String> getJvmArgs()
472     {
473         return jvmArgs;
474     }
475 
476     public CommandLineBuilder getMainArgs(BaseHome baseHome, boolean addJavaInit) throws IOException
477     {
478         CommandLineBuilder cmd = new CommandLineBuilder();
479 
480         if (addJavaInit)
481         {
482             cmd.addRawArg(CommandLineBuilder.findJavaBin());
483 
484             for (String x : jvmArgs)
485             {
486                 cmd.addRawArg(x);
487             }
488 
489             cmd.addRawArg("-Djetty.home=" + baseHome.getHome());
490             cmd.addRawArg("-Djetty.base=" + baseHome.getBase());
491 
492             // System Properties
493             for (String propKey : systemPropertyKeys)
494             {
495                 String value = System.getProperty(propKey);
496                 cmd.addEqualsArg("-D" + propKey,value);
497             }
498 
499             cmd.addRawArg("-cp");
500             cmd.addRawArg(classpath.toString());
501             cmd.addRawArg(getMainClassname());
502         }
503 
504         // Special Stop/Shutdown properties
505         ensureSystemPropertySet("STOP.PORT");
506         ensureSystemPropertySet("STOP.KEY");
507         ensureSystemPropertySet("STOP.WAIT");
508 
509         // Check if we need to pass properties as a file
510         if (properties.size() > 0)
511         {
512             File prop_file = File.createTempFile("start",".properties");
513             if (!dryRun)
514             {
515                 prop_file.deleteOnExit();
516             }
517             try (FileOutputStream out = new FileOutputStream(prop_file))
518             {
519                 properties.store(out,"start.jar properties");
520             }
521             cmd.addRawArg(prop_file.getAbsolutePath());
522         }
523 
524         for (Path xml : xmls)
525         {
526             cmd.addRawArg(xml.toAbsolutePath().toString());
527         }
528         
529         for (Path propertyFile : propertyFiles)
530         {
531             cmd.addRawArg(propertyFile.toAbsolutePath().toString());
532         }
533 
534         return cmd;
535     }
536 
537     public String getMainClassname()
538     {
539         String mainclass = System.getProperty("jetty.server",SERVER_MAIN);
540         return System.getProperty("main.class",mainclass);
541     }
542 
543     public String getModuleGraphFilename()
544     {
545         return moduleGraphFilename;
546     }
547 
548     public Props getProperties()
549     {
550         return properties;
551     }
552 
553     public List<String> getSources(String module)
554     {
555         return sources.get(module);
556     }
557 
558     public List<Path> getXmlFiles()
559     {
560         return xmls;
561     }
562 
563     public boolean hasJvmArgs()
564     {
565         return jvmArgs.size() > 0;
566     }
567 
568     public boolean hasSystemProperties()
569     {
570         for (String key : systemPropertyKeys)
571         {
572             // ignored keys
573             if ("jetty.home".equals(key) || "jetty.base".equals(key))
574             {
575                 // skip
576                 continue;
577             }
578             return true;
579         }
580         return false;
581     }
582 
583     public boolean isDownload()
584     {
585         return download;
586     }
587 
588     public boolean isDryRun()
589     {
590         return dryRun;
591     }
592 
593     public boolean isExec()
594     {
595         return exec;
596     }
597 
598     public boolean isHelp()
599     {
600         return help;
601     }
602 
603     public boolean isListClasspath()
604     {
605         return listClasspath;
606     }
607 
608     public boolean isListConfig()
609     {
610         return listConfig;
611     }
612 
613     public boolean isListModules()
614     {
615         return listModules;
616     }
617 
618     public boolean isRun()
619     {
620         return run;
621     }
622 
623     public boolean isStopCommand()
624     {
625         return stopCommand;
626     }
627 
628     public boolean isVersion()
629     {
630         return version;
631     }
632 
633     public void parse(ConfigSources sources)
634     {
635         ListIterator<ConfigSource> iter = sources.reverseListIterator();
636         while (iter.hasPrevious())
637         {
638             ConfigSource source = iter.previous();
639             for (String arg : source.getArgs())
640             {
641                 parse(arg,source.getId());
642             }
643         }
644     }
645 
646     public void parse(final String rawarg, String source)
647     {
648         if (rawarg == null)
649         {
650             return;
651         }
652 
653         final String arg = rawarg.trim();
654 
655         if (arg.length() <= 0)
656         {
657             return;
658         }
659 
660         if (arg.startsWith("#"))
661         {
662             return;
663         }
664 
665         if ("--help".equals(arg) || "-?".equals(arg))
666         {
667             help = true;
668             run = false;
669             return;
670         }
671 
672         if ("--debug".equals(arg) || arg.startsWith("--start-log-file"))
673         {
674             // valid, but handled in StartLog instead
675             return;
676         }
677 
678         if (arg.startsWith("--include-jetty-dir="))
679         {
680             // valid, but handled in ConfigSources instead
681             return;
682         }
683 
684         if ("--stop".equals(arg))
685         {
686             stopCommand = true;
687             run = false;
688             return;
689         }
690 
691         if (arg.startsWith("--download="))
692         {
693             addFile(Props.getValue(arg));
694             run = false;
695             download = true;
696             return;
697         }
698 
699         if (arg.equals("--create-files"))
700         {
701             run = false;
702             download = true;
703             return;
704         }
705 
706         if ("--list-classpath".equals(arg) || "--version".equals(arg) || "-v".equals(arg) || "--info".equals(arg))
707         {
708             listClasspath = true;
709             run = false;
710             return;
711         }
712 
713         if ("--list-config".equals(arg))
714         {
715             listConfig = true;
716             run = false;
717             return;
718         }
719 
720         if ("--dry-run".equals(arg) || "--exec-print".equals(arg))
721         {
722             dryRun = true;
723             run = false;
724             return;
725         }
726 
727         // Enable forked execution of Jetty server
728         if ("--exec".equals(arg))
729         {
730             exec = true;
731             return;
732         }
733 
734         // Arbitrary Libraries
735         if (arg.startsWith("--lib="))
736         {
737             String cp = Props.getValue(arg);
738 
739             if (cp != null)
740             {
741                 StringTokenizer t = new StringTokenizer(cp,File.pathSeparator);
742                 while (t.hasMoreTokens())
743                 {
744                     rawLibs.add(t.nextToken());
745                 }
746             }
747             return;
748         }
749 
750         // Module Management
751         if ("--list-modules".equals(arg))
752         {
753             listModules = true;
754             run = false;
755             return;
756         }
757 
758         // jetty.base build-out : add to ${jetty.base}/start.d/
759         if (arg.startsWith("--add-to-startd="))
760         {
761             addToStartdIni.addAll(Props.getValues(arg));
762             run = false;
763             download = true;
764             return;
765         }
766 
767         // jetty.base build-out : add to ${jetty.base}/start.ini
768         if (arg.startsWith("--add-to-start="))
769         {
770             addToStartIni.addAll(Props.getValues(arg));
771             run = false;
772             download = true;
773             return;
774         }
775 
776         // Enable a module
777         if (arg.startsWith("--module="))
778         {
779             for (String moduleName : Props.getValues(arg))
780             {
781                 modules.add(moduleName);
782                 List<String> list = sources.get(moduleName);
783                 if (list == null)
784                 {
785                     list = new ArrayList<String>();
786                     sources.put(moduleName,list);
787                 }
788                 list.add(source);
789             }
790             return;
791         }
792 
793         // Create graphviz output of module graph
794         if (arg.startsWith("--write-module-graph="))
795         {
796             this.moduleGraphFilename = Props.getValue(arg);
797             run = false;
798             return;
799         }
800 
801         // Start property (syntax similar to System property)
802         if (arg.startsWith("-D"))
803         {
804             String[] assign = arg.substring(2).split("=",2);
805             systemPropertyKeys.add(assign[0]);
806             switch (assign.length)
807             {
808                 case 2:
809                     System.setProperty(assign[0],assign[1]);
810                     setProperty(assign[0],assign[1],source);
811                     break;
812                 case 1:
813                     System.setProperty(assign[0],"");
814                     setProperty(assign[0],"",source);
815                     break;
816                 default:
817                     break;
818             }
819             return;
820         }
821 
822         // Anything else with a "-" is considered a JVM argument
823         if (arg.startsWith("-"))
824         {
825             // Only add non-duplicates
826             if (!jvmArgs.contains(arg))
827             {
828                 jvmArgs.add(arg);
829             }
830             return;
831         }
832 
833         // Is this a raw property declaration?
834         int idx = arg.indexOf('=');
835         if (idx >= 0)
836         {
837             String key = arg.substring(0,idx);
838             String value = arg.substring(idx + 1);
839 
840             if (propertySource.containsKey(key))
841             {
842                 StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key));
843             }
844             propertySource.put(key,source);
845 
846             if ("OPTION".equals(key) || "OPTIONS".equals(key))
847             {
848                 StringBuilder warn = new StringBuilder();
849                 warn.append("The behavior of the argument ");
850                 warn.append(arg).append(" (seen in ").append(source);
851                 warn.append(") has changed, and is now considered a normal property.  ");
852                 warn.append(key).append(" no longer controls what libraries are on your classpath,");
853                 warn.append(" use --module instead. See --help for details.");
854                 StartLog.warn(warn.toString());
855             }
856 
857             setProperty(key,value,source);
858             return;
859         }
860 
861         // Is this an xml file?
862         if (FS.isXml(arg))
863         {
864             // only add non-duplicates
865             if (!xmlRefs.contains(arg))
866             {
867                 xmlRefs.add(arg);
868             }
869             return;
870         }
871         
872         if (FS.isPropertyFile(arg))
873         {
874             // only add non-duplicates
875             if (!propertyFileRefs.contains(arg))
876             {
877             	propertyFileRefs.add(arg);
878             }
879         	return;
880         }
881 
882         // Anything else is unrecognized
883         throw new UsageException(ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source);
884     }
885 
886     public void resolveExtraXmls(BaseHome baseHome) throws IOException
887     {
888         // Find and Expand XML files
889         for (String xmlRef : xmlRefs)
890         {
891             // Straight Reference
892             Path xmlfile = baseHome.getPath(xmlRef);
893             if (!FS.exists(xmlfile))
894             {
895                 xmlfile = baseHome.getPath("etc/" + xmlRef);
896             }
897             addUniqueXmlFile(xmlRef,xmlfile);
898         }
899     }
900     
901     public void resolvePropertyFiles(BaseHome baseHome) throws IOException
902     {
903         // Find and Expand property files
904         for (String propertyFileRef : propertyFileRefs)
905         {
906             // Straight Reference
907             Path propertyFile = baseHome.getPath(propertyFileRef);
908             if (!FS.exists(propertyFile))
909             {
910             	propertyFile = baseHome.getPath("etc/" + propertyFileRef);
911             }
912             addUniquePropertyFile(propertyFileRef,propertyFile);
913         }
914     }
915 
916     public void setAllModules(Modules allModules)
917     {
918         this.allModules = allModules;
919     }
920 
921     private void setProperty(String key, String value, String source)
922     {
923         // Special / Prevent override from start.ini's
924         if (key.equals("jetty.home"))
925         {
926             properties.setProperty("jetty.home",System.getProperty("jetty.home"),source);
927             return;
928         }
929 
930         // Special / Prevent override from start.ini's
931         if (key.equals("jetty.base"))
932         {
933             properties.setProperty("jetty.base",System.getProperty("jetty.base"),source);
934             return;
935         }
936 
937         // Normal
938         properties.setProperty(key,value,source);
939     }
940 
941     public void setRun(boolean run)
942     {
943         this.run = run;
944     }
945 
946     @Override
947     public String toString()
948     {
949         StringBuilder builder = new StringBuilder();
950         builder.append("StartArgs [enabledModules=");
951         builder.append(modules);
952         builder.append(", xmlRefs=");
953         builder.append(xmlRefs);
954         builder.append(", properties=");
955         builder.append(properties);
956         builder.append(", jvmArgs=");
957         builder.append(jvmArgs);
958         builder.append("]");
959         return builder.toString();
960     }
961 }