KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jk > config > ApacheConfig


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.config;
18
19 import java.io.File JavaDoc;
20 import java.io.FileWriter JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.PrintWriter JavaDoc;
23 import java.util.Date JavaDoc;
24 import java.util.Hashtable JavaDoc;
25
26 import org.apache.catalina.Context;
27 import org.apache.catalina.Host;
28
29 /* The idea is to keep all configuration in server.xml and
30    the normal apache config files. We don't want people to
31    touch apache ( or IIS, NES ) config files unless they
32    want to and know what they're doing ( better than we do :-).
33
34    One nice feature ( if someone sends it ) would be to
35    also edit httpd.conf to add the include.
36
37    We'll generate a number of configuration files - this one
38    is trying to generate a native apache config file.
39
40    Some web.xml mappings do not "map" to server configuration - in
41    this case we need to fallback to forward all requests to tomcat.
42
43    Ajp14 will add to that the posibility to have tomcat and
44    apache on different machines, and many other improvements -
45    but this should also work for Ajp12, Ajp13 and Jni.
46
47 */

48
49 /**
50     Generates automatic apache mod_jk configurations based on
51     the Tomcat server.xml settings and the war contexts
52     initialized during startup.
53     <p>
54     This config interceptor is enabled by inserting an ApacheConfig
55     <code>Listener</code> in
56     the server.xml file like so:
57     <pre>
58     * < Server ... >
59     * ...
60     * <Listener className=<b>org.apache.ajp.tomcat4.config.ApacheConfig</b>
61     * <i>options</i> />
62     * ...
63     * < /Server >
64     </pre>
65     where <i>options</i> can include any of the following attributes:
66     <ul>
67      <li><b>configHome</b> - default parent directory for the following paths.
68                             If not set, this defaults to TOMCAT_HOME. Ignored
69                             whenever any of the following paths is absolute.
70                              </li>
71      <li><b>jkConfig</b> - path to use for writing Apache mod_jk conf file. If
72                             not set, defaults to
73                             "conf/auto/mod_jk.conf".</li>
74      <li><b>workersConfig</b> - path to workers.properties file used by
75                             mod_jk. If not set, defaults to
76                             "conf/jk/workers.properties".</li>
77      <li><b>modJk</b> - path to Apache mod_jk plugin file. If not set,
78                         defaults to "modules/mod_jk.dll" on windows,
79                         "modules/mod_jk.nlm" on netware, and
80                         "libexec/mod_jk.so" everywhere else.</li>
81      <li><b>jkLog</b> - path to log file to be used by mod_jk.</li>
82      <li><b>jkDebug</b> - JK Loglevel setting. May be debug, info, error, or emerg.
83                           If not set, defaults to emerg.</li>
84      <li><b>jkWorker</b> The desired worker. Must be set to one of the workers
85                          defined in the workers.properties file. "ajp12", "ajp13"
86                          or "inprocess" are the workers found in the default
87                          workers.properties file. If not specified, defaults
88                          to "ajp13" if an Ajp13Interceptor is in use, otherwise
89                          it defaults to "ajp12".</li>
90      <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
91                              insure that all the behavior configured in the web.xml
92                              file functions correctly. If false, let Apache serve
93                              static resources. The default is true.
94                              Warning: When false, some configuration in
95                              the web.xml may not be duplicated in Apache.
96                              Review the mod_jk conf file to see what
97                              configuration is actually being set in Apache.</li>
98      <li><b>noRoot</b> - If true, the root context is not mapped to
99                          Tomcat. If false and forwardAll is true, all requests
100                          to the root context are mapped to Tomcat. If false and
101                          forwardAll is false, only JSP and servlets requests to
102                          the root context are mapped to Tomcat. When false,
103                          to correctly serve Tomcat's root context you must also
104                          modify the DocumentRoot setting in Apache's httpd.conf
105                          file to point to Tomcat's root context directory.
106                          Otherwise some content, such as Apache's index.html,
107                          will be served by Apache before mod_jk gets a chance
108                          to claim the request and pass it to Tomcat.
109                          The default is true.</li>
110     </ul>
111     <p>
112     @author Costin Manolache
113     @author Larry Isaacs
114     @author Mel Martinez
115     @author Bill Barker
116  */

117 public class ApacheConfig extends BaseJkConfig {
118
119     private static org.apache.commons.logging.Log log =
120         org.apache.commons.logging.LogFactory.getLog(ApacheConfig.class);
121
122     /** default path to mod_jk .conf location */
123     public static final String JavaDoc MOD_JK_CONFIG = "conf/auto/mod_jk.conf";
124     /** default path to workers.properties file
125     This should be also auto-generated from server.xml.
126     */

127     public static final String JavaDoc WORKERS_CONFIG = "conf/jk/workers.properties";
128     /** default mod_jk log file location */
129     public static final String JavaDoc JK_LOG_LOCATION = "logs/mod_jk.log";
130     /** default location of mod_jk Apache plug-in. */
131     public static final String JavaDoc MOD_JK;
132     
133     //set up some defaults based on OS type
134
static{
135         String JavaDoc os = System.getProperty("os.name").toLowerCase();
136         if(os.indexOf("windows")>=0){
137            MOD_JK = "modules/mod_jk.dll";
138         }else if(os.indexOf("netware")>=0){
139            MOD_JK = "modules/mod_jk.nlm";
140         }else{
141            MOD_JK = "libexec/mod_jk.so";
142         }
143     }
144     
145     private File JavaDoc jkConfig = null;
146     private File JavaDoc modJk = null;
147
148     // ssl settings
149
private boolean sslExtract=true;
150     private String JavaDoc sslHttpsIndicator="HTTPS";
151     private String JavaDoc sslSessionIndicator="SSL_SESSION_ID";
152     private String JavaDoc sslCipherIndicator="SSL_CIPHER";
153     private String JavaDoc sslCertsIndicator="SSL_CLIENT_CERT";
154
155     Hashtable JavaDoc NamedVirtualHosts=null;
156     
157     public ApacheConfig() {
158     }
159
160     //-------------------- Properties --------------------
161

162     /**
163         set the path to the output file for the auto-generated
164         mod_jk configuration file. If this path is relative
165         then it will be resolved absolutely against
166         the getConfigHome() path.
167         <p>
168         @param path String path to a file
169     */

170     public void setJkConfig(String JavaDoc path){
171     jkConfig= (path==null)?null:new File JavaDoc(path);
172     }
173
174     /**
175         set the path to the mod_jk Apache Module
176         @param path String path to a file
177     */

178     public void setModJk(String JavaDoc path){
179         modJk=( path==null?null:new File JavaDoc(path));
180     }
181
182     /** By default mod_jk is configured to collect SSL information from
183     the apache environment and send it to the Tomcat workers. The
184     problem is that there are many SSL solutions for Apache and as
185     a result the environment variable names may change.
186
187     The following JK related SSL configureation
188     can be used to customize mod_jk's SSL behaviour.
189
190     Should mod_jk send SSL information to Tomact (default is On)
191     */

192     public void setExtractSSL( boolean sslMode ) {
193     this.sslExtract=sslMode;
194     }
195
196     /** What is the indicator for SSL (default is HTTPS)
197      */

198     public void setHttpsIndicator( String JavaDoc s ) {
199     sslHttpsIndicator=s;
200     }
201
202     /**What is the indicator for SSL session (default is SSL_SESSION_ID)
203      */

204     public void setSessionIndicator( String JavaDoc s ) {
205     sslSessionIndicator=s;
206     }
207     
208     /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
209      */

210     public void setCipherIndicator( String JavaDoc s ) {
211     sslCipherIndicator=s;
212     }
213
214     /** What is the indicator for the client SSL certificated(default
215     is SSL_CLIENT_CERT
216      */

217     public void setCertsIndicator( String JavaDoc s ) {
218     sslCertsIndicator=s;
219     }
220
221     // -------------------- Initialize/guess defaults --------------------
222

223     /** Initialize defaults for properties that are not set
224     explicitely
225     */

226     protected void initProperties() {
227         super.initProperties();
228
229     jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG);
230     workersConfig=getConfigFile( workersConfig, configHome,
231                      WORKERS_CONFIG);
232     if( modJk == null )
233         modJk=new File JavaDoc(MOD_JK);
234     else
235         modJk=getConfigFile( modJk, configHome, MOD_JK );
236     jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION);
237     }
238     // -------------------- Generate config --------------------
239

240     protected PrintWriter JavaDoc getWriter() throws IOException JavaDoc {
241     String JavaDoc abJkConfig = jkConfig.getAbsolutePath();
242     return new PrintWriter JavaDoc(new FileWriter JavaDoc(abJkConfig, append));
243     }
244                    
245
246     // -------------------- Config sections --------------------
247

248     /** Generate the loadModule and general options
249      */

250     protected boolean generateJkHead(PrintWriter JavaDoc mod_jk)
251     {
252
253     mod_jk.println("########## Auto generated on " + new Date JavaDoc() +
254                "##########" );
255     mod_jk.println();
256
257     // Fail if mod_jk not found, let the user know the problem
258
// instead of running into problems later.
259
if( ! modJk.exists() ) {
260         log.info( "mod_jk location: " + modJk );
261         log.info( "Make sure it is installed corectly or " +
262          " set the config location" );
263         log.info( "Using <Listener className=\""+getClass().getName()+"\" modJk=\"PATH_TO_MOD_JK.SO_OR_DLL\" />" );
264     }
265             
266     // Verify the file exists !!
267
mod_jk.println("<IfModule !mod_jk.c>");
268     mod_jk.println(" LoadModule jk_module \""+
269                modJk.toString().replace('\\','/') +
270                        "\"");
271     mod_jk.println("</IfModule>");
272     mod_jk.println();
273
274     
275     // Fail if workers file not found, let the user know the problem
276
// instead of running into problems later.
277
if( ! workersConfig.exists() ) {
278         log.warn( "Can't find workers.properties at " + workersConfig );
279         log.warn( "Please install it in the default location or " +
280          " set the config location" );
281         log.warn( "Using <Listener className=\"" + getClass().getName() + "\" workersConfig=\"FULL_PATH\" />" );
282         return false;
283     }
284             
285     mod_jk.println("JkWorkersFile \""
286                + workersConfig.toString().replace('\\', '/')
287                + "\"");
288
289     mod_jk.println("JkLogFile \""
290                + jkLog.toString().replace('\\', '/')
291                + "\"");
292     mod_jk.println();
293
294     if( jkDebug != null ) {
295         mod_jk.println("JkLogLevel " + jkDebug);
296         mod_jk.println();
297     }
298     return true;
299     }
300
301     protected void generateVhostHead(Host host, PrintWriter JavaDoc mod_jk) {
302
303         mod_jk.println();
304         String JavaDoc vhostip = host.getName();
305     String JavaDoc vhost = vhostip;
306     int ppos = vhost.indexOf(":");
307     if(ppos >= 0)
308         vhost = vhost.substring(0,ppos);
309
310         mod_jk.println("<VirtualHost "+ vhostip + ">");
311         mod_jk.println(" ServerName " + vhost );
312         String JavaDoc [] aliases=host.findAliases();
313         if( aliases.length > 0 ) {
314             mod_jk.print(" ServerAlias " );
315             for( int ii=0; ii < aliases.length ; ii++) {
316                 mod_jk.print( aliases[ii] + " " );
317             }
318             mod_jk.println();
319         }
320         indent=" ";
321     }
322
323     protected void generateVhostTail(Host host, PrintWriter JavaDoc mod_jk) {
324         mod_jk.println("</VirtualHost>");
325         indent="";
326     }
327     
328     protected void generateSSLConfig(PrintWriter JavaDoc mod_jk) {
329     if( ! sslExtract ) {
330         mod_jk.println("JkExtractSSL Off");
331     }
332     if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) {
333         mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator);
334     }
335     if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) {
336         mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator);
337     }
338     if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) {
339         mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator);
340     }
341     if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) {
342         mod_jk.println("JkCERTSIndicator " + sslCertsIndicator);
343     }
344
345     mod_jk.println();
346     }
347
348     // -------------------- Forward all mode --------------------
349
String JavaDoc indent="";
350     
351     /** Forward all requests for a context to tomcat.
352     The default.
353      */

354     protected void generateStupidMappings(Context context,
355                        PrintWriter JavaDoc mod_jk )
356     {
357     String JavaDoc ctxPath = context.getPath();
358     if(ctxPath == null)
359         return;
360
361     String JavaDoc nPath=("".equals(ctxPath)) ? "/" : ctxPath;
362     
363         mod_jk.println();
364     mod_jk.println(indent + "JkMount " + nPath + " " + jkWorker );
365     if( "".equals(ctxPath) ) {
366         mod_jk.println(indent + "JkMount " + nPath + "* " + jkWorker );
367             if ( context.getParent() instanceof Host ) {
368                 mod_jk.println(indent + "DocumentRoot \"" +
369                             getApacheDocBase(context) + "\"");
370             } else {
371                 mod_jk.println(indent +
372                         "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot");
373                 mod_jk.println(indent +
374                         "# to point to: \"" + getApacheDocBase(context) + "\"");
375             }
376
377     } else {
378         mod_jk.println(indent + "JkMount " + nPath + "/* " + jkWorker );
379     }
380     }
381
382     
383     private void generateNameVirtualHost( PrintWriter JavaDoc mod_jk, String JavaDoc ip ) {
384         if( !NamedVirtualHosts.containsKey(ip) ) {
385             mod_jk.println("NameVirtualHost " + ip + "");
386             NamedVirtualHosts.put(ip,ip);
387         }
388     }
389     
390     // -------------------- Apache serves static mode --------------------
391
// This is not going to work for all apps. We fall back to stupid mode.
392

393     protected void generateContextMappings(Context context, PrintWriter JavaDoc mod_jk )
394     {
395     String JavaDoc ctxPath = context.getPath();
396     Host vhost = getHost(context);
397
398         if( noRoot && "".equals(ctxPath) ) {
399             log.debug("Ignoring root context in non-forward-all mode ");
400             return;
401         }
402
403     mod_jk.println();
404     mod_jk.println(indent + "#################### " +
405                ((vhost!=null ) ? vhost.getName() + ":" : "" ) +
406                (("".equals(ctxPath)) ? "/" : ctxPath ) +
407                " ####################" );
408         mod_jk.println();
409     // Dynamic /servet pages go to Tomcat
410

411     generateStaticMappings( context, mod_jk );
412
413     // InvokerInterceptor - it doesn't have a container,
414
// but it's implemented using a special module.
415

416     // XXX we need to better collect all mappings
417

418     if(context.getLoginConfig() != null) {
419         String JavaDoc loginPage = context.getLoginConfig().getLoginPage();
420         if(loginPage != null) {
421         int lpos = loginPage.lastIndexOf("/");
422         String JavaDoc jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
423         addMapping( ctxPath, jscurl, mod_jk);
424         }
425     }
426     String JavaDoc [] servletMaps = context.findServletMappings();
427     for(int ii=0; ii < servletMaps.length; ii++) {
428           addMapping( ctxPath, servletMaps[ii] , mod_jk );
429     }
430     }
431
432     /** Add an Apache extension mapping.
433      */

434     protected boolean addExtensionMapping( String JavaDoc ctxPath, String JavaDoc ext,
435                      PrintWriter JavaDoc mod_jk )
436     {
437         if( log.isDebugEnabled() )
438             log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
439     mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext
440                + " " + jkWorker);
441     return true;
442     }
443     
444     
445     /** Add a fulling specified Appache mapping.
446      */

447     protected boolean addMapping( String JavaDoc fullPath, PrintWriter JavaDoc mod_jk ) {
448         if( log.isDebugEnabled() )
449             log.debug( "Adding map for " + fullPath );
450     mod_jk.println(indent + "JkMount " + fullPath + " " + jkWorker );
451     return true;
452     }
453     /** Add a partially specified Appache mapping.
454      */

455     protected boolean addMapping( String JavaDoc ctxP, String JavaDoc ext, PrintWriter JavaDoc mod_jk ) {
456         if( log.isDebugEnabled() )
457             log.debug( "Adding map for " + ext );
458     if(! ext.startsWith("/") )
459         ext = "/" + ext;
460     if(ext.length() > 1)
461         mod_jk.println(indent + "JkMount " + ctxP + ext+ " " + jkWorker );
462     return true;
463     }
464
465     private void generateWelcomeFiles(Context context, PrintWriter JavaDoc mod_jk ) {
466     String JavaDoc wf[]=context.findWelcomeFiles();
467     if( wf==null || wf.length == 0 )
468         return;
469     mod_jk.print(indent + " DirectoryIndex ");
470     for( int i=0; i<wf.length ; i++ ) {
471         mod_jk.print( wf[i] + " " );
472     }
473     mod_jk.println();
474     }
475
476     /** Mappings for static content. XXX need to add welcome files,
477      * mime mappings ( all will be handled by Mime and Static modules of
478      * apache ).
479      */

480     private void generateStaticMappings(Context context, PrintWriter JavaDoc mod_jk ) {
481     String JavaDoc ctxPath = context.getPath();
482
483     // Calculate the absolute path of the document base
484
String JavaDoc docBase = getApacheDocBase(context);
485
486         if( !"".equals(ctxPath) ) {
487             // Static files will be served by Apache
488
mod_jk.println(indent + "# Static files ");
489             mod_jk.println(indent + "Alias " + ctxPath + " \"" + docBase + "\"");
490             mod_jk.println();
491         } else {
492             if ( getHost(context) != null ) {
493                 mod_jk.println(indent + "DocumentRoot \"" +
494                             getApacheDocBase(context) + "\"");
495             } else {
496                 // For root context, ask user to update DocumentRoot setting.
497
// Using "Alias / " interferes with the Alias for other contexts.
498
mod_jk.println(indent +
499                         "# Be sure to update DocumentRoot");
500                 mod_jk.println(indent +
501                         "# to point to: \"" + docBase + "\"");
502             }
503         }
504     mod_jk.println(indent + "<Directory \"" + docBase + "\">");
505     mod_jk.println(indent + " Options Indexes FollowSymLinks");
506
507     generateWelcomeFiles(context, mod_jk);
508
509     // XXX XXX Here goes the Mime types and welcome files !!!!!!!!
510
mod_jk.println(indent + "</Directory>");
511     mod_jk.println();
512     
513
514     // Deny serving any files from WEB-INF
515
mod_jk.println();
516     mod_jk.println(indent +
517                "# Deny direct access to WEB-INF and META-INF");
518     mod_jk.println(indent + "#");
519     mod_jk.println(indent + "<Location \"" + ctxPath + "/WEB-INF/*\">");
520     mod_jk.println(indent + " AllowOverride None");
521     mod_jk.println(indent + " deny from all");
522     mod_jk.println(indent + "</Location>");
523     // Deny serving any files from META-INF
524
mod_jk.println();
525     mod_jk.println(indent + "<Location \"" + ctxPath + "/META-INF/*\">");
526     mod_jk.println(indent + " AllowOverride None");
527     mod_jk.println(indent + " deny from all");
528     mod_jk.println(indent + "</Location>");
529     if (File.separatorChar == '\\') {
530         mod_jk.println(indent + "#");
531         mod_jk.println(indent +
532                "# Use Directory too. On Windows, Location doesn't"
533                + " work unless case matches");
534         mod_jk.println(indent + "#");
535         mod_jk.println(indent +
536                "<Directory \"" + docBase + "/WEB-INF/\">");
537         mod_jk.println(indent + " AllowOverride None");
538         mod_jk.println(indent + " deny from all");
539         mod_jk.println(indent + "</Directory>");
540         mod_jk.println();
541         mod_jk.println(indent +
542                "<Directory \"" + docBase + "/META-INF/\">");
543         mod_jk.println(indent + " AllowOverride None");
544         mod_jk.println(indent + " deny from all");
545         mod_jk.println(indent + "</Directory>");
546     }
547     mod_jk.println();
548     }
549
550     // -------------------- Utils --------------------
551

552     private String JavaDoc getApacheDocBase(Context context)
553     {
554     // Calculate the absolute path of the document base
555
String JavaDoc docBase = getAbsoluteDocBase(context);
556     if (File.separatorChar == '\\') {
557         // use separator preferred by Apache
558
docBase = docBase.replace('\\','/');
559     }
560         return docBase;
561     }
562
563     private String JavaDoc getVirtualHostAddress(String JavaDoc vhost, String JavaDoc vhostip) {
564         if( vhostip == null ) {
565             if ( vhost != null && vhost.length() > 0 && Character.isDigit(vhost.charAt(0)) )
566                 vhostip=vhost;
567             else
568                 vhostip="*";
569         }
570         return vhostip;
571     }
572
573 }
574
Popular Tags