KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > server > resin > Resin


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.server.resin;
31
32 import com.caucho.config.Config;
33 import com.caucho.config.ConfigELContext;
34 import com.caucho.config.ConfigException;
35 import com.caucho.config.SchemaBean;
36 import com.caucho.config.types.Bytes;
37 import com.caucho.config.types.InitProgram;
38 import com.caucho.config.types.Period;
39 import com.caucho.el.EL;
40 import com.caucho.el.MapVariableResolver;
41 import com.caucho.el.SystemPropertiesResolver;
42 import com.caucho.jsp.cfg.JspPropertyGroup;
43 import com.caucho.license.LicenseCheck;
44 import com.caucho.lifecycle.Lifecycle;
45 import com.caucho.lifecycle.LifecycleState;
46 import com.caucho.loader.Environment;
47 import com.caucho.loader.EnvironmentBean;
48 import com.caucho.loader.EnvironmentClassLoader;
49 import com.caucho.loader.EnvironmentLocal;
50 import com.caucho.loader.EnvironmentProperties;
51 import com.caucho.log.EnvironmentStream;
52 import com.caucho.log.RotateStream;
53 import com.caucho.management.j2ee.J2EEDomain;
54 import com.caucho.management.j2ee.J2EEManagedObject;
55 import com.caucho.management.j2ee.JVM;
56 import com.caucho.management.server.ClusterMXBean;
57 import com.caucho.naming.Jndi;
58 import com.caucho.server.cluster.Cluster;
59 import com.caucho.server.cluster.ClusterServer;
60 import com.caucho.server.cluster.Server;
61 import com.caucho.transaction.cfg.TransactionManagerConfig;
62 import com.caucho.util.Alarm;
63 import com.caucho.util.CompileException;
64 import com.caucho.util.L10N;
65 import com.caucho.util.QDate;
66 import com.caucho.util.RandomUtil;
67 import com.caucho.vfs.Path;
68 import com.caucho.vfs.QJniServerSocket;
69 import com.caucho.vfs.QServerSocket;
70 import com.caucho.vfs.Vfs;
71 import com.caucho.vfs.WriteStream;
72
73 import javax.annotation.PostConstruct;
74 import javax.el.ELResolver;
75 import javax.management.ObjectName JavaDoc;
76 import java.io.FileInputStream JavaDoc;
77 import java.io.InputStream JavaDoc;
78 import java.io.InterruptedIOException JavaDoc;
79 import java.net.BindException JavaDoc;
80 import java.net.InetAddress JavaDoc;
81 import java.net.Socket JavaDoc;
82 import java.net.SocketException JavaDoc;
83 import java.net.SocketTimeoutException JavaDoc;
84 import java.security.Provider JavaDoc;
85 import java.security.Security JavaDoc;
86 import java.util.ArrayList JavaDoc;
87 import java.util.Date JavaDoc;
88 import java.util.HashMap JavaDoc;
89 import java.util.logging.Level JavaDoc;
90 import java.util.logging.Logger JavaDoc;
91
92 /**
93  * The Resin class represents the top-level container for Resin.
94  * It exactly matches the <resin> tag in the resin.conf
95  */

96 public class Resin implements EnvironmentBean, SchemaBean
97 {
98   private static Logger JavaDoc _log;
99   private static L10N _L;
100
101   private static final String JavaDoc OBJECT_NAME= "resin:type=Resin";
102
103   private static final EnvironmentLocal<Resin> _resinLocal =
104     new EnvironmentLocal<Resin>();
105
106   private final EnvironmentLocal<String JavaDoc> _serverIdLocal =
107     new EnvironmentLocal<String JavaDoc>("caucho.server-id");
108
109   private ObjectName JavaDoc _objectName;
110
111   private EnvironmentClassLoader _classLoader;
112   private boolean _isGlobal;
113
114   private String JavaDoc _serverId = "";
115
116   private Path _resinHome;
117   private Path _rootDirectory;
118
119   private boolean _isGlobalSystemProperties;
120   private boolean _isResinProfessional;
121
122   private long _minFreeMemory = 2 * 1024L * 1024L;
123   private long _shutdownWaitMax = 60000L;
124
125   private SecurityManager JavaDoc _securityManager;
126
127   private HashMap JavaDoc<String JavaDoc,Object JavaDoc> _variableMap = new HashMap JavaDoc<String JavaDoc,Object JavaDoc>();
128
129   private ArrayList JavaDoc<InitProgram> _clusterDefaults
130     = new ArrayList JavaDoc<InitProgram>();
131
132   private ArrayList JavaDoc<Cluster> _clusters
133     = new ArrayList JavaDoc<Cluster>();
134
135   private Lifecycle _lifecycle;
136
137   private Server _server;
138
139   private long _initialStartTime;
140   private long _startTime;
141   private J2EEDomain _j2eeDomainManagedObject;
142   private JVM _jvmManagedObject;
143
144   private String JavaDoc _configFile;
145   private String JavaDoc _configServer;
146
147   private Path _resinConf;
148
149   private ClassLoader JavaDoc _systemClassLoader;
150   private Thread JavaDoc _mainThread;
151
152   private ArrayList JavaDoc<BoundPort> _boundPortList
153     = new ArrayList JavaDoc<BoundPort>();
154
155   private InputStream JavaDoc _waitIn;
156
157   private Socket _pingSocket;
158
159   /**
160    * Creates a new resin server.
161    */

162   public Resin()
163   {
164     this(Thread.currentThread().getContextClassLoader());
165   }
166
167   /**
168    * Creates a new resin server.
169    */

170   public Resin(ClassLoader JavaDoc loader)
171   {
172     Environment.init();
173
174     if (loader == null)
175       loader = ClassLoader.getSystemClassLoader();
176
177     _isGlobal = (loader == ClassLoader.getSystemClassLoader());
178
179     if (loader instanceof EnvironmentClassLoader)
180       _classLoader = (EnvironmentClassLoader) loader;
181     else
182       _classLoader = new EnvironmentClassLoader();
183
184     _resinLocal.set(this, _classLoader);
185
186     _lifecycle = new Lifecycle(log(), "Resin[]");
187
188     _startTime = Alarm.getCurrentTime();
189
190     String JavaDoc resinHome = System.getProperty("resin.home");
191
192     if (resinHome != null)
193       setResinHome(Vfs.lookup(resinHome));
194     else
195       setResinHome(Vfs.getPwd());
196
197     // server.root backwards compat
198
String JavaDoc serverRoot = System.getProperty("server.root");
199
200     if (serverRoot != null)
201       setRootDirectory(Vfs.lookup(serverRoot));
202
203     // watchdog/0212
204
// else
205
// setRootDirectory(Vfs.getPwd());
206

207     _variableMap.put("resin", new Var());
208     _variableMap.put("server", new Var());
209     _variableMap.put("java", new JavaVar());
210
211     ELResolver varResolver = new SystemPropertiesResolver();
212     ConfigELContext elContext = new ConfigELContext(varResolver);
213     elContext.push(new MapVariableResolver(_variableMap));
214
215     EL.setEnvironment(elContext);
216     EL.setVariableMap(_variableMap, _classLoader);
217
218     _variableMap.put("fmt", new com.caucho.config.functions.FmtFunctions());
219
220     try {
221       _variableMap.put("jndi", Jndi.class.getMethod("lookup", new Class JavaDoc[] { String JavaDoc.class }));
222       _variableMap.put("jndi:lookup", Jndi.class.getMethod("lookup", new Class JavaDoc[] { String JavaDoc.class }));
223     } catch (Exception JavaDoc e) {
224       throw new ConfigException(e);
225     }
226
227     ThreadPoolAdmin.create();
228
229     new ResinAdmin(this);
230   }
231
232   /**
233    * Returns the resin server.
234    */

235   public static Resin getLocal()
236   {
237     return _resinLocal.get();
238   }
239
240   /**
241    * Returns the classLoader
242    */

243   public ClassLoader JavaDoc getClassLoader()
244   {
245     return _classLoader;
246   }
247
248   public ObjectName JavaDoc getObjectName()
249   {
250     return _objectName;
251   }
252
253   /**
254    * Sets the classLoader
255    */

256   public void setEnvironmentClassLoader(EnvironmentClassLoader loader)
257   {
258     _classLoader = loader;
259   }
260
261   /**
262    * Returns the relax schema.
263    */

264   public String JavaDoc getSchema()
265   {
266     return "com/caucho/server/resin/resin.rnc";
267   }
268
269   /**
270    * Sets the server id.
271    */

272   public void setServerId(String JavaDoc serverId)
273   {
274     _variableMap.put("serverId", serverId);
275
276     _serverId = serverId;
277     _serverIdLocal.set(serverId);
278   }
279
280   /**
281    * Returns the server id.
282    */

283   public String JavaDoc getServerId()
284   {
285     return _serverId;
286   }
287
288   /**
289    * Sets the config file.
290    */

291   public void setConfigFile(String JavaDoc configFile)
292   {
293     _configFile = configFile;
294   }
295
296   /**
297    * Sets resin.home
298    */

299   public void setResinHome(Path home)
300   {
301     _resinHome = home;
302
303     _variableMap.put("resinHome", _resinHome);
304     _variableMap.put("resin-home", _resinHome);
305   }
306
307   /**
308    * Returns resin.home.
309    */

310   public Path getResinHome()
311   {
312     return _resinHome;
313   }
314
315   /**
316    * Sets the root directory.
317    */

318   public void setRootDirectory(Path root)
319   {
320     _rootDirectory = root;
321
322     _variableMap.put("serverRoot", root);
323     _variableMap.put("server-root", root);
324   }
325
326   /**
327    * Gets the root directory.
328    */

329   public Path getRootDirectory()
330   {
331     return _rootDirectory;
332   }
333
334   /**
335    * The configuration file used to start the server.
336    */

337   public Path getResinConf()
338   {
339     return _resinConf;
340   }
341
342   /**
343    * Set true for Resin pro.
344    */

345   void setResinProfessional(boolean isPro)
346   {
347     _isResinProfessional = isPro;
348   }
349
350   /**
351    * Set true for Resin pro.
352    */

353   public boolean isProfessional()
354   {
355     return _isResinProfessional;
356   }
357
358   /**
359    * Returns the cluster names.
360    */

361   public ClusterMXBean []getClusters()
362   {
363     ClusterMXBean []clusters = new ClusterMXBean[_clusters.size()];
364
365     for (int i = 0; i < _clusters.size(); i++)
366       clusters[i] = _clusters.get(i).getAdmin();
367
368     return clusters;
369   }
370
371   public void addClusterDefault(InitProgram program)
372   {
373     _clusterDefaults.add(program);
374   }
375
376   public Cluster createCluster()
377     throws Throwable JavaDoc
378   {
379     Cluster cluster = new Cluster(this);
380
381     for (int i = 0; i < _clusterDefaults.size(); i++)
382       _clusterDefaults.get(i).configure(cluster);
383
384     return cluster;
385   }
386
387   public void addCluster(Cluster cluster)
388   {
389     _clusters.add(cluster);
390   }
391
392   public ArrayList JavaDoc<Cluster> getClusterList()
393   {
394     return _clusters;
395   }
396
397   /**
398    * Set true if the server should enable environment-based
399    * system properties.
400    */

401   public void setEnvironmentSystemProperties(boolean isEnable)
402   {
403     EnvironmentProperties.enableEnvironmentSystemProperties(isEnable);
404   }
405
406   /**
407    * Creates the compatibility server.
408    */

409   public ServerCompatConfig createServer()
410   {
411     return new ServerCompatConfig(this);
412     /*
413     if (Alarm.isTest() && _servers.size() == 1) {
414       _servers.get(0).addConfigDefault(config);
415     }
416     else {
417       String id = config.getId();
418
419       if (id != null && ! id.equals("")) {
420       }
421       else
422         id = String.valueOf(_servers.size());
423
424       ServerController controller = new ServerController(config);
425       controller.setResin(this);
426
427       _servers.add(controller);
428
429       // XXX: controller.addServerListener(this);
430
431       controller.setServerId(_serverId);
432       controller.setConfig(config);
433
434       controller.init();
435     }
436     */

437   }
438
439   /**
440    * Configures the thread pool
441    */

442   public ThreadPoolConfig createThreadPool()
443     throws Exception JavaDoc
444   {
445     return new ThreadPoolConfig();
446   }
447
448   /**
449    * Sets the user name for setuid.
450    */

451   public void setUserName(String JavaDoc userName)
452   {
453   }
454
455   /**
456    * Sets the group name for setuid.
457    */

458   public void setGroupName(String JavaDoc groupName)
459   {
460   }
461
462   /**
463    * Sets the minimum free memory allowed.
464    */

465   public void setMinFreeMemory(Bytes minFreeMemory)
466   {
467     _minFreeMemory = minFreeMemory.getBytes();
468   }
469
470   /**
471    * Gets the minimum free memory allowed.
472    */

473   public long getMinFreeMemory()
474   {
475     return _minFreeMemory;
476   }
477
478   /**
479    * Sets the shutdown time
480    */

481   public void setShutdownWaitMax(Period shutdownWaitMax)
482   {
483     _shutdownWaitMax = shutdownWaitMax.getPeriod();
484   }
485
486   /**
487    * Gets the minimum free memory allowed.
488    */

489   public long getShutdownWaitMax()
490   {
491     return _shutdownWaitMax;
492   }
493
494   /**
495    * Set true if system properties are global.
496    */

497   public void setGlobalSystemProperties(boolean isGlobal)
498   {
499     _isGlobalSystemProperties = isGlobal;
500   }
501
502   /**
503    * Configures the TM.
504    */

505   public void addTransactionManager(TransactionManagerConfig tm)
506     throws ConfigException
507   {
508     // the start is necessary to handle the QA tests
509

510     tm.start();
511   }
512
513   public SecurityManagerConfig createSecurityManager()
514   {
515     return new SecurityManagerConfig();
516   }
517
518   /**
519    * Adds a new security provider
520    */

521   public void addSecurityProvider(Class JavaDoc providerClass)
522     throws Exception JavaDoc
523   {
524     if (! Provider JavaDoc.class.isAssignableFrom(providerClass))
525       throw new ConfigException(L().l("security-provider {0} must implement java.security.Provider",
526                                     providerClass.getName()));
527
528     Security.addProvider((Provider JavaDoc) providerClass.newInstance());
529   }
530
531   /**
532    * Configures JSP (backwards compatibility).
533    */

534   public JspPropertyGroup createJsp()
535   {
536     return new JspPropertyGroup();
537   }
538
539   /**
540    * Ignore the boot configuration
541    */

542   public void addBoot(InitProgram program)
543     throws Exception JavaDoc
544   {
545   }
546
547   /**
548    * Sets the initial start time.
549    */

550   void setInitialStartTime(long now)
551   {
552     _initialStartTime = now;
553   }
554
555   /**
556    * Returns the initial start time.
557    */

558   public Date getInitialStartTime()
559   {
560     return new Date(_initialStartTime);
561   }
562
563   /**
564    * Returns the start time.
565    */

566   public Date getStartTime()
567   {
568     return new Date(_startTime);
569   }
570
571   /**
572    * Returns the current lifecycle state.
573    */

574   public LifecycleState getLifecycleState()
575   {
576     return _lifecycle;
577   }
578
579   /**
580    * Initialize the server.
581    */

582   @PostConstruct
583   public void init()
584   {
585     _lifecycle.toInit();
586   }
587
588   /**
589    * Returns the active server.
590    */

591   public Server getServer()
592   {
593     return _server;
594   }
595
596   /**
597    * Starts the server.
598    */

599   public void start()
600     throws Throwable JavaDoc
601   {
602     if (! _lifecycle.toActive())
603       return;
604
605     long start = Alarm.getCurrentTime();
606
607     _j2eeDomainManagedObject = J2EEManagedObject.register(new J2EEDomain());
608     _jvmManagedObject = J2EEManagedObject.register(new JVM());
609
610     // force a GC on start
611
System.gc();
612
613     // XXX: get the server
614

615     ClusterServer clusterServer = findClusterServer(_serverId);
616
617     if (clusterServer == null)
618       throw new ConfigException(L().l("server-id '{0}' has no matching <server> definition.",
619                     _serverId));
620
621
622     _server = clusterServer.startServer();
623
624     /*
625     ArrayList<ServerController> servers = _servers;
626
627     for (int i = 0; i < servers.size(); i++) {
628       ServerController server = servers.get(i);
629
630       server.start();
631     }
632     */

633
634     Environment.start(getClassLoader());
635
636     /*
637     if (! hasListeningPort()) {
638       log().warning(L().l("-server \"{0}\" has no matching http or srun ports. Check the resin.conf and -server values.",
639                       _serverId));
640     }
641     */

642
643     log().info("Resin started in " + (Alarm.getCurrentTime() - _startTime) + "ms");
644   }
645
646   public Cluster findCluster(String JavaDoc id)
647   {
648     for (int i = 0; i < _clusters.size(); i++) {
649       Cluster cluster = _clusters.get(i);
650
651       if (cluster.getId().equals(id))
652     return cluster;
653     }
654
655     return null;
656   }
657
658   public ClusterServer findClusterServer(String JavaDoc id)
659   {
660     for (int i = 0; i < _clusters.size(); i++) {
661       Cluster cluster = _clusters.get(i);
662
663       ClusterServer server = cluster.findServer(id);
664
665       if (server != null)
666     return server;
667     }
668
669     return null;
670   }
671
672   /**
673    * Returns true if active.
674    */

675   public boolean isActive()
676   {
677     return _lifecycle.isActive();
678   }
679
680   /**
681    * Returns true if the server is closing.
682    */

683   public boolean isClosing()
684   {
685     return _lifecycle.isDestroying();
686   }
687
688   /**
689    * Returns true if the server is closed.
690    */

691   public boolean isClosed()
692   {
693     return _lifecycle.isDestroyed();
694   }
695
696   /**
697    * Closes the server.
698    */

699   public void destroy()
700   {
701     if (! _lifecycle.toDestroying())
702       return;
703
704     try {
705       // notify watchdog thread before starting shutdown
706
synchronized (this) {
707     notifyAll();
708       }
709
710       Socket socket = _pingSocket;
711
712       if (socket != null)
713     socket.setSoTimeout(1000);
714     } catch (Throwable JavaDoc e) {
715       log().log(Level.WARNING, e.toString(), e);
716     }
717
718     try {
719       Server server = _server;
720       _server = null;
721
722       if (server != null)
723     server.destroy();
724     } catch (Throwable JavaDoc e) {
725       log().log(Level.WARNING, e.toString(), e);
726     }
727
728     try {
729       if (_isGlobal)
730     Environment.closeGlobal();
731       else
732     _classLoader.destroy();
733     } finally {
734       _lifecycle.toDestroy();
735     }
736   }
737
738   /**
739    * Create a new Resin server.
740    *
741    * @param argv the command-line to initialize Resin with
742    * @param isHttp default to http
743    */

744   /*
745   public Resin(String []argv)
746     throws Exception
747   {
748     _systemClassLoader = Thread.currentThread().getContextClassLoader();
749     _startTime = Alarm.getCurrentTime();
750
751     _resinHome = CauchoSystem.getResinHome();
752     _serverRoot = _resinHome;
753
754     parseCommandLine(argv);
755   }
756   */

757
758   private void parseCommandLine(String JavaDoc []argv)
759     throws Exception JavaDoc
760   {
761     int len = argv.length;
762     int i = 0;
763
764     while (i < len) {
765       RandomUtil.addRandom(argv[i]);
766
767       if (i + 1 < len &&
768           (argv[i].equals("-stdout") ||
769            argv[i].equals("--stdout"))) {
770         Path path = Vfs.lookup(argv[i + 1]);
771
772         RotateStream stream = RotateStream.create(path);
773     stream.init();
774     WriteStream out = stream.getStream();
775     out.setDisableClose(true);
776
777         EnvironmentStream.setStdout(out);
778
779     i += 2;
780       }
781       else if (i + 1 < len &&
782                (argv[i].equals("-stderr") ||
783                 argv[i].equals("--stderr"))) {
784         Path path = Vfs.lookup(argv[i + 1]);
785
786         RotateStream stream = RotateStream.create(path);
787     stream.init();
788     WriteStream out = stream.getStream();
789     out.setDisableClose(true);
790
791         EnvironmentStream.setStderr(out);
792
793     i += 2;
794       }
795       else if (i + 1 < len &&
796                (argv[i].equals("-conf") ||
797                 argv[i].equals("--conf"))) {
798         _configFile = argv[i + 1];
799     i += 2;
800       }
801       else if (i + 1 < len &&
802                (argv[i].equals("-server") ||
803                 argv[i].equals("--server"))) {
804     _serverId = argv[i + 1];
805     i += 2;
806       }
807       else if (argv[i].equals("-version")
808            || argv[i].equals("--version")) {
809     System.out.println(com.caucho.Version.FULL_VERSION);
810     System.exit(66);
811       }
812       else if (argv[i].equals("-resin-home")
813            || argv[i].equals("--resin-home")) {
814     _resinHome = Vfs.lookup(argv[i + 1]);
815
816     i += 2;
817       }
818       else if (argv[i].equals("-root-directory")
819                || argv[i].equals("--root-directory")) {
820         _rootDirectory = _resinHome.lookup(argv[i + 1]);
821
822         i += 2;
823       }
824       else if (argv[i].equals("-server-root") // backwards compat
825
|| argv[i].equals("--server-root")) {
826     _rootDirectory = _resinHome.lookup(argv[i + 1]);
827
828     i += 2;
829       }
830       else if (argv[i].equals("-config-server") ||
831                argv[i].equals("--config-server")) {
832         _configServer = argv[i + 1];
833         i += 2;
834       }
835       else if (argv[i].equals("-socketwait") ||
836                argv[i].equals("--socketwait") ||
837                argv[i].equals("-pingwait") ||
838                argv[i].equals("--pingwait")) {
839         int socketport = Integer.parseInt(argv[i + 1]);
840
841         Socket socket = null;
842         for (int k = 0; k < 15 && socket == null; k++) {
843           try {
844             socket = new Socket("127.0.0.1", socketport);
845           } catch (Throwable JavaDoc e) {
846         System.out.println(new Date());
847         e.printStackTrace();
848           }
849
850           if (socket == null)
851             Thread.sleep(1000);
852         }
853
854         if (socket == null) {
855           System.err.println("Can't connect to parent process through socket " + socketport);
856           System.err.println("Resin needs to connect to its parent.");
857           System.exit(0);
858         }
859
860     if (argv[i].equals("-socketwait") || argv[i].equals("--socketwait"))
861           _waitIn = socket.getInputStream();
862     else
863       _pingSocket = socket;
864
865         socket.setSoTimeout(60000);
866
867     i += 2;
868       }
869       else if ("-port".equals(argv[i]) || "--port".equals(argv[i])) {
870         int fd = Integer.parseInt(argv[i + 1]);
871     String JavaDoc addr = argv[i + 2];
872     if ("null".equals(addr))
873       addr = null;
874     int port = Integer.parseInt(argv[i + 3]);
875
876     _boundPortList.add(new BoundPort(QJniServerSocket.openJNI(fd, port),
877                      addr,
878                      port));
879
880     i += 4;
881       }
882       else if ("start".equals(argv[i])
883            || "restart".equals(argv[i])) {
884     i++;
885       }
886       else if (argv[i].equals("-verbose")
887            || argv[i].equals("--verbose")) {
888     i += 1;
889       }
890       else if (argv[i].equals("-fine")
891            || argv[i].equals("--fine")) {
892     i += 1;
893       }
894       else if (argv[i].equals("-finer")
895            || argv[i].equals("--finer")) {
896     i += 1;
897       }
898       else {
899         System.out.println(L().l("unknown argument '{0}'", argv[i]));
900         System.out.println();
901     usage();
902     System.exit(66);
903       }
904     }
905   }
906
907   private static void usage()
908   {
909     System.err.println(L().l("usage: Resin [-conf resin.conf] [-server id]"));
910   }
911
912   /**
913    * Initialize the server, binding to TCP and starting the threads.
914    */

915   public void initMain()
916     throws Throwable JavaDoc
917   {
918     _mainThread = Thread.currentThread();
919     _mainThread.setContextClassLoader(_systemClassLoader);
920
921     addRandom();
922
923     System.out.println(com.caucho.Version.FULL_VERSION);
924     System.out.println(com.caucho.Version.COPYRIGHT);
925     System.out.println();
926
927     boolean isResinProfessional = false;
928
929     try {
930       Class JavaDoc cl = Class.forName("com.caucho.license.LicenseCheckImpl",
931                    false,
932                    ClassLoader.getSystemClassLoader());
933
934       LicenseCheck license = (LicenseCheck) cl.newInstance();
935
936       try {
937     license.validate(0);
938
939     license.doLogging(1);
940
941     license.validate(1);
942
943     isResinProfessional = true;
944     System.setProperty("isResinProfessional", "true");
945
946     Vfs.initJNI();
947
948     // license.doLogging(1);
949
} catch (Throwable JavaDoc e) {
950     String JavaDoc msg;
951
952     if (e instanceof ConfigException)
953       msg = e.getMessage() + "\n";
954     else {
955       e.printStackTrace();
956
957       msg = e.toString() + "\n";
958
959       log().log(Level.WARNING, e.toString(), e);
960     }
961
962     log().log(Level.FINE, e.toString(), e);
963
964     msg += L().l("\n" +
965              "Using Resin Open Source under the GNU Public License (GPL).\n" +
966              "\n" +
967              " See http://www.caucho.com for information on Resin Professional.\n");
968
969     log().warning(msg);
970     System.err.println(msg);
971       }
972     } catch (Throwable JavaDoc e) {
973       log().log(Level.FINER, e.toString(), e);
974
975       String JavaDoc msg = L().l(" Using Resin(R) Open Source under the GNU Public License (GPL).\n" +
976              "\n" +
977              " See http://www.caucho.com for information on Resin Professional,\n" +
978              " including caching, clustering, JNI acceleration, and OpenSSL integration.\n");
979
980       log().warning(msg);
981       System.err.println(msg);
982     }
983
984     System.out.println("Starting Resin on " + QDate.formatLocal(Alarm.getCurrentTime()));
985     System.out.println();
986
987     EnvironmentClassLoader.initializeEnvironment();
988
989     // buildResinClassLoader();
990

991     // validateEnvironment();
992

993     if (_classLoader != null)
994       _mainThread.setContextClassLoader(_classLoader);
995
996     /*
997     if (isResinProfessional && _configServer != null) {
998       Path dbDir = Vfs.lookup("work/config");
999
1000      Class cl = Class.forName("com.caucho.vfs.remote.RemotePath");
1001      Constructor ctor = cl.getConstructor(new Class[] { String.class,
1002                             Path.class,
1003                              String.class });
1004
1005      Path path = (Path) ctor.newInstance(_configServer, dbDir, _serverId);
1006
1007      ConfigPath.setRemote(path);
1008      log().info("Using configuration from " + _configServer);
1009    }
1010    */

1011
1012    Path pwd = Vfs.getPwd();
1013
1014    if (_rootDirectory == null)
1015      _rootDirectory = _resinHome;
1016
1017    Vfs.setPwd(_rootDirectory);
1018
1019    Path resinConf = null;
1020
1021    if (_configFile != null) {
1022      if (log().isLoggable(Level.FINER))
1023        log().log(Level.FINER, "looking for conf in " + pwd.lookup(_configFile));
1024
1025      resinConf = pwd.lookup(_configFile);
1026    }
1027
1028    if (_configFile == null)
1029      _configFile = "conf/resin.conf";
1030
1031    if (resinConf == null || !resinConf.exists()) {
1032      if (log().isLoggable(Level.FINER))
1033        log().log(Level.FINER, "looking for conf in " + _rootDirectory.lookup(_configFile));
1034
1035      resinConf = _rootDirectory.lookup(_configFile);
1036    }
1037
1038    if (!resinConf.exists() && ! _resinHome.equals(_rootDirectory)) {
1039      if (log().isLoggable(Level.FINER))
1040        log().log(Level.FINER, "looking for conf in " + _resinHome.lookup(_configFile));
1041
1042      resinConf = _resinHome.lookup(_configFile);
1043    }
1044
1045    // for error messages, show path relative to rootDirectory
1046
if (!resinConf.exists())
1047      resinConf = _rootDirectory.lookup(_configFile);
1048
1049    _resinConf = resinConf;
1050
1051    // server.setServerRoot(_serverRoot);
1052

1053    setResinProfessional(isResinProfessional);
1054
1055    _mainThread.setContextClassLoader(_systemClassLoader);
1056
1057    Config config = new Config();
1058    // server/10hc
1059
// config.setResinInclude(true);
1060

1061    config.configure(this, resinConf, getSchema());
1062
1063    ClusterServer clusterServer = findClusterServer(_serverId);
1064    for (int i = 0; i < _boundPortList.size(); i++) {
1065      BoundPort port = _boundPortList.get(i);
1066
1067      clusterServer.bind(port.getAddress(),
1068             port.getPort(),
1069             port.getServerSocket());
1070    }
1071
1072    start();
1073  }
1074
1075  private void addRandom()
1076  {
1077    RandomUtil.addRandom(System.currentTimeMillis());
1078    RandomUtil.addRandom(Runtime.getRuntime().freeMemory());
1079
1080    RandomUtil.addRandom(System.identityHashCode(_mainThread));
1081    RandomUtil.addRandom(System.identityHashCode(_systemClassLoader));
1082    RandomUtil.addRandom(com.caucho.Version.FULL_VERSION);
1083
1084    try {
1085      RandomUtil.addRandom(InetAddress.getLocalHost().toString());
1086    } catch (Throwable JavaDoc e) {
1087    }
1088
1089    // for systems with /dev/urandom, read more bits from it.
1090
try {
1091      InputStream JavaDoc is = new FileInputStream JavaDoc("/dev/urandom");
1092
1093      for (int i = 0; i < 16; i++)
1094    RandomUtil.addRandom(is.read());
1095
1096      is.close();
1097    } catch (Throwable JavaDoc e) {
1098    }
1099
1100    RandomUtil.addRandom(System.currentTimeMillis());
1101  }
1102
1103  /**
1104   * Thread to wait until Resin should be stopped.
1105   */

1106  public void waitForExit()
1107  {
1108    int socketExceptionCount = 0;
1109    Integer JavaDoc memoryTest;
1110    Runtime JavaDoc runtime = Runtime.getRuntime();
1111
1112    /*
1113     * If the server has a parent process watching over us, close
1114     * gracefully when the parent dies.
1115     */

1116    while (! isClosing()) {
1117      try {
1118    Thread.sleep(10);
1119
1120    long minFreeMemory = getMinFreeMemory();
1121
1122    if (minFreeMemory <= 0) {
1123      // memory check disabled
1124
}
1125    else if (2 * minFreeMemory < getFreeMemory(runtime)) {
1126      // plenty of free memory
1127
}
1128    else {
1129      if (log().isLoggable(Level.FINER)) {
1130        log().finer(L().l("free memory {0} max:{1} total:{2} free:{3}",
1131              "" + getFreeMemory(runtime),
1132              "" + runtime.maxMemory(),
1133              "" + runtime.totalMemory(),
1134              "" + runtime.freeMemory()));
1135      }
1136
1137      log().info(L().l("Forcing GC due to low memory. {0} free bytes.",
1138               getFreeMemory(runtime)));
1139
1140      runtime.gc();
1141
1142      Thread.sleep(1000);
1143
1144      runtime.gc();
1145
1146      if (getFreeMemory(runtime) < minFreeMemory) {
1147        log().severe(L().l("Restarting due to low free memory. {0} free bytes",
1148               getFreeMemory(runtime)));
1149        destroy();
1150        return;
1151      }
1152    }
1153
1154        // second memory check
1155
memoryTest = new Integer JavaDoc(0);
1156
1157    long alarmTime = Alarm.getCurrentTime();
1158    long systemTime = System.currentTimeMillis();
1159
1160    long diff = alarmTime - systemTime;
1161    if (diff < 0)
1162      diff = -diff;
1163
1164    // The time difference needs to be fairly large because
1165
// GC might take a good deal of time.
1166
if (10 * 60000L < diff) {
1167      log().severe(L().l("Restarting due to frozen Resin timer manager thread (Alarm). This error generally indicates a JVM freeze, not an application deadlock."));
1168      Runtime.getRuntime().halt(1);
1169    }
1170
1171    if (_waitIn != null) {
1172          int len;
1173          if ((len = _waitIn.read()) >= 0) {
1174            socketExceptionCount = 0;
1175          }
1176
1177      return;
1178        }
1179        else {
1180      synchronized (this) {
1181        wait(10000);
1182      }
1183        }
1184      } catch (SocketTimeoutException JavaDoc e) {
1185        socketExceptionCount = 0;
1186      } catch (InterruptedIOException JavaDoc e) {
1187        socketExceptionCount = 0;
1188      } catch (InterruptedException JavaDoc e) {
1189        socketExceptionCount = 0;
1190      } catch (SocketException JavaDoc e) {
1191        // The Solaris JVM will throw SocketException periodically
1192
// instead of interrupted exception, so those exceptions need to
1193
// be ignored.
1194

1195        // However, the Windows JVMs will throw connection reset by peer
1196
// instead of returning an end of file in the read. So those
1197
// need to be trapped to close the socket.
1198
if (socketExceptionCount++ == 0) {
1199          log().log(Level.FINE, e.toString(), e);
1200        }
1201        else if (socketExceptionCount > 100)
1202          return;
1203      } catch (OutOfMemoryError JavaDoc e) {
1204    try {
1205      System.err.println("Out of memory");
1206    } finally {
1207      Runtime.getRuntime().halt(1);
1208    }
1209      } catch (Throwable JavaDoc e) {
1210        log().log(Level.FINE, e.toString(), e);
1211
1212        return;
1213      }
1214    }
1215  }
1216
1217  private static long getFreeMemory(Runtime JavaDoc runtime)
1218  {
1219    long maxMemory = runtime.maxMemory();
1220    long totalMemory = runtime.totalMemory();
1221    long freeMemory = runtime.freeMemory();
1222
1223    // Some JDKs (JRocket) return 0 for the maxMemory
1224
if (maxMemory < totalMemory)
1225      return freeMemory;
1226    else
1227      return maxMemory - totalMemory + freeMemory;
1228  }
1229
1230  /**
1231   * Shuts the server down.
1232   */

1233  public static void shutdown()
1234  {
1235    Resin resin = getLocal();
1236
1237    if (resin != null) {
1238      resin.destroy();
1239    }
1240  }
1241
1242  /**
1243   * The main start of the web server.
1244   *
1245   * <pre>
1246   * -conf resin.conf : alternate configuration file
1247   * -port port : set the server's portt
1248   * <pre>
1249   */

1250  public static void main(String JavaDoc []argv)
1251  {
1252    try {
1253      validateEnvironment();
1254
1255      final Resin resin = new Resin();
1256
1257      resin.parseCommandLine(argv);
1258
1259      resin.initMain();
1260
1261      resin.waitForExit();
1262
1263      System.err.println(L().l("closing server"));
1264
1265      new Thread JavaDoc() {
1266    public void run()
1267    {
1268      setName("resin-destroy");
1269
1270      resin.destroy();
1271    }
1272      }.start();
1273
1274      Server server = resin.getServer();
1275
1276      long stopTime = System.currentTimeMillis();
1277      long endTime = stopTime + 15000L;
1278
1279      if (server != null)
1280    endTime = stopTime + server.getShutdownWaitMax() ;
1281
1282      while (System.currentTimeMillis() < endTime && ! resin.isClosed()) {
1283    try {
1284      Thread.interrupted();
1285      Thread.sleep(100);
1286    } catch (Throwable JavaDoc e) {
1287    }
1288      }
1289
1290      if (! resin.isClosed())
1291    Runtime.getRuntime().halt(1);
1292
1293      System.exit(0);
1294    } catch (BindException JavaDoc e) {
1295      System.out.println(e);
1296
1297      log().log(Level.FINE, e.toString(), e);
1298
1299      System.exit(67);
1300    } catch (Throwable JavaDoc e) {
1301      boolean isCompile = false;
1302      Throwable JavaDoc cause;
1303
1304      for (cause = e; cause != null; cause = cause.getCause()) {
1305    if (cause instanceof CompileException) {
1306      System.err.println(cause.getMessage());
1307      isCompile = true;
1308      break;
1309    }
1310      }
1311
1312      if (! isCompile)
1313    e.printStackTrace(System.err);
1314      else
1315    log().log(Level.CONFIG, e.toString(), e);
1316    } finally {
1317      System.exit(1);
1318    }
1319  }
1320
1321  /**
1322   * Validates the environment.
1323   */

1324  private static void validateEnvironment()
1325    throws ConfigException
1326  {
1327    String JavaDoc loggingManager = System.getProperty("java.util.logging.manager");
1328
1329    if (loggingManager == null ||
1330    ! loggingManager.equals("com.caucho.log.LogManagerImpl")) {
1331      throw new ConfigException(L().l("The following system property must be set:\n -Djava.util.logging.manager=com.caucho.log.LogManagerImpl\nThe JDK 1.4 Logging manager must be set to Resin's log manager."));
1332    }
1333
1334    validatePackage("javax.servlet.Servlet", new String JavaDoc[] {"2.5", "1.5"});
1335    validatePackage("javax.servlet.jsp.jstl.core.Config", new String JavaDoc[] {"1.1"});
1336    validatePackage("javax.management.MBeanServer", new String JavaDoc[] { "1.2", "1.5" });
1337    validatePackage("javax.resource.spi.ResourceAdapter", new String JavaDoc[] {"1.5", "1.4"});
1338  }
1339
1340  /**
1341   * Validates a package version.
1342   */

1343  private static void validatePackage(String JavaDoc className, String JavaDoc []versions)
1344    throws ConfigException
1345  {
1346    Class JavaDoc cl = null;
1347
1348    try {
1349      cl = Class.forName(className);
1350    } catch (Throwable JavaDoc e) {
1351      throw new ConfigException(L().l("class {0} is not loadable on startup. Resin requires {0} to be in the classpath on startup.",
1352                    className));
1353
1354    }
1355
1356    Package JavaDoc pkg = cl.getPackage();
1357
1358    if (pkg == null) {
1359      log().warning(L().l("package for class {0} is missing. Resin requires class {0} in the classpath on startup.",
1360            className));
1361
1362      return;
1363    }
1364    else if (pkg.getSpecificationVersion() == null) {
1365      log().warning(L().l("{0} has no specification version. Resin {1} requires version {2}.",
1366                    pkg, com.caucho.Version.VERSION,
1367                    versions[0]));
1368
1369      return;
1370    }
1371
1372    for (int i = 0; i < versions.length; i++) {
1373      if (versions[i].compareTo(pkg.getSpecificationVersion()) <= 0)
1374    return;
1375    }
1376
1377    log().warning(L().l("Specification version {0} of {1} is not compatible with Resin {2}. Resin {2} requires version {3}.",
1378              pkg.getSpecificationVersion(),
1379              pkg, com.caucho.Version.VERSION,
1380              versions[0]));
1381  }
1382
1383  private static L10N L()
1384  {
1385    if (_L == null)
1386      _L = new L10N(Resin.class);
1387
1388    return _L;
1389  }
1390
1391  private static Logger JavaDoc log()
1392  {
1393    if (_log == null)
1394      _log = Logger.getLogger(Resin.class.getName());
1395
1396    return _log;
1397  }
1398
1399  static class BoundPort {
1400    private QServerSocket _ss;
1401    private String JavaDoc _address;
1402    private int _port;
1403
1404    BoundPort(QServerSocket ss, String JavaDoc address, int port)
1405    {
1406      if (ss == null)
1407    throw new NullPointerException JavaDoc();
1408
1409      _ss = ss;
1410      _address = address;
1411      _port = port;
1412    }
1413
1414    public QServerSocket getServerSocket()
1415    {
1416      return _ss;
1417    }
1418
1419    public int getPort()
1420    {
1421      return _port;
1422    }
1423
1424    public String JavaDoc getAddress()
1425    {
1426      return _address;
1427    }
1428  }
1429
1430  /**
1431   * EL variables
1432   */

1433  public class Var {
1434    /**
1435     * Returns the resin.id
1436     */

1437    public String JavaDoc getId()
1438    {
1439      return _serverId;
1440    }
1441
1442    /**
1443     * Returns the local address
1444     *
1445     * @return IP address
1446     */

1447    public String JavaDoc getAddress()
1448    {
1449      try {
1450    if (Alarm.isTest())
1451      return "127.0.0.1";
1452    else
1453      return InetAddress.getLocalHost().getHostAddress();
1454      } catch (Exception JavaDoc e) {
1455    log().log(Level.FINE, e.toString(), e);
1456
1457    return "localhost";
1458      }
1459    }
1460
1461    /**
1462     * Returns the resin config.
1463     */

1464    public Path getConf()
1465    {
1466      return getResinConf();
1467    }
1468
1469    /**
1470     * Returns the resin home.
1471     */

1472    public Path getHome()
1473    {
1474      return Resin.this.getResinHome();
1475    }
1476
1477    /**
1478     * Returns the root directory.
1479     *
1480     * @return the root directory
1481     */

1482    public Path getRoot()
1483    {
1484      return Resin.this.getRootDirectory();
1485    }
1486
1487    /**
1488     * Returns the version
1489     *
1490     * @return version
1491     */

1492    public String JavaDoc getVersion()
1493    {
1494      if (Alarm.isTest())
1495    return "3.1.test";
1496      else
1497    return com.caucho.Version.VERSION;
1498    }
1499
1500    /**
1501     * Returns the version
1502     *
1503     * @return version
1504     */

1505    public String JavaDoc getVersionDate()
1506    {
1507      if (Alarm.isTest())
1508    return "19980508T0251";
1509      else
1510    return com.caucho.Version.VERSION_DATE;
1511    }
1512
1513    /**
1514     * Returns the local hostname
1515     *
1516     * @return version
1517     */

1518    public String JavaDoc getHostName()
1519    {
1520      try {
1521    if (Alarm.isTest())
1522      return "localhost";
1523    else
1524      return InetAddress.getLocalHost().getHostName();
1525      } catch (Exception JavaDoc e) {
1526    log().log(Level.FINE, e.toString(), e);
1527
1528    return "localhost";
1529      }
1530    }
1531
1532    /**
1533     * Returns the root directory.
1534     *
1535     * @return resin.home
1536     */

1537    public Path getRootDir()
1538    {
1539      return getRoot();
1540    }
1541
1542    /**
1543     * Returns the root directory.
1544     *
1545     * @return resin.home
1546     */

1547    public Path getRootDirectory()
1548    {
1549      return getRoot();
1550    }
1551
1552    /**
1553     * Returns true for Resin professional.
1554     */

1555    public boolean isProfessional()
1556    {
1557      return _isResinProfessional;
1558    }
1559
1560    /**
1561     * Returns the -server id
1562     */

1563    public String JavaDoc getServerId()
1564    {
1565      return _serverId;
1566    }
1567  }
1568
1569  /**
1570   * Java variables
1571   */

1572  public class JavaVar {
1573    /**
1574     * Returns true for JDK 5
1575     */

1576    public boolean isJava5()
1577    {
1578      return true;
1579    }
1580    /**
1581     * Returns the JDK version
1582     */

1583    public String JavaDoc getVersion()
1584    {
1585      return System.getProperty("java.version");
1586    }
1587  }
1588
1589  class SecurityManagerConfig {
1590    private boolean _isEnable;
1591
1592    SecurityManagerConfig()
1593    {
1594      if (_securityManager == null)
1595        _securityManager = new SecurityManager JavaDoc();
1596    }
1597
1598    public void setEnable(boolean enable)
1599    {
1600      _isEnable = enable;
1601    }
1602
1603    public void setValue(boolean enable)
1604    {
1605      setEnable(enable);
1606    }
1607
1608    public void setPolicyFile(Path path)
1609      throws ConfigException
1610    {
1611      if (! path.canRead())
1612        throw new ConfigException(L().l("policy-file '{0}' must be readable.",
1613                                      path));
1614
1615    }
1616
1617    public void init()
1618    {
1619      if (_isEnable)
1620        System.setSecurityManager(_securityManager);
1621    }
1622  }
1623}
1624
Popular Tags