1 package emissary.config;
2
3 import jakarta.annotation.Nullable;
4 import org.apache.commons.lang3.ArrayUtils;
5 import org.apache.commons.lang3.StringUtils;
6 import org.apache.commons.lang3.Validate;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9
10 import java.io.BufferedReader;
11 import java.io.File;
12 import java.io.FileWriter;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.InputStreamReader;
16 import java.io.Reader;
17 import java.io.Serializable;
18 import java.io.StreamTokenizer;
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.nio.file.Paths;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.LinkedHashMap;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.Properties;
35 import java.util.Set;
36
37
38
39
40
41 public class ServiceConfigGuide implements Configurator, Serializable {
42
43 static final long serialVersionUID = 3906838615422657150L;
44 public static final char SLASH = '/';
45 public static final char COLON = ':';
46 public static final String DOUBLESLASH = "//";
47
48 protected static final Logger logger = LoggerFactory.getLogger(ServiceConfigGuide.class);
49
50 protected static final String DEFAULT_FILE_NAME = "default.cfg";
51 protected static final String POST_FILE_NAME = "post.cfg";
52
53
54
55 protected static final String NULL_VALUE = "<null>";
56
57
58 protected List<ConfigEntry> serviceParameters = new ArrayList<>();
59
60
61 protected List<ConfigEntry> removeParameters = new ArrayList<>();
62
63 protected String operator;
64
65
66 protected static final String VSTART = "@{";
67 protected static final String VEND = "}";
68
69
70
71
72
73
74 protected static final String ENVSTART = "@ENV{'";
75 protected static final String ENVSTOP = "'}";
76
77
78 protected Map<String, String> values = new HashMap<>();
79
80
81 private static final String hostname;
82
83
84 static {
85 String tmpHostname;
86 try {
87 tmpHostname = InetAddress.getLocalHost().getCanonicalHostName();
88 } catch (UnknownHostException e) {
89 logger.error("Error getting host name", e);
90 tmpHostname = "localhost";
91 }
92 hostname = tmpHostname;
93 }
94
95
96
97
98 public ServiceConfigGuide() {
99 initializeValues();
100 }
101
102
103
104
105
106
107
108 public ServiceConfigGuide(final String path, final String file) throws IOException {
109 this(path + File.separator + file);
110 }
111
112
113
114
115
116
117 public ServiceConfigGuide(final String filename) throws IOException {
118 this();
119 try {
120 readConfigData(filename);
121 } catch (ConfigSyntaxException ex) {
122 throw new IOException("Cannot parse configuration file " + ex.getMessage(), ex);
123 }
124 }
125
126
127
128
129
130
131 public ServiceConfigGuide(final InputStream is) throws IOException {
132 this();
133 try {
134 readConfigData(is);
135 } catch (ConfigSyntaxException ex) {
136 throw new IOException("Cannot parse configuration file " + ex.getMessage(), ex);
137 }
138 }
139
140
141
142
143
144
145
146 public ServiceConfigGuide(final InputStream is, final String name) throws IOException {
147 this();
148 try {
149 readConfigData(is, name);
150 } catch (ConfigSyntaxException ex) {
151 logger.error("Caught ConfigSytaxException {}", ex.getMessage());
152 throw new IOException("Cannot parse configuration file " + ex.getMessage(), ex);
153 }
154 }
155
156
157
158
159 protected void initializeValues() {
160 this.values.clear();
161
162
163
164
165
166 this.values.putAll(System.getenv());
167
168
169 final Properties props = System.getProperties();
170 for (Enumeration<?> e = props.propertyNames(); e.hasMoreElements();) {
171 final String key = (String) e.nextElement();
172 logger.trace("Adding {} to replaceable properties", key);
173 this.values.put(key, props.getProperty(key));
174 }
175
176
177 this.values.put("CONFIG_DIR", StringUtils.join(ConfigUtil.getConfigDirs(), ","));
178 this.values.put("PRJ_BASE", ConfigUtil.getProjectBase());
179 this.values.put("PROJECT_BASE", ConfigUtil.getProjectBase());
180 this.values.put("OUTPUT_ROOT", ConfigUtil.getOutputRoot());
181 this.values.put("BIN_DIR", ConfigUtil.getBinDir());
182 this.values.put("HOST", hostname);
183 this.values.put("/", File.separator);
184 this.values.put("TMPDIR", System.getProperty("java.io.tmpdir"));
185 this.values.put("NULL", null);
186 this.values.put("OS.NAME", System.getProperty("os.name").replace(' ', '_'));
187 this.values.put("OS.VER", System.getProperty("os.version").replace(' ', '_'));
188 this.values.put("OS.ARCH", System.getProperty("os.arch").replace(' ', '_'));
189 }
190
191
192
193
194 protected void readConfigData(final String filename) throws IOException, ConfigSyntaxException {
195 readSingleConfigFile(filename);
196 }
197
198 public void readConfigData(final InputStream is) throws IOException, ConfigSyntaxException {
199 readConfigData(is, "UNKNOWN");
200 }
201
202
203 protected void readConfigData(final InputStream is, final String filename) throws IOException, ConfigSyntaxException {
204 final Reader r = new BufferedReader(new InputStreamReader(is));
205 final StreamTokenizer in = new StreamTokenizer(r);
206 int nextToken = StreamTokenizer.TT_WORD;
207 String parmName;
208 String sval;
209
210 in.commentChar('#');
211 in.wordChars(33, 33);
212 in.wordChars(36, 47);
213 in.wordChars(58, 64);
214 in.wordChars(91, 96);
215 in.wordChars(123, 65536);
216
217 while (nextToken != StreamTokenizer.TT_EOF) {
218
219 nextToken = in.nextToken();
220
221
222 if (nextToken == StreamTokenizer.TT_EOF) {
223 break;
224 }
225 if (nextToken == StreamTokenizer.TT_NUMBER) {
226 throw new ConfigSyntaxException("Illegal token " + in.sval + ", missing quote on line " + in.lineno() + "?");
227 }
228
229 parmName = in.sval;
230
231 nextToken = in.nextToken();
232 this.operator = in.sval;
233
234 nextToken = in.nextToken();
235 if (nextToken == StreamTokenizer.TT_NUMBER) {
236 sval = Long.toString((long) in.nval);
237 } else {
238 sval = in.sval;
239 }
240
241 if (sval == null) {
242
243 throw new ConfigSyntaxException("Illegal token " + parmName + ", missing space or value on line " + (in.lineno() - 1) + "?");
244 }
245
246 handleNewEntry(parmName, sval, this.operator, filename, in.lineno() - 1, false);
247 }
248 r.close();
249 is.close();
250 }
251
252 protected void readSingleConfigFile(final String filename) throws IOException, ConfigSyntaxException {
253 logger.debug("Reading config file {}", filename);
254 final InputStream is = ConfigUtil.getConfigData(filename);
255 readConfigData(is, filename);
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 protected ConfigEntry handleNewEntry(final String parmNameArg, final String svalArg, final String operatorArg, final String filename,
273 final int lineno, final boolean merge) throws IOException {
274 final String parmName = handleReplacements(parmNameArg, filename, lineno);
275 final String sval = handleReplacements(svalArg, filename, lineno);
276
277
278 final ConfigEntry anEntry = new ConfigEntry(parmName, sval);
279
280 if ("!=".equals(operatorArg)) {
281 if ("*".equals(sval)) {
282 removeAllEntries(parmName);
283 this.values.remove(parmName);
284 } else {
285 removeEntry(anEntry);
286 if (sval.equals(this.values.get(parmName))) {
287 this.values.remove(parmName);
288 }
289 }
290 this.removeParameters.add(anEntry);
291 } else {
292
293 if (merge) {
294 this.serviceParameters.add(0, anEntry);
295 } else {
296 this.serviceParameters.add(anEntry);
297 }
298
299
300 this.values.put(parmName, sval);
301 }
302
303 if ("IMPORT_FILE".equals(parmName) || "OPT_IMPORT_FILE".equals(parmName)) {
304 final List<String> fileFlavorList = new ArrayList<>();
305
306 fileFlavorList.add(sval);
307 final String[] fileFlavors = ConfigUtil.addFlavors(sval);
308 if (ArrayUtils.isNotEmpty(fileFlavors)) {
309 fileFlavorList.addAll(Arrays.asList(fileFlavors));
310 }
311 logger.debug("ServiceConfigGuide::handleNewEntry -- FileFlavorList = {}", fileFlavorList);
312
313
314 for (int i = 0; i < fileFlavorList.size(); i++) {
315 final String fileFlavor = fileFlavorList.get(i);
316
317 try {
318 readConfigData(ConfigUtil.getConfigStream(fileFlavor), fileFlavor);
319 } catch (ConfigSyntaxException e) {
320
321 throw new IOException(parmName + " = " + sval + " from " + filename + " failed " + e.getMessage(), e);
322 } catch (IOException e) {
323
324 if ("IMPORT_FILE".equals(parmName) && i == 0) {
325 String importFileName = Paths.get(svalArg).getFileName().toString();
326 throw new IOException("In " + filename + ", cannot find IMPORT_FILE: " + sval
327 + " on the specified path. Make sure IMPORT_FILE (" + importFileName + ") exists, and the file path is correct.",
328 e);
329 }
330 }
331 }
332 return anEntry;
333 } else if ("CREATE_DIRECTORY".equals(parmName) && !createDirectory(sval)) {
334 logger.warn("{}: Cannot create directory {}", filename, sval);
335 } else if ("CREATE_FILE".equals(parmName) && !createFile(sval)) {
336 logger.warn("{}: Cannot create file {}", filename, sval);
337 }
338
339 return anEntry;
340 }
341
342
343
344
345
346
347
348
349
350
351 protected String handleReplacements(final String svalArg, final String filename, final int lineno) throws IOException {
352 String sval = svalArg;
353 int startpos = 0;
354 while (sval != null && sval.indexOf(VSTART, startpos) > -1) {
355 final int ndx = sval.indexOf(VSTART, startpos);
356 final int edx = sval.indexOf(VEND, ndx + VSTART.length());
357 if (ndx == -1 && ndx >= edx) {
358 throw new IOException("Problem parsing line " + lineno + " " + sval);
359 }
360 final String tok = sval.substring(ndx + VSTART.length(), edx);
361 logger.debug("Replacement token is {}", tok);
362 final String mapval = this.values.get(tok);
363 if (mapval != null) {
364 sval = sval.substring(0, ndx) + mapval + sval.substring(edx + VEND.length());
365 } else {
366 logger.warn("Did not find replacement for '{}' in file {} at line {}", tok, filename, lineno);
367 startpos = edx + VEND.length();
368 }
369 }
370
371
372 if (sval != null && sval.contains(ENVSTART)) {
373 sval = substituteEnvProps(sval, filename, lineno);
374 }
375
376
377 if (sval != null && (sval.contains("\\u") || sval.contains("\\U"))) {
378 sval = substituteUtfChars(sval, filename, lineno);
379 }
380
381
382 if (sval != null && sval.equals(NULL_VALUE)) {
383 sval = null;
384 logger.debug("Using {} is deprecated, please just use {}NULL{}", NULL_VALUE, VSTART, VEND);
385 }
386 return sval;
387 }
388
389
390
391
392
393
394
395
396
397 protected String substituteUtfChars(final String s, final String filename, final int lnum) throws IOException {
398 final int slen = s.length();
399 final StringBuilder sb = new StringBuilder(slen);
400 for (int i = 0; i < slen; i++) {
401 if (s.charAt(i) != '\\') {
402 sb.append(s.charAt(i));
403 } else if ((i + 4) < slen && (s.charAt(i + 1) == 'u' || s.charAt(i + 1) == 'U')) {
404 int epos = i + 2;
405 final int max = (s.charAt(epos) == '1' || s.charAt(epos) == '0') ? (i + 7) : (i + 6);
406 while (epos < slen
407 && epos < max
408 && ((s.charAt(epos) >= '0' && s.charAt(epos) <= '9') || (s.charAt(epos) >= 'A' && s.charAt(epos) <= 'F')
409 || (s.charAt(epos) >= 'a' && s
410 .charAt(epos) <= 'f'))) {
411 epos++;
412 }
413 if (epos <= slen) {
414 try {
415 final int digit = Integer.parseInt(s.substring(i + 2, epos), 16);
416 sb.appendCodePoint(digit);
417 i = epos - 1;
418 } catch (RuntimeException ex) {
419 throw new IOException("Unable to convert characters in " + s + ", from filename=" + filename + " line " + lnum, ex);
420 }
421 }
422 } else {
423 sb.append(s.charAt(i));
424 }
425 }
426
427 return sb.toString();
428 }
429
430
431
432
433
434
435
436
437
438
439 protected String substituteEnvProps(final String str, final String filename, final int lnum) throws IOException {
440 int lastPos = -1;
441 int thisPos = 0;
442 int count = 0;
443
444 logger.debug("{}{} style substitution is deprecated. Please just use {}yourvalue{}", ENVSTART, ENVSTOP, VSTART, VEND);
445
446 String currentStr = str;
447 while ((thisPos = currentStr.indexOf(ENVSTART, thisPos)) > lastPos) {
448 final int start = thisPos + ENVSTART.length();
449 final int stop = currentStr.indexOf(ENVSTOP, thisPos);
450 count++;
451
452 if (stop > start) {
453 final String envName = currentStr.substring(start, stop);
454 String envVal = System.getProperty(envName);
455 if (envVal == null) {
456 envVal = System.getenv(envName);
457 }
458
459 if (envVal != null) {
460 currentStr = currentStr.substring(0, thisPos) +
461 envVal +
462 currentStr.substring(stop + ENVSTOP.length());
463 logger.debug("Replaced {} with {} at {}: {}", envName, envVal, filename, lnum);
464 } else {
465 logger.debug("No env value for {} at {}: {}", envName, filename, lnum);
466 }
467 } else {
468 throw new IOException("Runaway string on line ->" + currentStr + "<- at " + filename + ": " + lnum);
469 }
470
471 lastPos = thisPos;
472 }
473 logger.debug("Found {} env vars to subst --> {}", count, currentStr);
474 return currentStr;
475 }
476
477
478
479
480 protected boolean createDirectory(final String sval) {
481 final String fixedSval = sval.replace('\\', '/');
482 logger.debug("Trying to create dir {}", fixedSval);
483 final File d = new File(fixedSval);
484 if (!d.exists() && !d.mkdirs()) {
485 logger.debug("Failed to create directory {}", fixedSval);
486 return false;
487 }
488 return true;
489 }
490
491
492
493
494 protected boolean createFile(final String sval) {
495
496 final String fixedSval = sval.replace('\\', '/');
497 logger.debug("Trying to create file {}", fixedSval);
498 final File d = new File(fixedSval);
499 FileWriter newFile = null;
500 if (!d.exists()) {
501 try {
502
503 final File parent = new File(new File(d.getCanonicalPath()).getParent());
504 if (!parent.exists() && !createDirectory(parent.toString())) {
505 logger.debug("Failed to create parent directory for {}", fixedSval);
506 return false;
507 }
508
509 newFile = new FileWriter(d);
510 } catch (IOException e) {
511 logger.debug("Failed to create file {}", fixedSval, e);
512 return false;
513 } finally {
514 if (newFile != null) {
515 try {
516 newFile.close();
517 } catch (IOException ioe) {
518 logger.debug("Error closing file", ioe);
519 }
520 }
521 }
522 }
523 return true;
524 }
525
526
527
528
529
530 @Override
531 public Set<String> entryKeys() {
532 final Set<String> set = new HashSet<>();
533 for (final ConfigEntry curEntry : this.serviceParameters) {
534 set.add(curEntry.getKey());
535 }
536 return set;
537 }
538
539
540
541
542 @Override
543 public List<ConfigEntry> getEntries() {
544 return new ArrayList<>(this.serviceParameters);
545 }
546
547
548
549
550
551 protected List<ConfigEntry> getRemoveEntries() {
552 return new ArrayList<>(this.removeParameters);
553 }
554
555
556
557
558
559
560
561
562 @Override
563 public ConfigEntry addEntry(final String key, final String value) {
564 ConfigEntry entry = null;
565 try {
566 entry = handleNewEntry(key, value, "=", "<user>", 1, false);
567 } catch (IOException ex) {
568 logger.error("Could not add entry for {}", key, ex);
569 }
570 return entry;
571 }
572
573
574
575
576
577
578
579
580 @Override
581 public List<ConfigEntry> addEntries(final String key, final List<String> values) {
582 final List<ConfigEntry> list = new ArrayList<>();
583 try {
584 int i = 1;
585 for (final String value : values) {
586 final ConfigEntry entry = handleNewEntry(key, value, "=", "<user>", i++, false);
587 list.add(entry);
588 }
589 } catch (IOException ex) {
590 logger.error("Error adding entries for {}", key, ex);
591 }
592 return list;
593 }
594
595
596
597
598
599
600
601 @Override
602 public void removeEntry(final String key, final String value) {
603 try {
604 handleNewEntry(key, value, "!=", "<user>", 1, false);
605 } catch (IOException ex) {
606 logger.warn("Cannot remove entry", ex);
607 }
608 }
609
610
611
612
613
614
615 public void removeEntry(final ConfigEntry anEntry) {
616
617 for (final Iterator<ConfigEntry> i = this.serviceParameters.iterator(); i.hasNext();) {
618 final ConfigEntry curEntry = i.next();
619 if (anEntry.getKey().equals(curEntry.getKey())
620 && ((anEntry.getValue() == null && curEntry.getValue() == null) || (anEntry.getValue() != null && anEntry.getValue().equals(
621 curEntry.getValue())))) {
622 logger.debug("Removing {} = {}", curEntry.getKey(), curEntry.getValue());
623 i.remove();
624 }
625 }
626 }
627
628
629
630
631
632
633
634
635 @Override
636 public List<String> findEntries(final String theParameter, final String defaultString) {
637 final List<String> result = findEntries(theParameter);
638 if (result.isEmpty()) {
639 result.add(defaultString);
640 }
641 return result;
642 }
643
644
645
646
647
648
649
650 @Override
651 public List<String> findEntries(final String theParameter) {
652 final List<String> matchingEntries = new ArrayList<>();
653
654 for (final ConfigEntry curEntry : this.serviceParameters) {
655 if (theParameter.equals(curEntry.getKey())) {
656 matchingEntries.add(curEntry.getValue());
657 }
658 }
659 return matchingEntries;
660 }
661
662
663
664
665
666
667 public void removeAllEntries(final String theParameter) {
668
669 for (final Iterator<ConfigEntry> i = this.serviceParameters.iterator(); i.hasNext();) {
670 final ConfigEntry curEntry = i.next();
671 if (theParameter.equals(curEntry.getKey())) {
672 logger.debug("Removing {} = {}", curEntry.getKey(), curEntry.getValue());
673 i.remove();
674 }
675 }
676 }
677
678
679
680
681
682
683
684 @Override
685 public Set<String> findEntriesAsSet(final String theParameter) {
686
687 final Set<String> matchingEntries = new HashSet<>();
688
689 for (final ConfigEntry curEntry : this.serviceParameters) {
690 if (theParameter.equals(curEntry.getKey())) {
691 matchingEntries.add(curEntry.getValue());
692 }
693 }
694 return matchingEntries;
695 }
696
697
698
699
700
701
702
703 @Override
704 public List<ConfigEntry> findStringMatchEntries(final String theParameter) {
705
706 final List<ConfigEntry> matchingEntries = new ArrayList<>();
707
708 for (final ConfigEntry curEntry : this.serviceParameters) {
709 if (curEntry.getKey().startsWith(theParameter)) {
710 matchingEntries.add(curEntry);
711 }
712 }
713 return matchingEntries;
714 }
715
716
717
718
719
720
721
722
723 @Override
724 public List<ConfigEntry> findStringMatchList(final String theParameter) {
725 final List<ConfigEntry> list = findStringMatchEntries(theParameter);
726 for (final ConfigEntry entry : list) {
727 entry.setKey(entry.getKey().substring(theParameter.length()));
728 }
729 return list;
730 }
731
732
733
734
735
736
737
738 @Override
739 public Map<String, String> findStringMatchMap(final String theParameter) {
740 return findStringMatchMap(theParameter, false);
741 }
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763 @Override
764 public Map<String, String> findStringMatchMap(final String theParameter, final boolean preserveCase) {
765 return findStringMatchMap(theParameter, preserveCase, false);
766 }
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789 @Override
790 public Map<String, String> findStringMatchMap(@Nullable final String theParameter, final boolean preserveCase, final boolean preserveOrder) {
791 if (theParameter == null) {
792 return Collections.emptyMap();
793 }
794
795 final Map<String, String> theHash = preserveOrder ? new LinkedHashMap<>() : new HashMap<>();
796 final List<ConfigEntry> parameters = this.findStringMatchEntries(theParameter);
797
798 for (final ConfigEntry el : parameters) {
799 String key = el.getKey();
800 key = key.substring(theParameter.length());
801 if (!preserveCase) {
802 key = key.toUpperCase(Locale.getDefault());
803 }
804 theHash.put(key, el.getValue());
805 }
806 return theHash;
807 }
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831 @Override
832 public Map<String, Set<String>> findStringMatchMultiMap(@Nullable final String param) {
833 if (param == null) {
834 return Map.of();
835 }
836
837 return findStringMatchMultiMap(param, false);
838 }
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863 @Override
864 public Map<String, Set<String>> findStringMatchMultiMap(@Nullable final String param, final boolean preserveOrder) {
865
866 if (param == null) {
867 return Map.of();
868 }
869
870 final Map<String, Set<String>> theHash = preserveOrder ? new LinkedHashMap<>() : new HashMap<>();
871 final List<ConfigEntry> parameters = this.findStringMatchEntries(param);
872
873 for (final ConfigEntry el : parameters) {
874 final String key = el.getKey().substring(param.length()).toUpperCase(Locale.getDefault());
875
876 if (theHash.containsKey(key)) {
877 theHash.get(key).add(el.getValue());
878 } else {
879 final Set<String> values = preserveOrder ? new LinkedHashSet<>() : new HashSet<>();
880 values.add(el.getValue());
881 theHash.put(key, values);
882 }
883 }
884 return theHash;
885
886 }
887
888
889
890
891
892
893
894
895 @Override
896 public String findRequiredStringEntry(final String theParameter) {
897 String value = findStringEntry(theParameter, null);
898 Validate.notBlank(value, "Missing required parameter [%s]", theParameter);
899 return value;
900 }
901
902
903
904
905
906
907
908
909 @Override
910 public String findStringEntry(final String theParameter, @Nullable final String dflt) {
911 final List<String> matchingEntries = findEntries(theParameter);
912 for (final String entry : matchingEntries) {
913 if (entry != null) {
914 return entry;
915 }
916 }
917 return dflt;
918 }
919
920
921
922
923
924
925
926 @Override
927 public String findStringEntry(final String theParameter) {
928 return findStringEntry(theParameter, null);
929 }
930
931
932
933
934
935
936
937 @Override
938 public String findLastStringEntry(final String theParameter) {
939 String result = "";
940 for (final ConfigEntry curEntry : this.serviceParameters) {
941 if (theParameter.equals(curEntry.getKey())) {
942 result = curEntry.getValue();
943 }
944 }
945 return result;
946 }
947
948
949
950
951
952
953
954
955
956
957 @Override
958 public long findSizeEntry(final String theParameter, final long dflt) {
959 final List<String> matchingEntries = findEntries(theParameter);
960 if (!matchingEntries.isEmpty()) {
961 long val = dflt;
962 final String s = matchingEntries.get(0);
963 final char c = Character.toUpperCase(s.charAt(s.length() - 1));
964 final String ss = s.substring(0, s.length() - 1);
965 boolean broken = false;
966 switch (c) {
967 case 'T':
968 val = Long.parseLong(ss) * 1024 * 1024 * 1024 * 1024;
969 break;
970 case 'G':
971 val = Long.parseLong(ss) * 1024 * 1024 * 1024;
972 break;
973 case 'M':
974 val = Long.parseLong(ss) * 1024 * 1024;
975 break;
976 case 'K':
977 val = Long.parseLong(ss) * 1024;
978 break;
979 case 'B':
980 val = Long.parseLong(ss);
981 break;
982 case '0':
983 case '1':
984 case '2':
985 case '3':
986 case '4':
987 case '5':
988 case '6':
989 case '7':
990 case '8':
991 case '9':
992 val = Long.parseLong(s);
993 break;
994 default:
995 broken = true;
996 }
997
998 if (!broken) {
999 return val;
1000 }
1001 return dflt;
1002 }
1003 return dflt;
1004 }
1005
1006
1007
1008
1009
1010
1011
1012
1013 @Override
1014 public String findCanonicalFileNameEntry(final String theParameter, final String dflt) {
1015 final String fn = findStringEntry(theParameter, dflt);
1016 if (fn != null && fn.length() > 0) {
1017 try {
1018 return new File(fn).getCanonicalPath();
1019 } catch (IOException ex) {
1020 logger.error("Cannot compute canonical path on {}", fn, ex);
1021 }
1022 }
1023 return fn;
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033 @Override
1034 public int findIntEntry(final String theParameter, final int dflt) {
1035 final List<String> matchingEntries = findEntries(theParameter);
1036
1037 if (!matchingEntries.isEmpty()) {
1038 try {
1039 return Integer.parseInt(matchingEntries.get(0));
1040 } catch (NumberFormatException e) {
1041 logger.warn("{} is non-numeric returning default value: {}", theParameter, dflt);
1042 }
1043 }
1044 return dflt;
1045 }
1046
1047
1048
1049
1050
1051
1052
1053
1054 @Override
1055 public long findLongEntry(final String theParameter, final long dflt) {
1056 final List<String> matchingEntries = findEntries(theParameter);
1057
1058 if (!matchingEntries.isEmpty()) {
1059 try {
1060 return Long.parseLong(matchingEntries.get(0));
1061 } catch (NumberFormatException e) {
1062 logger.warn("{} is non-numeric returning default value: {}", theParameter, dflt);
1063 }
1064 }
1065 return dflt;
1066 }
1067
1068
1069
1070
1071
1072
1073
1074
1075 @Override
1076 public double findDoubleEntry(final String theParameter, final double dflt) {
1077 final List<String> matchingEntries = findEntries(theParameter);
1078
1079 if (!matchingEntries.isEmpty()) {
1080 try {
1081 return Double.parseDouble(matchingEntries.get(0));
1082 } catch (NumberFormatException e) {
1083 logger.warn("{} is non-numeric returning default value: {}", theParameter, dflt);
1084 }
1085 }
1086 return dflt;
1087 }
1088
1089
1090
1091
1092
1093
1094
1095
1096 @Override
1097 public boolean findBooleanEntry(final String theParameter, final boolean dflt) {
1098 final List<String> matchingEntries = findEntries(theParameter);
1099
1100 if (!matchingEntries.isEmpty()) {
1101 String el = matchingEntries.get(0);
1102 el = el.toUpperCase(Locale.getDefault());
1103 if (el.startsWith("F")) {
1104 return false;
1105 } else if (el.startsWith("T")) {
1106 return true;
1107 }
1108 }
1109 return dflt;
1110 }
1111
1112
1113
1114
1115
1116
1117
1118
1119 @Override
1120 public boolean findBooleanEntry(final String theParameter, final String dflt) {
1121 return findBooleanEntry(theParameter, Boolean.parseBoolean(dflt));
1122 }
1123
1124
1125
1126
1127
1128
1129 protected int getNumericParameter(final String name) {
1130 final String val = this.values.get(name);
1131 int i = -1;
1132 if (val != null) {
1133 try {
1134 i = Integer.parseInt(val);
1135 } catch (NumberFormatException ex) {
1136 logger.warn("{} is non-numeric: {}", name, val);
1137 }
1138 }
1139 return i;
1140 }
1141
1142 public boolean debug() {
1143 return "TRUE".equalsIgnoreCase(this.values.get("DEBUG"));
1144 }
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 @Override
1158 public void merge(final Configurator other) throws IOException {
1159 int i = 1;
1160
1161
1162 if (other instanceof ServiceConfigGuide) {
1163 for (final ConfigEntry entry : ((ServiceConfigGuide) other).getRemoveEntries()) {
1164 handleNewEntry(entry.getKey(), entry.getValue(), "!=", "<merge>", i++, true);
1165 }
1166 }
1167
1168
1169 for (final ConfigEntry entry : other.getEntries()) {
1170 handleNewEntry(entry.getKey(), entry.getValue(), "=", "<merge>", i++, true);
1171 }
1172 }
1173
1174
1175
1176
1177 public static void main(final String[] args) {
1178 if (args.length < 1) {
1179 logger.error("usage: java ServiceConfigGuide configfile");
1180 return;
1181 }
1182
1183 for (String arg : args) {
1184 try {
1185 final ServiceConfigGuide sc = new ServiceConfigGuide(arg);
1186 logger.info("Config File:{} ", arg);
1187 for (int i = 0; i < sc.serviceParameters.size(); i++) {
1188 final ConfigEntry c = sc.serviceParameters.get(i);
1189 logger.info("{}: {}", c.getKey(), c.getValue());
1190 }
1191 logger.info("---");
1192 } catch (IOException e) {
1193 logger.info("Cannot process {}:{}", arg, e.getLocalizedMessage());
1194 }
1195 }
1196 }
1197 }