1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.gridsystems.config.modules.tomcat;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.text.MessageFormat;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Properties;
28 import java.util.ResourceBundle;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 import com.gridsystems.config.ConfiguratorModel;
34 import com.gridsystems.config.modules.jvm.JVMConfigurator;
35 import com.gridsystems.config.tools.IpVerifier;
36 import com.gridsystems.config.tools.Template;
37 import com.gridsystems.utils.NetUtils;
38
39
40
41
42
43
44
45
46 public class TomcatConfigModel implements ConfiguratorModel {
47
48
49
50
51 protected static final int ALLOWED_IP_TYPE = IpVerifier.IP_4_IP_6;
52
53
54
55
56 public static final String HOST_IP = "host.ip";
57
58
59
60
61 public static final int DEFAULT_SHUTDOWN_PORT = 9114;
62
63
64
65
66 public static final int DEFAULT_HTTP_PORT = 9112;
67
68
69
70
71 public static final int DEFAULT_HTTPS_PORT = 9116;
72
73
74
75
76 public static final int DEFAULT_RESTART_CODE = 0;
77
78
79
80
81 public static final int DEFAULT_SHUTDOWN_CODE = 1;
82
83
84
85
86 public static final boolean DEFAULT_RESTART_ENABLED = false;
87
88
89
90
91 public static final boolean DEFAULT_HTTPS_ENABLED = false;
92
93
94
95
96 public static final String DEFAULT_KEYSTORE_DIR = "../conf/security";
97
98
99
100
101 public static final String DEFAULT_KEYSTORE_PASS = "changeit2";
102
103
104
105
106 private static Log log = LogFactory.getLog("TomcatConfigModel");
107
108
109 private static ResourceBundle customizerBundle
110 = ResourceBundle.getBundle("ServerConfiguratorCustomizer");
111
112
113
114
115
116 public static String getProductName() {
117 return getCustomizerString("Configurator.ProductName");
118 }
119
120
121
122
123
124
125 public static String getCustomizerString(String key) {
126 return customizerBundle.getString(key);
127 }
128
129
130
131
132 private String ip = null;
133
134
135
136
137 private int fShutdownPort = DEFAULT_SHUTDOWN_PORT;
138
139
140
141
142 private boolean fRestartEnabled = DEFAULT_RESTART_ENABLED;
143
144
145
146
147 private int fRestartExitCode = DEFAULT_RESTART_CODE;
148
149
150
151
152 private int fShutdownExitCode = DEFAULT_SHUTDOWN_CODE;
153
154
155
156
157 private File fKeystoreDir;
158
159
160
161
162 private String fKeystorePass;
163
164
165
166
167 private String fOldPassword;
168
169
170
171
172 private String fTruststorePass;
173
174
175
176
177 private List<Connector> connectors = new ArrayList<Connector>();
178
179
180
181
182 public TomcatConfigModel() { }
183
184
185
186
187
188
189
190 public TomcatConfigModel(TomcatConfigModel m) {
191 if (m != null) {
192 this.connectors = m.connectors;
193 this.fKeystoreDir = m.fKeystoreDir;
194 this.fKeystorePass = m.fKeystorePass;
195 this.fOldPassword = m.fOldPassword;
196 this.fRestartEnabled = m.fRestartEnabled;
197 this.fRestartExitCode = m.fRestartExitCode;
198 this.fShutdownExitCode = m.fShutdownExitCode;
199 this.fShutdownPort = m.fShutdownPort;
200 this.fTruststorePass = m.fTruststorePass;
201 this.ip = m.ip;
202 }
203 }
204
205
206
207
208
209
210 protected String getKeystorePath() {
211 try {
212 return fKeystoreDir.getCanonicalPath().replace('\\', '/');
213 } catch (IOException e) {
214 return fKeystoreDir.getAbsolutePath().replace('\\', '/');
215 }
216 }
217
218
219
220
221 public void load() {
222 JVMConfigurator jvmc = JVMConfigurator.getInstance();
223
224 if (this.ip == null || this.ip.length() == 0) {
225 this.ip = jvmc.getProperty(HOST_IP, null);
226 if (this.ip == null || this.ip.length() == 0) {
227 this.ip = NetUtils.getMachineIP();
228 }
229 }
230
231 fShutdownPort = jvmc.getIntProperty("tomcat.shutdown.port", DEFAULT_SHUTDOWN_PORT);
232 fRestartEnabled = jvmc.getBoolProperty("restart.enabled", DEFAULT_RESTART_ENABLED);
233 fRestartExitCode = jvmc.getIntProperty("exitcode.restart", DEFAULT_RESTART_CODE);
234 fShutdownExitCode = jvmc.getIntProperty("exitcode.shutdown", DEFAULT_SHUTDOWN_CODE);
235
236 String path = jvmc.getProperty("keystore.dir", DEFAULT_KEYSTORE_DIR);
237 fKeystoreDir = new File(path);
238
239 fKeystorePass = jvmc.getProperty("keystore.password", null);
240 if (fKeystorePass == null) {
241 fKeystorePass = DEFAULT_KEYSTORE_PASS;
242 fOldPassword = "changeit";
243 } else {
244 fOldPassword = fKeystorePass;
245 }
246
247 fTruststorePass = jvmc.getProperty("truststore.password", null);
248 if (fTruststorePass == null) {
249 fTruststorePass = fKeystorePass;
250 }
251
252 File f = new File("../conf/connectors.conf");
253 if (f.isFile()) {
254 try {
255 connectors = Connector.loadFromFile(f);
256 } catch (Exception e) {
257 log.error("Error parsing the connector list", e);
258 }
259 }
260 fixConnectors();
261 }
262
263
264
265
266 public void store() throws IOException {
267 File f = new File("../conf/connectors.conf");
268 Connector.saveToFile(f, connectors);
269 }
270
271
272
273
274 public void apply() throws IOException {
275
276 if (this.connectors.size() == 0) {
277 ResourceBundle bundle;
278 bundle = ResourceBundle.getBundle(TomcatConfigurator.BUNDLE);
279 throw new IOException(bundle.getString("errors.general"));
280 }
281 Properties props = new Properties();
282 props.setProperty(HOST_IP, this.ip);
283 props.setProperty("http.port", Integer.toString(getHttpPort()));
284 props.setProperty("shutdown.port", Integer.toString(fShutdownPort));
285 props.setProperty("restart.enabled", fRestartEnabled ? "true" : "false");
286 props.setProperty("restart.exitcode", Integer.toString(fRestartExitCode));
287 props.setProperty("shutdown.exitcode", Integer.toString(fShutdownExitCode));
288
289
290 String keystore = getKeystorePath() + "/keystore";
291 String password = fKeystorePass;
292 String truststore = getKeystorePath() + "/cacerts";
293 String trustpass = fTruststorePass;
294
295
296 File f = new File(truststore);
297 if (!f.exists()) {
298 truststore = null;
299 trustpass = null;
300 }
301 String xml = Connector.toXML(connectors, keystore, password, truststore, trustpass);
302
303 props.setProperty("connectors", xml);
304
305
306 applyTemplate(props, "../conf/template_server.xml", "template_server.xml",
307 "../conf/server.xml");
308
309
310 String ext = (File.separatorChar == '\\') ? ".bat" : ".sh";
311 String src = "template_kernel" + (fRestartEnabled ? "HA" : "") + ext;
312 String dst = "kernel" + ext;
313
314 applyTemplate(props, src, src, dst);
315
316
317 Connector maidenPort = getMaidenPort();
318 Properties serverHaProperties = new Properties();
319 serverHaProperties.put(
320 "server.maiden.port.number", Integer.toString(maidenPort.getPort()));
321 serverHaProperties.put(
322 "server.maiden.port.protocol", maidenPort.getProtocol());
323 applyTemplate(serverHaProperties, "template_ServerHA.cfg",
324 "template_ServerHA.cfg", "ServerHA.cfg");
325
326
327 if (isHttpsEnabled()) {
328 Properties p = new Properties();
329 p.setProperty("keystore.pass", fKeystorePass);
330 p.setProperty("keystore.oldPass", fOldPassword);
331 KeystoreUtils.createKeystores(fKeystoreDir, p);
332 }
333
334 applyJVMConfiguration(maidenPort);
335
336
337 fOldPassword = fKeystorePass;
338 }
339
340
341
342
343
344 private void applyJVMConfiguration(Connector maidenPort) {
345
346
347 JVMConfigurator jvmc = JVMConfigurator.getInstance();
348 jvmc.setProperty(
349 "server.maiden.port.number", Integer.toString(maidenPort.getPort()));
350 jvmc.setProperty(
351 "server.maiden.port.protocol", maidenPort.getProtocol());
352 jvmc.setProperty("tomcat.shutdown.port", Integer.toString(fShutdownPort));
353 jvmc.setProperty("restart.enabled", fRestartEnabled ? "true" : "false");
354 jvmc.setProperty("restart.exitcode", Integer.toString(fRestartExitCode));
355 jvmc.setProperty("shutdown.exitcode", Integer.toString(fShutdownExitCode));
356
357 jvmc.setProperty("keystore.dir", getKeystorePath());
358 jvmc.setProperty("keystore.password", fKeystorePass);
359 jvmc.setProperty("truststore.password", fTruststorePass);
360 jvmc.setProperty(HOST_IP, this.ip);
361
362
363
364
365 jvmc.setProperty("java.awt.headless", "true");
366
367
368
369
370
371 }
372
373
374
375
376
377
378
379
380
381
382
383 private void applyTemplate(Properties props, String src, String res, String dest) {
384 try {
385 Template t;
386 t = new Template(new File(src), this.getClass().getResource(res));
387 t.writeTo(props, new File(dest));
388 } catch (Exception e) {
389 e.printStackTrace();
390 }
391 }
392
393
394
395
396
397
398 public String getIp() {
399 return this.ip;
400 }
401
402
403
404
405
406
407 public void setIp(String ip) {
408 this.ip = ip;
409 }
410
411
412
413
414
415
416 public int getHttpPort() {
417 for (Iterator it = connectors.iterator(); it.hasNext();) {
418 Connector c = (Connector) it.next();
419 if ("Default HTTP".equals(c.getName())) {
420 return c.getPort();
421 }
422 }
423
424
425 return ((Connector)connectors.get(0)).getPort();
426 }
427
428
429
430
431
432
433 public int getShutdownPort() {
434 return fShutdownPort;
435 }
436
437
438
439
440
441
442 public int getHttpsPort() {
443 for (Iterator it = connectors.iterator(); it.hasNext();) {
444 Connector c = (Connector) it.next();
445 if ("Default HTTPS".equals(c.getName())) {
446 return c.getPort();
447 }
448 }
449 return 0;
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 public Connector getMaidenPort() {
466 Connector returnValue = null;
467
468 int level = Integer.MAX_VALUE;
469 for (Iterator it = connectors.iterator(); it.hasNext();) {
470 Connector c = (Connector) it.next();
471 if ("DefaultHTTP".equals(c.getName())) {
472
473 return c;
474 }
475 if ("DefaultHTTPS".equals(c.getName())) {
476 returnValue = c;
477 level = 0;
478 } else {
479 if (c.getProtocol().equalsIgnoreCase(Connector.HTTPS)) {
480
481 if (level > 2) {
482 returnValue = c;
483 level = 2;
484 }
485 } else {
486
487 if (level > 1) {
488 returnValue = c;
489 level = 1;
490 }
491 }
492 }
493 }
494 return returnValue;
495 }
496
497
498
499
500
501 public boolean isHttpsEnabled() {
502 for (Iterator it = connectors.iterator(); it.hasNext();) {
503 Connector c = (Connector) it.next();
504 if (c.getProtocol().equalsIgnoreCase(Connector.HTTPS)) {
505 return true;
506 }
507 }
508 return false;
509 }
510
511
512
513
514
515
516 public boolean isRestartEnabled() {
517 return fRestartEnabled;
518 }
519
520
521
522
523
524
525 public int getRestartExitCode() {
526 return fRestartExitCode;
527 }
528
529
530
531
532
533
534 public int getShutdownExitCode() {
535 return fShutdownExitCode;
536 }
537
538
539
540
541
542
543 public void setShutdownPort(int port) {
544 this.fShutdownPort = port;
545 }
546
547
548
549
550
551
552
553 public void setShutdownPort(String s) {
554 try {
555 fShutdownPort = Integer.parseInt(s);
556 } catch (Exception e) {
557 fShutdownPort = DEFAULT_SHUTDOWN_PORT;
558 }
559 }
560
561
562
563
564
565
566 public void setRestartEnabled(boolean enabled) {
567 fRestartEnabled = enabled;
568 }
569
570
571
572
573
574
575 public void setRestartExitCode(int exitCode) {
576 fRestartExitCode = exitCode;
577 }
578
579
580
581
582
583
584 public void setShutdownExitCode(int exitCode) {
585 fShutdownExitCode = exitCode;
586 }
587
588
589
590
591
592
593 public File getKeystoreDir() {
594 return this.fKeystoreDir;
595 }
596
597
598
599
600
601
602 public void setKeystoreDir(File dir) {
603 this.fKeystoreDir = dir;
604 }
605
606
607
608
609
610
611 public String getKeystorePassword() {
612 return this.fKeystorePass;
613 }
614
615
616
617
618
619
620 public void setKeystorePassword(String pass) {
621 this.fKeystorePass = pass;
622 }
623
624
625
626
627
628
629 public Connector[] getConnectors() {
630 Connector[] list = new Connector[connectors.size()];
631 for (int i = 0; i < list.length; i++) {
632 list[i] = ((Connector) connectors.get(i)).copy();
633 }
634 return list;
635 }
636
637
638
639
640
641
642
643 public void setConnectors(Connector[] cc) throws Exception {
644 validate(cc);
645 connectors = Arrays.asList(cc);
646
647 }
648
649
650
651
652
653
654 public void addConnector(Connector c) {
655 connectors.add(0, c);
656 }
657
658
659
660
661
662
663
664 public void validate(List conns) throws Exception {
665 HashMap<String, Connector> map = new HashMap<String, Connector>();
666 for (Iterator it = conns.iterator(); it.hasNext();) {
667 Connector c = (Connector) it.next();
668 check(map, c);
669 }
670 }
671
672
673
674
675
676
677
678 public void validate(Connector[] conns) throws Exception {
679 HashMap<String, Connector> map = new HashMap<String, Connector>();
680 for (int i = 0; i < conns.length; i++) {
681 check(map, conns[i]);
682 }
683 }
684
685
686
687
688
689
690 public void validate() throws Exception {
691 if ((this.ip == null) || (this.ip.length() == 0)) {
692 log.error("IP is empty! Maybe a configuration error has happened");
693 ResourceBundle bundle = TomcatConfigurator.getInstance().getBundle();
694 throw new IOException(bundle.getString("errors.empty.ip"));
695 }
696 if (IpVerifier.isLoopbackAddress(this.ip, ALLOWED_IP_TYPE)) {
697 log.error("The IP is a loopback address! Maybe a configuration error has happened");
698 ResourceBundle bundle = TomcatConfigurator.getInstance().getBundle();
699 throw new IOException(bundle.getString("errors.loopback.ip"));
700 }
701 validate(connectors);
702 }
703
704
705
706
707
708
709
710
711
712 private void check(HashMap<String, Connector> map, Connector c) throws Exception {
713 if (c.getPort() == fShutdownPort) {
714 throw new IncompatiblePortException(c);
715 }
716
717 String bindAddress = c.getAddress();
718 String name;
719 if (bindAddress == null || bindAddress.length() == 0) {
720
721 for (Iterator it = map.values().iterator(); it.hasNext();) {
722 Connector cc = (Connector) it.next();
723 if (cc.getName().equals(c.getName())) {
724 ResourceBundle bundle = TomcatConfigurator.getInstance().getBundle();
725 String pattern = bundle.getString("errors.duplicatedPorts");
726 Object[] params = new Object[] {c.getName()};
727 throw new Exception(MessageFormat.format(pattern, params));
728 }
729 if (cc.getPort() == c.getPort()
730 && !cc.getProtocol().equalsIgnoreCase(c.getProtocol())) {
731 throw new IncompatiblePortException(cc);
732 }
733 }
734
735 name = "0.0.0.0:" + c.getPort();
736 } else {
737 name = bindAddress + ":" + c.getPort();
738
739
740 Connector cc = (Connector) map.get("0.0.0.0:" + c.getPort());
741 if (cc != null) {
742 cc = (Connector) map.get(name);
743 }
744 if (cc != null && !cc.getProtocol().equalsIgnoreCase(c.getProtocol())) {
745 throw new IncompatiblePortException(c);
746 }
747 }
748
749 log.info("Checking port " + c.getPort());
750 if (!NetUtils.checkPort(c.getPort())) {
751 throw new PortInUseException(c);
752 }
753
754
755 map.put(name, c);
756 }
757
758
759
760
761
762 private void fixConnectors() {
763 boolean hasDefault;
764
765 if (connectors == null) {
766 connectors = new ArrayList<Connector>();
767 hasDefault = false;
768 } else {
769 if (connectors.size() == 0) {
770 hasDefault = false;
771 } else {
772 hasDefault = false;
773 int i = 0;
774 while (!hasDefault && (i < connectors.size())) {
775 Connector c = (Connector) connectors.get(i);
776 if (("Default HTTP".equals(c.getName())
777 && !c.getProtocol().equals(Connector.HTTPS))
778 || ("Default HTTPS".equals(c.getName())
779 && c.getProtocol().equals(Connector.HTTPS))) {
780 hasDefault = true;
781 }
782 i++;
783 }
784 }
785 }
786
787 if (!hasDefault) {
788 Connector def = new Connector("Default HTTP", DEFAULT_HTTP_PORT, Connector.HTTP);
789 def.setUserCreated(false);
790 connectors.add(0, def);
791
792 Connector sdef;
793 sdef = new Connector("Default HTTPS", DEFAULT_HTTPS_PORT, Connector.HTTPS);
794 sdef.setUserCreated(false);
795 connectors.add(1, sdef);
796 }
797 }
798
799
800
801 }