1 
17 package org.apache.catalina.core;
18 
19 import java.beans.PropertyChangeListener;
20 import java.beans.PropertyChangeSupport;
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.InetAddress;
25 import java.net.ServerSocket;
26 import java.net.Socket;
27 import java.net.SocketTimeoutException;
28 import java.net.URISyntaxException;
29 import java.net.URL;
30 import java.net.URLClassLoader;
31 import java.security.AccessControlException;
32 import java.util.Random;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.ScheduledExecutorService;
35 import java.util.concurrent.ScheduledFuture;
36 import java.util.concurrent.ScheduledThreadPoolExecutor;
37 import java.util.concurrent.TimeUnit;
38 
39 import javax.management.InstanceNotFoundException;
40 import javax.management.MBeanException;
41 import javax.management.MBeanServer;
42 import javax.management.ObjectName;
43 
44 import org.apache.catalina.Context;
45 import org.apache.catalina.Lifecycle;
46 import org.apache.catalina.LifecycleException;
47 import org.apache.catalina.LifecycleState;
48 import org.apache.catalina.Server;
49 import org.apache.catalina.Service;
50 import org.apache.catalina.deploy.NamingResourcesImpl;
51 import org.apache.catalina.mbeans.MBeanFactory;
52 import org.apache.catalina.startup.Catalina;
53 import org.apache.catalina.util.ExtensionValidator;
54 import org.apache.catalina.util.LifecycleMBeanBase;
55 import org.apache.catalina.util.ServerInfo;
56 import org.apache.juli.logging.Log;
57 import org.apache.juli.logging.LogFactory;
58 import org.apache.tomcat.util.ExceptionUtils;
59 import org.apache.tomcat.util.buf.StringCache;
60 import org.apache.tomcat.util.modeler.Registry;
61 import org.apache.tomcat.util.res.StringManager;
62 import org.apache.tomcat.util.threads.TaskThreadFactory;
63 
64 
65 
71 public final class StandardServer extends LifecycleMBeanBase implements Server {
72 
73     private static final Log log = LogFactory.getLog(StandardServer.class);
74 
75 
76     
77 
78 
79     
82     public StandardServer() {
83 
84         super();
85 
86         globalNamingResources = new NamingResourcesImpl();
87         globalNamingResources.setContainer(this);
88 
89         if (isUseNaming()) {
90             namingContextListener = new NamingContextListener();
91             addLifecycleListener(namingContextListener);
92         } else {
93             namingContextListener = null;
94         }
95 
96     }
97 
98 
99     
100 
101 
102     
105     private javax.naming.Context globalNamingContext = null;
106 
107 
108     
111     private NamingResourcesImpl globalNamingResources = null;
112 
113 
114     
117     private final NamingContextListener namingContextListener;
118 
119 
120     
123     private int port = 8005;
124 
125     private int portOffset = 0;
126 
127     
130     private String address = "localhost";
131 
132 
133     
137     private Random random = null;
138 
139 
140     
143     private Service services[] = new Service[0];
144     private final Object servicesLock = new Object();
145 
146 
147     
150     private String shutdown = "SHUTDOWN";
151 
152 
153     
156     private static final StringManager sm =
157         StringManager.getManager(Constants.Package);
158 
159 
160     
163     final PropertyChangeSupport support = new PropertyChangeSupport(this);
164 
165     private volatile boolean stopAwait = false;
166 
167     private Catalina catalina = null;
168 
169     private ClassLoader parentClassLoader = null;
170 
171     
174     private volatile Thread awaitThread = null;
175 
176     
179     private volatile ServerSocket awaitSocket = null;
180 
181     private File catalinaHome = null;
182 
183     private File catalinaBase = null;
184 
185     private final Object namingToken = new Object();
186 
187     
190     protected int utilityThreads = 2;
191 
192     
195     protected boolean utilityThreadsAsDaemon = false;
196 
197     
200     private ScheduledThreadPoolExecutor utilityExecutor = null;
201 
202     
205     private ScheduledExecutorService utilityExecutorWrapper = null;
206 
207 
208     
211     private ScheduledFuture<?> periodicLifecycleEventFuture = null;
212     private ScheduledFuture<?> monitorFuture;
213 
214 
215     
218     protected int periodicEventDelay = 10;
219 
220 
221     
222 
223     @Override
224     public Object getNamingToken() {
225         return namingToken;
226     }
227 
228 
229     
232     @Override
233     public javax.naming.Context getGlobalNamingContext() {
234         return this.globalNamingContext;
235     }
236 
237 
238     
243     public void setGlobalNamingContext(javax.naming.Context globalNamingContext) {
244         this.globalNamingContext = globalNamingContext;
245     }
246 
247 
248     
251     @Override
252     public NamingResourcesImpl getGlobalNamingResources() {
253         return this.globalNamingResources;
254     }
255 
256 
257     
262     @Override
263     public void setGlobalNamingResources
264         (NamingResourcesImpl globalNamingResources) {
265 
266         NamingResourcesImpl oldGlobalNamingResources =
267             this.globalNamingResources;
268         this.globalNamingResources = globalNamingResources;
269         this.globalNamingResources.setContainer(this);
270         support.firePropertyChange("globalNamingResources",
271                                    oldGlobalNamingResources,
272                                    this.globalNamingResources);
273 
274     }
275 
276 
277     
281     public String getServerInfo() {
282         return ServerInfo.getServerInfo();
283     }
284 
285 
286     
290     public String getServerBuilt() {
291         return ServerInfo.getServerBuilt();
292     }
293 
294 
295     
299     public String getServerNumber() {
300         return ServerInfo.getServerNumber();
301     }
302 
303 
304     
307     @Override
308     public int getPort() {
309         return this.port;
310     }
311 
312 
313     
318     @Override
319     public void setPort(int port) {
320         this.port = port;
321     }
322 
323 
324     @Override
325     public int getPortOffset() {
326         return portOffset;
327     }
328 
329 
330     @Override
331     public void setPortOffset(int portOffset) {
332         if (portOffset < 0) {
333             throw new IllegalArgumentException(
334                     sm.getString("standardServer.portOffset.invalid", Integer.valueOf(portOffset)));
335         }
336         this.portOffset = portOffset;
337     }
338 
339 
340     @Override
341     public int getPortWithOffset() {
342         
343         
344         int port = getPort();
345         if (port > 0) {
346             return port + getPortOffset();
347         } else {
348             return port;
349         }
350     }
351 
352 
353     
356     @Override
357     public String getAddress() {
358         return this.address;
359     }
360 
361 
362     
367     @Override
368     public void setAddress(String address) {
369         this.address = address;
370     }
371 
372     
375     @Override
376     public String getShutdown() {
377         return this.shutdown;
378     }
379 
380 
381     
386     @Override
387     public void setShutdown(String shutdown) {
388         this.shutdown = shutdown;
389     }
390 
391 
392     
395     @Override
396     public Catalina getCatalina() {
397         return catalina;
398     }
399 
400 
401     
404     @Override
405     public void setCatalina(Catalina catalina) {
406         this.catalina = catalina;
407     }
408 
409 
410     @Override
411     public int getUtilityThreads() {
412         return utilityThreads;
413     }
414 
415 
416     
419     private static int getUtilityThreadsInternal(int utilityThreads) {
420         int result = utilityThreads;
421         if (result <= 0) {
422             result = Runtime.getRuntime().availableProcessors() + result;
423             if (result < 2) {
424                 result = 2;
425             }
426         }
427         return result;
428     }
429 
430 
431     @Override
432     public void setUtilityThreads(int utilityThreads) {
433         
434         int oldUtilityThreads = this.utilityThreads;
435         if (getUtilityThreadsInternal(utilityThreads) < getUtilityThreadsInternal(oldUtilityThreads)) {
436             return;
437         }
438         this.utilityThreads = utilityThreads;
439         if (oldUtilityThreads != utilityThreads && utilityExecutor != null) {
440             reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads));
441         }
442     }
443 
444 
445     private synchronized void reconfigureUtilityExecutor(int threads) {
446         
447         if (utilityExecutor != null) {
448             utilityExecutor.setCorePoolSize(threads);
449         } else {
450             ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
451                     new ScheduledThreadPoolExecutor(threads,
452                             new TaskThreadFactory("Catalina-utility-", utilityThreadsAsDaemon, Thread.MIN_PRIORITY));
453             scheduledThreadPoolExecutor.setKeepAliveTime(10, TimeUnit.SECONDS);
454             scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
455             scheduledThreadPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
456             utilityExecutor = scheduledThreadPoolExecutor;
457             utilityExecutorWrapper = new org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor(utilityExecutor);
458         }
459     }
460 
461 
462     
466     public boolean getUtilityThreadsAsDaemon() {
467         return utilityThreadsAsDaemon;
468     }
469 
470 
471     
475     public void setUtilityThreadsAsDaemon(boolean utilityThreadsAsDaemon) {
476         this.utilityThreadsAsDaemon = utilityThreadsAsDaemon;
477     }
478 
479 
480     
483     public final int getPeriodicEventDelay() {
484         return periodicEventDelay;
485     }
486 
487 
488     
493     public final void setPeriodicEventDelay(int periodicEventDelay) {
494         this.periodicEventDelay = periodicEventDelay;
495     }
496 
497 
498     
499 
500 
501     
506     @Override
507     public void addService(Service service) {
508 
509         service.setServer(this);
510 
511         synchronized (servicesLock) {
512             Service results[] = new Service[services.length + 1];
513             System.arraycopy(services, 0, results, 0, services.length);
514             results[services.length] = service;
515             services = results;
516 
517             if (getState().isAvailable()) {
518                 try {
519                     service.start();
520                 } catch (LifecycleException e) {
521                     
522                 }
523             }
524 
525             
526             support.firePropertyChange("service", null, service);
527         }
528 
529     }
530 
531     public void stopAwait() {
532         stopAwait=true;
533         Thread t = awaitThread;
534         if (t != null) {
535             ServerSocket s = awaitSocket;
536             if (s != null) {
537                 awaitSocket = null;
538                 try {
539                     s.close();
540                 } catch (IOException e) {
541                     
542                 }
543             }
544             t.interrupt();
545             try {
546                 t.join(1000);
547             } catch (InterruptedException e) {
548                 
549             }
550         }
551     }
552 
553     
558     @Override
559     public void await() {
560         
561         if (getPortWithOffset() == -2) {
562             
563             return;
564         }
565         if (getPortWithOffset() == -1) {
566             try {
567                 awaitThread = Thread.currentThread();
568                 while(!stopAwait) {
569                     try {
570                         Thread.sleep( 10000 );
571                     } catch( InterruptedException ex ) {
572                         
573                     }
574                 }
575             } finally {
576                 awaitThread = null;
577             }
578             return;
579         }
580 
581         
582         try {
583             awaitSocket = new ServerSocket(getPortWithOffset(), 1,
584                     InetAddress.getByName(address));
585         } catch (IOException e) {
586             log.error(sm.getString("standardServer.awaitSocket.fail", address,
587                     String.valueOf(getPortWithOffset()), String.valueOf(getPort()),
588                     String.valueOf(getPortOffset())), e);
589             return;
590         }
591 
592         try {
593             awaitThread = Thread.currentThread();
594 
595             
596             while (!stopAwait) {
597                 ServerSocket serverSocket = awaitSocket;
598                 if (serverSocket == null) {
599                     break;
600                 }
601 
602                 
603                 Socket socket = null;
604                 StringBuilder command = new StringBuilder();
605                 try {
606                     InputStream stream;
607                     long acceptStartTime = System.currentTimeMillis();
608                     try {
609                         socket = serverSocket.accept();
610                         socket.setSoTimeout(10 * 1000);  
611                         stream = socket.getInputStream();
612                     } catch (SocketTimeoutException ste) {
613                         
614                         
615                         log.warn(sm.getString("standardServer.accept.timeout",
616                                 Long.valueOf(System.currentTimeMillis() - acceptStartTime)), ste);
617                         continue;
618                     } catch (AccessControlException ace) {
619                         log.warn(sm.getString("standardServer.accept.security"), ace);
620                         continue;
621                     } catch (IOException e) {
622                         if (stopAwait) {
623                             
624                             break;
625                         }
626                         log.error(sm.getString("standardServer.accept.error"), e);
627                         break;
628                     }
629 
630                     
631                     int expected = 1024; 
632                     while (expected < shutdown.length()) {
633                         if (random == null)
634                             random = new Random();
635                         expected += (random.nextInt() % 1024);
636                     }
637                     while (expected > 0) {
638                         int ch = -1;
639                         try {
640                             ch = stream.read();
641                         } catch (IOException e) {
642                             log.warn(sm.getString("standardServer.accept.readError"), e);
643                             ch = -1;
644                         }
645                         
646                         if (ch < 32 || ch == 127) {
647                             break;
648                         }
649                         command.append((char) ch);
650                         expected--;
651                     }
652                 } finally {
653                     
654                     try {
655                         if (socket != null) {
656                             socket.close();
657                         }
658                     } catch (IOException e) {
659                         
660                     }
661                 }
662 
663                 
664                 boolean match = command.toString().equals(shutdown);
665                 if (match) {
666                     log.info(sm.getString("standardServer.shutdownViaPort"));
667                     break;
668                 } else
669                     log.warn(sm.getString("standardServer.invalidShutdownCommand", command.toString()));
670             }
671         } finally {
672             ServerSocket serverSocket = awaitSocket;
673             awaitThread = null;
674             awaitSocket = null;
675 
676             
677             if (serverSocket != null) {
678                 try {
679                     serverSocket.close();
680                 } catch (IOException e) {
681                     
682                 }
683             }
684         }
685     }
686 
687 
688     
694     @Override
695     public Service findService(String name) {
696         if (name == null) {
697             return null;
698         }
699         synchronized (servicesLock) {
700             for (int i = 0; i < services.length; i++) {
701                 if (name.equals(services[i].getName())) {
702                     return services[i];
703                 }
704             }
705         }
706         return null;
707     }
708 
709 
710     
713     @Override
714     public Service[] findServices() {
715         return services;
716     }
717 
718     
721     public ObjectName[] getServiceNames() {
722         ObjectName onames[]=new ObjectName[ services.length ];
723         for( int i=0; i<services.length; i++ ) {
724             onames[i]=((StandardService)services[i]).getObjectName();
725         }
726         return onames;
727     }
728 
729 
730     
736     @Override
737     public void removeService(Service service) {
738 
739         synchronized (servicesLock) {
740             int j = -1;
741             for (int i = 0; i < services.length; i++) {
742                 if (service == services[i]) {
743                     j = i;
744                     break;
745                 }
746             }
747             if (j < 0)
748                 return;
749             try {
750                 services[j].stop();
751             } catch (LifecycleException e) {
752                 
753             }
754             int k = 0;
755             Service results[] = new Service[services.length - 1];
756             for (int i = 0; i < services.length; i++) {
757                 if (i != j)
758                     results[k++] = services[i];
759             }
760             services = results;
761 
762             
763             support.firePropertyChange("service", service, null);
764         }
765 
766     }
767 
768 
769     @Override
770     public File getCatalinaBase() {
771         if (catalinaBase != null) {
772             return catalinaBase;
773         }
774 
775         catalinaBase = getCatalinaHome();
776         return catalinaBase;
777     }
778 
779 
780     @Override
781     public void setCatalinaBase(File catalinaBase) {
782         this.catalinaBase = catalinaBase;
783     }
784 
785 
786     @Override
787     public File getCatalinaHome() {
788         return catalinaHome;
789     }
790 
791 
792     @Override
793     public void setCatalinaHome(File catalinaHome) {
794         this.catalinaHome = catalinaHome;
795     }
796 
797 
798     
799 
800     
805     public void addPropertyChangeListener(PropertyChangeListener listener) {
806 
807         support.addPropertyChangeListener(listener);
808 
809     }
810 
811 
812     
817     public void removePropertyChangeListener(PropertyChangeListener listener) {
818 
819         support.removePropertyChangeListener(listener);
820 
821     }
822 
823 
824     
827     @Override
828     public String toString() {
829         StringBuilder sb = new StringBuilder("StandardServer[");
830         sb.append(getPort());
831         sb.append("]");
832         return sb.toString();
833     }
834 
835 
836     
848     public synchronized void storeConfig() throws InstanceNotFoundException, MBeanException {
849         try {
850             
851             ObjectName sname = new ObjectName("Catalina:type=StoreConfig");
852             MBeanServer server = Registry.getRegistry(null, null).getMBeanServer();
853             if (server.isRegistered(sname)) {
854                 server.invoke(sname, "storeConfig", null, null);
855             } else {
856                 log.error(sm.getString("standardServer.storeConfig.notAvailable", sname));
857             }
858         } catch (Throwable t) {
859             ExceptionUtils.handleThrowable(t);
860             log.error(sm.getString("standardServer.storeConfig.error"), t);
861         }
862     }
863 
864 
865     
878     public synchronized void storeContext(Context context) throws InstanceNotFoundException, MBeanException {
879         try {
880             
881             ObjectName sname = new ObjectName("Catalina:type=StoreConfig");
882             MBeanServer server = Registry.getRegistry(null, null).getMBeanServer();
883             if (server.isRegistered(sname)) {
884                 server.invoke(sname, "store",
885                     new Object[] {context},
886                     new String [] { "java.lang.String"});
887             } else {
888                 log.error(sm.getString("standardServer.storeConfig.notAvailable", sname));
889             }
890         } catch (Throwable t) {
891             ExceptionUtils.handleThrowable(t);
892             log.error(sm.getString("standardServer.storeConfig.contextError", context.getName()), t);
893         }
894     }
895 
896 
897     
900     private boolean isUseNaming() {
901         boolean useNaming = true;
902         
903         String useNamingProperty = System.getProperty("catalina.useNaming");
904         if ((useNamingProperty != null)
905             && (useNamingProperty.equals("false"))) {
906             useNaming = false;
907         }
908         return useNaming;
909     }
910 
911 
912     
919     @Override
920     protected void startInternal() throws LifecycleException {
921 
922         fireLifecycleEvent(CONFIGURE_START_EVENT, null);
923         setState(LifecycleState.STARTING);
924 
925         globalNamingResources.start();
926 
927         
928         synchronized (servicesLock) {
929             for (int i = 0; i < services.length; i++) {
930                 services[i].start();
931             }
932         }
933 
934         if (periodicEventDelay > 0) {
935             monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
936                     new Runnable() {
937                         @Override
938                         public void run() {
939                             startPeriodicLifecycleEvent();
940                         }
941                     }, 0, 60, TimeUnit.SECONDS);
942         }
943     }
944 
945 
946     protected void startPeriodicLifecycleEvent() {
947         if (periodicLifecycleEventFuture == null || (periodicLifecycleEventFuture != null && periodicLifecycleEventFuture.isDone())) {
948             if (periodicLifecycleEventFuture != null && periodicLifecycleEventFuture.isDone()) {
949                 
950                 try {
951                     periodicLifecycleEventFuture.get();
952                 } catch (InterruptedException | ExecutionException e) {
953                     log.error(sm.getString("standardServer.periodicEventError"), e);
954                 }
955             }
956             periodicLifecycleEventFuture = getUtilityExecutor().scheduleAtFixedRate(
957                     new Runnable() {
958                         @Override
959                         public void run() {
960                             fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
961                         }
962                     }, periodicEventDelay, periodicEventDelay, TimeUnit.SECONDS);
963         }
964     }
965 
966 
967     
974     @Override
975     protected void stopInternal() throws LifecycleException {
976 
977         setState(LifecycleState.STOPPING);
978 
979         if (monitorFuture != null) {
980             monitorFuture.cancel(true);
981             monitorFuture = null;
982         }
983         if (periodicLifecycleEventFuture != null) {
984             periodicLifecycleEventFuture.cancel(false);
985             periodicLifecycleEventFuture = null;
986         }
987 
988         fireLifecycleEvent(CONFIGURE_STOP_EVENT, null);
989 
990         
991         for (int i = 0; i < services.length; i++) {
992             services[i].stop();
993         }
994 
995         globalNamingResources.stop();
996 
997         stopAwait();
998     }
999 
1000     
1004     @Override
1005     protected void initInternal() throws LifecycleException {
1006 
1007         super.initInternal();
1008 
1009         
1010         reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads));
1011         register(utilityExecutor, "type=UtilityExecutor");
1012 
1013         
1014         
1015         
1016         
1017         onameStringCache = register(new StringCache(), "type=StringCache");
1018 
1019         
1020         MBeanFactory factory = new MBeanFactory();
1021         factory.setContainer(this);
1022         onameMBeanFactory = register(factory, "type=MBeanFactory");
1023 
1024         
1025         globalNamingResources.init();
1026 
1027         
1028         
1029         if (getCatalina() != null) {
1030             ClassLoader cl = getCatalina().getParentClassLoader();
1031             
1032             
1033             while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
1034                 if (cl instanceof URLClassLoader) {
1035                     URL[] urls = ((URLClassLoader) cl).getURLs();
1036                     for (URL url : urls) {
1037                         if (url.getProtocol().equals("file")) {
1038                             try {
1039                                 File f = new File (url.toURI());
1040                                 if (f.isFile() &&
1041                                         f.getName().endsWith(".jar")) {
1042                                     ExtensionValidator.addSystemResource(f);
1043                                 }
1044                             } catch (URISyntaxException e) {
1045                                 
1046                             } catch (IOException e) {
1047                                 
1048                             }
1049                         }
1050                     }
1051                 }
1052                 cl = cl.getParent();
1053             }
1054         }
1055         
1056         for (int i = 0; i < services.length; i++) {
1057             services[i].init();
1058         }
1059     }
1060 
1061     @Override
1062     protected void destroyInternal() throws LifecycleException {
1063         
1064         for (int i = 0; i < services.length; i++) {
1065             services[i].destroy();
1066         }
1067 
1068         globalNamingResources.destroy();
1069 
1070         unregister(onameMBeanFactory);
1071 
1072         unregister(onameStringCache);
1073 
1074         if (utilityExecutor != null) {
1075             utilityExecutor.shutdownNow();
1076             unregister("type=UtilityExecutor");
1077             utilityExecutor = null;
1078         }
1079 
1080         super.destroyInternal();
1081     }
1082 
1083     
1086     @Override
1087     public ClassLoader getParentClassLoader() {
1088         if (parentClassLoader != null)
1089             return parentClassLoader;
1090         if (catalina != null) {
1091             return catalina.getParentClassLoader();
1092         }
1093         return ClassLoader.getSystemClassLoader();
1094     }
1095 
1096     
1101     @Override
1102     public void setParentClassLoader(ClassLoader parent) {
1103         ClassLoader oldParentClassLoader = this.parentClassLoader;
1104         this.parentClassLoader = parent;
1105         support.firePropertyChange("parentClassLoader", oldParentClassLoader,
1106                                    this.parentClassLoader);
1107     }
1108 
1109 
1110     private ObjectName onameStringCache;
1111     private ObjectName onameMBeanFactory;
1112 
1113     
1121     @Override
1122     protected String getDomainInternal() {
1123 
1124         String domain = null;
1125 
1126         Service[] services = findServices();
1127         if (services.length > 0) {
1128             Service service = services[0];
1129             if (service != null) {
1130                 domain = service.getDomain();
1131             }
1132         }
1133         return domain;
1134     }
1135 
1136 
1137     @Override
1138     protected final String getObjectNameKeyProperties() {
1139         return "type=Server";
1140     }
1141 
1142     @Override
1143     public ScheduledExecutorService getUtilityExecutor() {
1144         return utilityExecutorWrapper;
1145     }
1146 }
1147