KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jk > server > JkMain


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.jk.server;
18
19 import java.io.File JavaDoc;
20 import java.io.FileInputStream JavaDoc;
21 import java.io.FileOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.PrintStream JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.Hashtable JavaDoc;
26 import java.util.Properties JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28 import java.util.Vector JavaDoc;
29
30 import javax.management.MBeanRegistration JavaDoc;
31 import javax.management.MBeanServer JavaDoc;
32 import javax.management.ObjectName JavaDoc;
33
34 import org.apache.commons.modeler.Registry;
35 import org.apache.jk.core.JkHandler;
36 import org.apache.jk.core.WorkerEnv;
37 import org.apache.tomcat.util.IntrospectionUtils;
38
39 /** Main class used to startup and configure jk. It manages the conf/jk2.properties file
40  * and is the target of JMX proxy.
41  *
42  * It implements a policy of save-on-change - whenever a property is changed at
43  * runtime the jk2.properties file will be overriden.
44  *
45  * You can edit the config file when tomcat is stoped ( or if you don't use JMX or
46  * other admin tools ).
47  *
48  * The format of jk2.properties:
49  * <dl>
50  * <dt>TYPE[.LOCALNAME].PROPERTY_NAME=VALUE
51  * <dd>Set a property on the associated component. TYPE will be used to
52  * find the class name and instantiate the component. LOCALNAME allows
53  * multiple instances. In JMX mode, TYPE and LOCALNAME will form the
54  * JMX name ( eventually combined with a 'jk2' component )
55  *
56  * <dt>NAME=VALUE
57  * <dd>Define global properties to be used in ${} substitutions
58  *
59  * <dt>class.COMPONENT_TYPE=JAVA_CLASS_NAME
60  * <dd>Adds a new 'type' of component. We predefine all known types.
61  * </dl>
62  *
63  * Instances are created the first time a component name is found. In addition,
64  * 'handler.list' property will override the list of 'default' components that are
65  * loaded automatically.
66  *
67  * Note that the properties file is just one (simplistic) way to configure jk. We hope
68  * to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better )
69  *
70  * @author Costin Manolache
71  */

72 public class JkMain implements MBeanRegistration JavaDoc
73 {
74     WorkerEnv wEnv;
75     String JavaDoc propFile;
76     Properties JavaDoc props=new Properties JavaDoc();
77
78     Properties JavaDoc modules=new Properties JavaDoc();
79     boolean modified=false;
80     boolean started=false;
81     boolean saveProperties=false;
82
83     public JkMain()
84     {
85         JkMain.jkMain=this;
86         modules.put("channelSocket", "org.apache.jk.common.ChannelSocket");
87         modules.put("channelUnix", "org.apache.jk.common.ChannelUn");
88         modules.put("channelJni", "org.apache.jk.common.ChannelJni");
89         modules.put("apr", "org.apache.jk.apr.AprImpl");
90         modules.put("mx", "org.apache.jk.common.JkMX");
91         modules.put("modeler", "org.apache.jk.common.JkModeler");
92         modules.put("shm", "org.apache.jk.common.Shm");
93         modules.put("request","org.apache.jk.common.HandlerRequest");
94         modules.put("container","org.apache.jk.common.HandlerRequest");
95         modules.put("modjk","org.apache.jk.common.ModJkMX");
96
97     }
98
99     public static JkMain getJkMain() {
100         return jkMain;
101     }
102
103     private static String JavaDoc DEFAULT_HTTPS="com.sun.net.ssl.internal.www.protocol";
104     private void initHTTPSUrls() {
105         try {
106             // 11657: if only ajp is used, https: redirects need to work ( at least for 1.3+)
107
String JavaDoc value = System.getProperty("java.protocol.handler.pkgs");
108             if (value == null) {
109                 value = DEFAULT_HTTPS;
110             } else if (value.indexOf(DEFAULT_HTTPS) >= 0 ) {
111                 return; // already set
112
} else {
113                 value += "|" + DEFAULT_HTTPS;
114             }
115             System.setProperty("java.protocol.handler.pkgs", value);
116         } catch(Exception JavaDoc ex ) {
117             log.info("Error adding SSL Protocol Handler",ex);
118         }
119     }
120
121     // -------------------- Setting --------------------
122

123     /** Load a .properties file into and set the values
124      * into jk2 configuration.
125      */

126     public void setPropertiesFile( String JavaDoc p ) {
127         propFile=p;
128         if( started ) {
129             loadPropertiesFile();
130         }
131     }
132
133     public String JavaDoc getPropertiesFile() {
134         return propFile;
135     }
136
137     public void setSaveProperties( boolean b ) {
138         saveProperties=b;
139     }
140
141     /** Set a name/value as a jk2 property
142      */

143     public void setProperty( String JavaDoc n, String JavaDoc v ) {
144         if( "jkHome".equals( n ) ) {
145             setJkHome( v );
146         }
147         if( "propertiesFile".equals( n ) ) {
148             setPropertiesFile( v );
149         }
150         props.put( n, v );
151         if( started ) {
152             processProperty( n, v );
153             saveProperties();
154         }
155     }
156     /**
157      * Retrieve a property.
158      */

159     public Object JavaDoc getProperty(String JavaDoc name) {
160         String JavaDoc alias = (String JavaDoc)replacements.get(name);
161         Object JavaDoc result = null;
162         if(alias != null) {
163             result = props.get(alias);
164         }
165         if(result == null) {
166             result = props.get(name);
167         }
168         return result;
169     }
170     /**
171      * Set the <code>channelClassName</code> that will used to connect to
172      * httpd.
173      */

174     public void setChannelClassName(String JavaDoc name) {
175         props.put( "handler.channel.className",name);
176     }
177
178     public String JavaDoc getChannelClassName() {
179         return (String JavaDoc)props.get( "handler.channel.className");
180     }
181
182     /**
183      * Set the <code>workerClassName</code> that will handle the request.
184      * ( sort of 'pivot' in axis :-)
185      */

186     public void setWorkerClassName(String JavaDoc name) {
187         props.put( "handler.container.className",name);
188     }
189
190     public String JavaDoc getWorkerClassName() {
191         return (String JavaDoc)props.get( "handler.container.className");
192     }
193
194     /** Set the base dir of jk2. ( including WEB-INF if in a webapp ).
195      * We'll try to guess it from classpath if none is set ( for
196      * example on command line ), but if in a servlet environment
197      * you need to use Context.getRealPath or a system property or
198      * set it expliciltey.
199      */

200     public void setJkHome( String JavaDoc s ) {
201         getWorkerEnv().setJkHome(s);
202     }
203
204     public String JavaDoc getJkHome() {
205         return getWorkerEnv().getJkHome();
206     }
207
208     String JavaDoc out;
209     String JavaDoc err;
210     File JavaDoc propsF;
211     
212     public void setOut( String JavaDoc s ) {
213         this.out=s;
214     }
215
216     public String JavaDoc getOut() {
217         return this.out;
218     }
219
220     public void setErr( String JavaDoc s ) {
221         this.err=s;
222     }
223     
224     public String JavaDoc getErr() {
225         return this.err;
226     }
227     
228     // -------------------- Initialization --------------------
229

230     public void init() throws IOException JavaDoc
231     {
232         long t1=System.currentTimeMillis();
233         if(null != out) {
234             PrintStream JavaDoc outS=new PrintStream JavaDoc(new FileOutputStream JavaDoc(out));
235             System.setOut(outS);
236         }
237         if(null != err) {
238             PrintStream JavaDoc errS=new PrintStream JavaDoc(new FileOutputStream JavaDoc(err));
239             System.setErr(errS);
240         }
241
242         String JavaDoc home=getWorkerEnv().getJkHome();
243         if( home==null ) {
244             // XXX use IntrospectionUtil to find myself
245
this.guessHome();
246         }
247         home=getWorkerEnv().getJkHome();
248         if( home==null ) {
249             log.info( "Can't find home, jk2.properties not loaded");
250         }
251         if(log.isDebugEnabled())
252             log.debug("Starting Jk2, base dir= " + home );
253         loadPropertiesFile();
254
255         String JavaDoc initHTTPS = (String JavaDoc)props.get("class.initHTTPS");
256         if("true".equalsIgnoreCase(initHTTPS)) {
257             initHTTPSUrls();
258         }
259
260         long t2=System.currentTimeMillis();
261         initTime=t2-t1;
262     }
263     
264     static String JavaDoc defaultHandlers[]= { "request",
265                                        "container",
266                                        "channelSocket"};
267     /*
268      static String defaultHandlers[]= { "apr",
269                                        "shm",
270                                        "request",
271                                        "container",
272                                        "channelSocket",
273                                        "channelJni",
274                                        "channelUnix"};
275     */

276     
277     public void stop()
278     {
279         for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
280             if( wEnv.getHandler(i) != null ) {
281                 try {
282                     wEnv.getHandler(i).destroy();
283                 } catch( IOException JavaDoc ex) {
284                     log.error("Error stoping " + wEnv.getHandler(i).getName(), ex);
285                 }
286             }
287         }
288
289         started=false;
290     }
291     
292     public void start() throws IOException JavaDoc
293     {
294         long t1=System.currentTimeMillis();
295         // We must have at least 3 handlers:
296
// channel is the 'transport'
297
// request is the request processor or 'global' chain
298
// container is the 'provider'
299
// Additional handlers may exist and be used internally
300
// or be chained to create one of the standard handlers
301

302         String JavaDoc handlers[]=defaultHandlers;
303         // backward compat
304
String JavaDoc workers=props.getProperty( "handler.list", null );
305         if( workers!=null ) {
306             handlers= split( workers, ",");
307         }
308
309         // Load additional component declarations
310
processModules();
311         
312         for( int i=0; i<handlers.length; i++ ) {
313             String JavaDoc name= handlers[i];
314             JkHandler w=getWorkerEnv().getHandler( name );
315             if( w==null ) {
316                 newHandler( name, "", name );
317             }
318         }
319
320         // Process properties - and add aditional handlers.
321
processProperties();
322
323         for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
324             if( wEnv.getHandler(i) != null ) {
325                 try {
326                     wEnv.getHandler(i).init();
327                 } catch( IOException JavaDoc ex) {
328                     if( "apr".equals(wEnv.getHandler(i).getName() )) {
329                         log.info( "APR not loaded, disabling jni components: " + ex.toString());
330                     } else {
331                         log.error( "error initializing " + wEnv.getHandler(i).getName(), ex );
332                     }
333                 }
334             }
335         }
336
337         started=true;
338         long t2=System.currentTimeMillis();
339         startTime=t2-t1;
340
341         this.saveProperties();
342         log.info("Jk running ID=" + wEnv.getLocalId() + " time=" + initTime + "/" + startTime +
343                  " config=" + propFile);
344     }
345
346     // -------------------- Usefull methods --------------------
347

348     public WorkerEnv getWorkerEnv() {
349         if( wEnv==null ) {
350             wEnv=new WorkerEnv();
351         }
352         return wEnv;
353     }
354
355     public void setWorkerEnv(WorkerEnv wEnv) {
356         this.wEnv = wEnv;
357     }
358
359     /* A bit of magic to support workers.properties without giving
360        up the clean get/set
361     */

362     public void setBeanProperty( Object JavaDoc target, String JavaDoc name, String JavaDoc val ) {
363         if( val!=null )
364             val=IntrospectionUtils.replaceProperties( val, props, null );
365         if( log.isDebugEnabled())
366             log.debug( "setProperty " + target + " " + name + "=" + val );
367         
368         IntrospectionUtils.setProperty( target, name, val );
369     }
370
371     /*
372      * Set a handler property
373      */

374     public void setPropertyString( String JavaDoc handlerN, String JavaDoc name, String JavaDoc val ) {
375         if( log.isDebugEnabled() )
376             log.debug( "setProperty " + handlerN + " " + name + "=" + val );
377         Object JavaDoc target=getWorkerEnv().getHandler( handlerN );
378
379         setBeanProperty( target, name, val );
380         if( started ) {
381             saveProperties();
382         }
383
384     }
385
386     /** The time it took to initialize jk ( ms)
387      */

388     public long getInitTime() {
389         return initTime;
390     }
391
392     /** The time it took to start jk ( ms )
393      */

394     public long getStartTime() {
395         return startTime;
396     }
397     
398     // -------------------- Main --------------------
399

400     long initTime;
401     long startTime;
402     static JkMain jkMain=null;
403
404     public static void main(String JavaDoc args[]) {
405         try {
406             if( args.length == 1 &&
407                 ( "-?".equals(args[0]) || "-h".equals( args[0])) ) {
408                 System.out.println("Usage: ");
409                 System.out.println(" JkMain [args]");
410                 System.out.println();
411                 System.out.println(" Each bean setter corresponds to an arg ( like -debug 10 )");
412                 System.out.println(" System properties:");
413                 System.out.println(" jk2.home Base dir of jk2");
414                 return;
415             }
416
417             jkMain=new JkMain();
418
419             IntrospectionUtils.processArgs( jkMain, args, new String JavaDoc[] {},
420                                             null, new Hashtable JavaDoc());
421
422             jkMain.init();
423             jkMain.start();
424         } catch( Exception JavaDoc ex ) {
425             log.warn("Error running",ex);
426         }
427     }
428
429     // -------------------- Private methods --------------------
430

431
432     private boolean checkPropertiesFile() {
433         if(propFile == null) {
434             return false;
435         }
436         propsF = new File JavaDoc(propFile);
437         if(!propsF.isAbsolute()) {
438             String JavaDoc home = getWorkerEnv().getJkHome();
439             if( home == null ) {
440                 return false;
441             }
442             propsF = new File JavaDoc(home, propFile);
443         }
444         return propsF.exists();
445     }
446             
447     private void loadPropertiesFile() {
448         if(!checkPropertiesFile()) {
449             return;
450         }
451
452         try {
453             props.load( new FileInputStream JavaDoc(propsF) );
454         } catch(IOException JavaDoc ex ){
455             log.warn("Unable to load properties from "+propsF,ex);
456         }
457     }
458
459     public void saveProperties() {
460         if( !saveProperties) return;
461         
462         if(propsF == null) {
463             log.warn("No properties file specified. Unable to save");
464             return;
465         }
466         // Temp - to check if it works
467
File JavaDoc outFile= new File JavaDoc(propsF.getParentFile(), propsF.getName()+".save");
468         log.debug("Saving properties " + outFile );
469         try {
470             props.store( new FileOutputStream JavaDoc(outFile), "AUTOMATICALLY GENERATED" );
471         } catch(IOException JavaDoc ex ){
472             log.warn("Unable to save to "+outFile,ex);
473         }
474     }
475
476     // translate top-level keys ( from coyote or generic ) into component keys
477
static Hashtable JavaDoc replacements=new Hashtable JavaDoc();
478     static {
479         replacements.put("port","channelSocket.port");
480         replacements.put("maxThreads", "channelSocket.maxThreads");
481         replacements.put("minSpareThreads", "channelSocket.minSpareThreads");
482         replacements.put("maxSpareThreads", "channelSocket.maxSpareThreads");
483         replacements.put("backlog", "channelSocket.backlog");
484         replacements.put("tcpNoDelay", "channelSocket.tcpNoDelay");
485         replacements.put("soTimeout", "channelSocket.soTimeout");
486         replacements.put("timeout", "channelSocket.timeout");
487         replacements.put("address", "channelSocket.address");
488         replacements.put("tomcatAuthentication", "request.tomcatAuthentication");
489     }
490
491     private void preProcessProperties() {
492         Enumeration JavaDoc keys=props.keys();
493         Vector JavaDoc v=new Vector JavaDoc();
494         
495         while( keys.hasMoreElements() ) {
496             String JavaDoc key=(String JavaDoc)keys.nextElement();
497             Object JavaDoc newName=replacements.get(key);
498             if( newName !=null ) {
499                 v.addElement(key);
500             }
501         }
502         keys=v.elements();
503         while( keys.hasMoreElements() ) {
504             String JavaDoc key=(String JavaDoc)keys.nextElement();
505             Object JavaDoc propValue=props.getProperty( key );
506             String JavaDoc replacement=(String JavaDoc)replacements.get(key);
507             props.put(replacement, propValue);
508             if( log.isDebugEnabled())
509                 log.debug("Substituting " + key + " " + replacement + " " +
510                     propValue);
511         }
512     }
513     
514     private void processProperties() {
515         preProcessProperties();
516         Enumeration JavaDoc keys=props.keys();
517
518         while( keys.hasMoreElements() ) {
519             String JavaDoc name=(String JavaDoc)keys.nextElement();
520             String JavaDoc propValue=props.getProperty( name );
521
522             processProperty( name, propValue );
523         }
524     }
525
526     private void processProperty(String JavaDoc name, String JavaDoc propValue) {
527         String JavaDoc type=name;
528         String JavaDoc fullName=name;
529         String JavaDoc localName="";
530         String JavaDoc propName="";
531         // ignore
532
if( name.startsWith("key.")) return;
533
534         int dot=name.indexOf(".");
535         int lastDot=name.lastIndexOf(".");
536         if( dot > 0 ) {
537             type=name.substring(0, dot );
538             if( dot != lastDot ) {
539                 localName=name.substring( dot + 1, lastDot );
540                 fullName=type + "." + localName;
541             } else {
542                 fullName=type;
543             }
544             propName=name.substring( lastDot+1);
545         } else {
546             return;
547         }
548         
549         if( log.isDebugEnabled() )
550             log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName );
551         if( "class".equals( type ) || "handler".equals( type ) ) {
552             return;
553         }
554         
555         JkHandler comp=getWorkerEnv().getHandler( fullName );
556         if( comp==null ) {
557             comp=newHandler( type, localName, fullName );
558         }
559         if( comp==null )
560             return;
561         
562         if( log.isDebugEnabled() )
563             log.debug("Setting " + propName + " on " + fullName + " " + comp);
564         this.setBeanProperty( comp, propName, propValue );
565     }
566
567     private JkHandler newHandler( String JavaDoc type, String JavaDoc localName, String JavaDoc fullName )
568     {
569         JkHandler handler;
570         String JavaDoc classN=modules.getProperty(type);
571         if( classN == null ) {
572             log.error("No class name for " + fullName + " " + type );
573             return null;
574         }
575         try {
576             Class JavaDoc channelclass = Class.forName(classN);
577             handler=(JkHandler)channelclass.newInstance();
578         } catch (Throwable JavaDoc ex) {
579             handler=null;
580             log.error( "Can't create " + fullName, ex );
581             return null;
582         }
583         if( this.domain != null ) {
584             try {
585                 ObjectName JavaDoc handlerOname = new ObjectName JavaDoc
586                     (this.domain + ":" + "type=JkHandler,name=" + fullName);
587                 Registry.getRegistry(null, null).registerComponent(handler, handlerOname, classN);
588             } catch (Exception JavaDoc e) {
589                 log.error( "Error registering " + fullName, e );
590             }
591
592         }
593         wEnv.addHandler( fullName, handler );
594         return handler;
595     }
596
597     private void processModules() {
598         Enumeration JavaDoc keys=props.keys();
599         int plen=6;
600         
601         while( keys.hasMoreElements() ) {
602             String JavaDoc k=(String JavaDoc)keys.nextElement();
603             if( ! k.startsWith( "class." ) )
604                 continue;
605
606             String JavaDoc name= k.substring( plen );
607             String JavaDoc propValue=props.getProperty( k );
608
609             if( log.isDebugEnabled()) log.debug("Register " + name + " " + propValue );
610             modules.put( name, propValue );
611         }
612     }
613
614     private String JavaDoc[] split(String JavaDoc s, String JavaDoc delim ) {
615          Vector JavaDoc v=new Vector JavaDoc();
616         StringTokenizer JavaDoc st=new StringTokenizer JavaDoc(s, delim );
617         while( st.hasMoreTokens() ) {
618             v.addElement( st.nextToken());
619         }
620         String JavaDoc res[]=new String JavaDoc[ v.size() ];
621         for( int i=0; i<res.length; i++ ) {
622             res[i]=(String JavaDoc)v.elementAt(i);
623         }
624         return res;
625     }
626
627     // guessing home
628
private static String JavaDoc CNAME="org/apache/jk/server/JkMain.class";
629
630     private void guessHome() {
631         String JavaDoc home= wEnv.getJkHome();
632         if( home != null )
633             return;
634         home=IntrospectionUtils.guessInstall( "jk2.home","jk2.home",
635                                               "tomcat-jk2.jar", CNAME );
636         if( home != null ) {
637             log.info("Guessed home " + home );
638             wEnv.setJkHome( home );
639         }
640     }
641
642     static org.apache.commons.logging.Log log=
643         org.apache.commons.logging.LogFactory.getLog( JkMain.class );
644
645     protected String JavaDoc domain;
646     protected ObjectName JavaDoc oname;
647     protected MBeanServer JavaDoc mserver;
648
649     public ObjectName JavaDoc getObjectName() {
650         return oname;
651     }
652
653     public String JavaDoc getDomain() {
654         return domain;
655     }
656
657     public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server,
658                                   ObjectName JavaDoc name) throws Exception JavaDoc {
659         oname=name;
660         mserver=server;
661         domain=name.getDomain();
662         return name;
663     }
664
665     public void postRegister(Boolean JavaDoc registrationDone) {
666     }
667
668     public void preDeregister() throws Exception JavaDoc {
669     }
670
671     public void postDeregister() {
672     }
673
674     public void pause() throws Exception JavaDoc {
675         for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
676             if( wEnv.getHandler(i) != null ) {
677                 wEnv.getHandler(i).pause();
678             }
679         }
680     }
681
682     public void resume() throws Exception JavaDoc {
683         for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
684             if( wEnv.getHandler(i) != null ) {
685                 wEnv.getHandler(i).resume();
686             }
687         }
688     }
689
690
691 }
692
Popular Tags