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 }