Save This Page
Home » apache-tomcat-6.0.16-src » org.apache.jk » config » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.jk.config;
   19   
   20   import java.io.File;
   21   import java.io.FileWriter;
   22   import java.io.IOException;
   23   import java.io.PrintWriter;
   24   import java.util.Date;
   25   import java.util.Hashtable;
   26   
   27   import org.apache.catalina.Context;
   28   import org.apache.catalina.Host;
   29   
   30   /* The idea is to keep all configuration in server.xml and
   31      the normal apache config files. We don't want people to
   32      touch apache ( or IIS, NES ) config files unless they
   33      want to and know what they're doing ( better than we do :-).
   34   
   35      One nice feature ( if someone sends it ) would be to
   36      also edit httpd.conf to add the include.
   37   
   38      We'll generate a number of configuration files - this one
   39      is trying to generate a native apache config file.
   40   
   41      Some web.xml mappings do not "map" to server configuration - in
   42      this case we need to fallback to forward all requests to tomcat.
   43   
   44      Ajp14 will add to that the posibility to have tomcat and
   45      apache on different machines, and many other improvements -
   46      but this should also work for Ajp12, Ajp13 and Jni.
   47   
   48   */
   49   
   50   /**
   51       Generates automatic apache mod_jk configurations based on
   52       the Tomcat server.xml settings and the war contexts
   53       initialized during startup.
   54       <p>
   55       This config interceptor is enabled by inserting an ApacheConfig
   56       <code>Listener</code> in 
   57       the server.xml file like so:
   58       <pre>
   59       * < Server ... >
   60       *   ...
   61       *   <Listener className=<b>org.apache.ajp.tomcat4.config.ApacheConfig</b> 
   62       *       <i>options</i> />
   63       *   ...
   64       * < /Server >
   65       </pre>
   66       where <i>options</i> can include any of the following attributes:
   67       <ul>
   68        <li><b>configHome</b> - default parent directory for the following paths.
   69                               If not set, this defaults to TOMCAT_HOME. Ignored
   70                               whenever any of the following paths is absolute.
   71                                </li>
   72        <li><b>jkConfig</b> - path to use for writing Apache mod_jk conf file. If
   73                               not set, defaults to
   74                               "conf/auto/mod_jk.conf".</li>
   75        <li><b>workersConfig</b> - path to workers.properties file used by 
   76                               mod_jk. If not set, defaults to
   77                               "conf/jk/workers.properties".</li>
   78        <li><b>modJk</b> - path to Apache mod_jk plugin file.  If not set,
   79                           defaults to "modules/mod_jk.dll" on windows,
   80                           "modules/mod_jk.nlm" on netware, and
   81                           "libexec/mod_jk.so" everywhere else.</li>
   82        <li><b>jkLog</b> - path to log file to be used by mod_jk.</li>
   83        <li><b>jkDebug</b> - JK Loglevel setting.  May be debug, info, error, or emerg.
   84                             If not set, defaults to emerg.</li>
   85        <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
   86                            defined in the workers.properties file. "ajp12", "ajp13"
   87                            or "inprocess" are the workers found in the default
   88                            workers.properties file. If not specified, defaults
   89                            to "ajp13" if an Ajp13Interceptor is in use, otherwise
   90                            it defaults to "ajp12".</li>
   91        <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
   92                                insure that all the behavior configured in the web.xml
   93                                file functions correctly.  If false, let Apache serve
   94                                static resources. The default is true.
   95                                Warning: When false, some configuration in
   96                                the web.xml may not be duplicated in Apache.
   97                                Review the mod_jk conf file to see what
   98                                configuration is actually being set in Apache.</li>
   99        <li><b>noRoot</b> - If true, the root context is not mapped to
  100                            Tomcat.  If false and forwardAll is true, all requests
  101                            to the root context are mapped to Tomcat. If false and
  102                            forwardAll is false, only JSP and servlets requests to
  103                            the root context are mapped to Tomcat. When false,
  104                            to correctly serve Tomcat's root context you must also
  105                            modify the DocumentRoot setting in Apache's httpd.conf
  106                            file to point to Tomcat's root context directory.
  107                            Otherwise some content, such as Apache's index.html,
  108                            will be served by Apache before mod_jk gets a chance
  109                            to claim the request and pass it to Tomcat.
  110                            The default is true.</li>
  111       </ul>
  112       <p>
  113       @author Costin Manolache
  114       @author Larry Isaacs
  115       @author Mel Martinez
  116       @author Bill Barker
  117    */
  118   public class ApacheConfig  extends BaseJkConfig { 
  119   
  120       private static org.apache.juli.logging.Log log =
  121           org.apache.juli.logging.LogFactory.getLog(ApacheConfig.class);
  122   
  123       /** default path to mod_jk .conf location */
  124       public static final String MOD_JK_CONFIG = "conf/auto/mod_jk.conf";
  125       /** default path to workers.properties file
  126   	This should be also auto-generated from server.xml.
  127       */
  128       public static final String WORKERS_CONFIG = "conf/jk/workers.properties";
  129       /** default mod_jk log file location */
  130       public static final String JK_LOG_LOCATION = "logs/mod_jk.log";
  131       /** default location of mod_jk Apache plug-in. */
  132       public static final String MOD_JK;
  133       
  134       //set up some defaults based on OS type
  135       static{
  136           String os = System.getProperty("os.name").toLowerCase();
  137           if(os.indexOf("windows")>=0){ 
  138              MOD_JK = "modules/mod_jk.dll";
  139           }else if(os.indexOf("netware")>=0){
  140              MOD_JK = "modules/mod_jk.nlm";
  141           }else{
  142              MOD_JK = "libexec/mod_jk.so";
  143           }
  144       }
  145       
  146       private File jkConfig = null;
  147       private File modJk = null;
  148   
  149       // ssl settings 
  150       private boolean sslExtract=true;
  151       private String sslHttpsIndicator="HTTPS";
  152       private String sslSessionIndicator="SSL_SESSION_ID";
  153       private String sslCipherIndicator="SSL_CIPHER";
  154       private String sslCertsIndicator="SSL_CLIENT_CERT";
  155   
  156       Hashtable NamedVirtualHosts=null;
  157       
  158       public ApacheConfig() {
  159       }
  160   
  161       //-------------------- Properties --------------------
  162   
  163       /**
  164           set the path to the output file for the auto-generated
  165           mod_jk configuration file.  If this path is relative
  166           then it will be resolved absolutely against
  167           the getConfigHome() path.
  168           <p>
  169           @param path String path to a file
  170       */
  171       public void setJkConfig(String path){
  172   	jkConfig= (path==null)?null:new File(path);
  173       }
  174   
  175       /**
  176           set the path to the mod_jk Apache Module
  177           @param path String path to a file
  178       */
  179       public void setModJk(String path){
  180           modJk=( path==null?null:new File(path));
  181       }
  182   
  183       /** By default mod_jk is configured to collect SSL information from
  184   	the apache environment and send it to the Tomcat workers. The
  185   	problem is that there are many SSL solutions for Apache and as
  186   	a result the environment variable names may change.
  187   
  188   	The following JK related SSL configureation
  189   	can be used to customize mod_jk's SSL behaviour.
  190   
  191   	Should mod_jk send SSL information to Tomact (default is On)
  192       */
  193       public void setExtractSSL( boolean sslMode ) {
  194   	this.sslExtract=sslMode;
  195       }
  196   
  197       /** What is the indicator for SSL (default is HTTPS)
  198        */
  199       public void setHttpsIndicator( String s ) {
  200   	sslHttpsIndicator=s;
  201       }
  202   
  203       /**What is the indicator for SSL session (default is SSL_SESSION_ID)
  204        */
  205       public void setSessionIndicator( String s ) {
  206   	sslSessionIndicator=s;
  207       }
  208       
  209       /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
  210        */
  211       public void setCipherIndicator( String s ) {
  212   	sslCipherIndicator=s;
  213       }
  214   
  215       /** What is the indicator for the client SSL certificated(default
  216   	is SSL_CLIENT_CERT
  217        */
  218       public void setCertsIndicator( String s ) {
  219   	sslCertsIndicator=s;
  220       }
  221   
  222       // -------------------- Initialize/guess defaults --------------------
  223   
  224       /** Initialize defaults for properties that are not set
  225   	explicitely
  226       */
  227       protected void initProperties() {
  228           super.initProperties();
  229   
  230   	jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG);
  231   	workersConfig=getConfigFile( workersConfig, configHome,
  232   				     WORKERS_CONFIG);
  233   	if( modJk == null )
  234   	    modJk=new File(MOD_JK);
  235   	else
  236   	    modJk=getConfigFile( modJk, configHome, MOD_JK );
  237   	jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION);
  238       }
  239       // -------------------- Generate config --------------------
  240       
  241       protected PrintWriter getWriter() throws IOException {
  242   	String abJkConfig = jkConfig.getAbsolutePath();
  243   	return new PrintWriter(new FileWriter(abJkConfig, append));
  244       }
  245   			       
  246   
  247       // -------------------- Config sections  --------------------
  248   
  249       /** Generate the loadModule and general options
  250        */
  251       protected boolean generateJkHead(PrintWriter mod_jk)
  252       {
  253   
  254   	mod_jk.println("########## Auto generated on " +  new Date() +
  255   		       "##########" );
  256   	mod_jk.println();
  257   
  258   	// Fail if mod_jk not found, let the user know the problem
  259   	// instead of running into problems later.
  260   	if( ! modJk.exists() ) {
  261   	    log.info( "mod_jk location: " + modJk );
  262   	    log.info( "Make sure it is installed corectly or " +
  263   		 " set the config location" );
  264   	    log.info( "Using <Listener className=\""+getClass().getName()+"\"  modJk=\"PATH_TO_MOD_JK.SO_OR_DLL\" />" );
  265   	}
  266               
  267   	// Verify the file exists !!
  268   	mod_jk.println("<IfModule !mod_jk.c>");
  269   	mod_jk.println("  LoadModule jk_module \""+
  270   		       modJk.toString().replace('\\','/') +
  271                          "\"");
  272   	mod_jk.println("</IfModule>");
  273   	mod_jk.println();                
  274   
  275   	
  276   	// Fail if workers file not found, let the user know the problem
  277   	// instead of running into problems later.
  278   	if( ! workersConfig.exists() ) {
  279   	    log.warn( "Can't find workers.properties at " + workersConfig );
  280   	    log.warn( "Please install it in the default location or " +
  281   		 " set the config location" );
  282   	    log.warn( "Using <Listener className=\"" + getClass().getName() + "\"  workersConfig=\"FULL_PATH\" />" );
  283   	    return false;
  284   	}
  285               
  286   	mod_jk.println("JkWorkersFile \"" 
  287   		       + workersConfig.toString().replace('\\', '/') 
  288   		       + "\"");
  289   
  290   	mod_jk.println("JkLogFile \"" 
  291   		       + jkLog.toString().replace('\\', '/') 
  292   		       + "\"");
  293   	mod_jk.println();
  294   
  295   	if( jkDebug != null ) {
  296   	    mod_jk.println("JkLogLevel " + jkDebug);
  297   	    mod_jk.println();
  298   	}
  299   	return true;
  300       }
  301   
  302       protected void generateVhostHead(Host host, PrintWriter mod_jk) {
  303   
  304           mod_jk.println();
  305           String vhostip = host.getName();
  306   	String vhost = vhostip;
  307   	int ppos = vhost.indexOf(":");
  308   	if(ppos >= 0)
  309   	    vhost = vhost.substring(0,ppos);
  310   
  311           mod_jk.println("<VirtualHost "+ vhostip + ">");
  312           mod_jk.println("    ServerName " + vhost );
  313           String [] aliases=host.findAliases();
  314           if( aliases.length > 0 ) {
  315               mod_jk.print("    ServerAlias " );
  316               for( int ii=0; ii < aliases.length ; ii++) {
  317                   mod_jk.print( aliases[ii] + " " );
  318               }
  319               mod_jk.println();
  320           }
  321           indent="    ";
  322       }
  323   
  324       protected void generateVhostTail(Host host, PrintWriter mod_jk) {
  325           mod_jk.println("</VirtualHost>");
  326           indent="";
  327       }
  328       
  329       protected void generateSSLConfig(PrintWriter mod_jk) {
  330   	if( ! sslExtract ) {
  331   	    mod_jk.println("JkExtractSSL Off");        
  332   	}
  333   	if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) {
  334   	    mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator);        
  335   	}
  336   	if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) {
  337   	    mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator);
  338   	}
  339   	if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) {
  340   	    mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator);
  341   	}
  342   	if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) {
  343   	    mod_jk.println("JkCERTSIndicator " + sslCertsIndicator);
  344   	}
  345   
  346   	mod_jk.println();
  347       }
  348   
  349       // -------------------- Forward all mode --------------------
  350       String indent="";
  351       
  352       /** Forward all requests for a context to tomcat.
  353   	The default.
  354        */
  355       protected void generateStupidMappings(Context context,
  356   					   PrintWriter mod_jk )
  357       {
  358   	String ctxPath  = context.getPath();
  359   	if(ctxPath == null)
  360   	    return;
  361   
  362   	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
  363   	
  364           mod_jk.println();
  365   	mod_jk.println(indent + "JkMount " +  nPath + " " + jkWorker );
  366   	if( "".equals(ctxPath) ) {
  367   	    mod_jk.println(indent + "JkMount " +  nPath + "* " + jkWorker );
  368               if ( context.getParent() instanceof Host ) {
  369                   mod_jk.println(indent + "DocumentRoot \"" +
  370                               getApacheDocBase(context) + "\"");
  371               } else {
  372                   mod_jk.println(indent +
  373                           "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot");
  374                   mod_jk.println(indent +
  375                           "# to point to: \"" + getApacheDocBase(context) + "\"");
  376               }
  377   
  378   	} else {
  379   	    mod_jk.println(indent + "JkMount " +  nPath + "/* " + jkWorker );
  380   	}
  381       }    
  382   
  383       
  384       private void generateNameVirtualHost( PrintWriter mod_jk, String ip ) {
  385           if( !NamedVirtualHosts.containsKey(ip) ) {
  386               mod_jk.println("NameVirtualHost " + ip + "");
  387               NamedVirtualHosts.put(ip,ip);
  388           }
  389       }
  390       
  391       // -------------------- Apache serves static mode --------------------
  392       // This is not going to work for all apps. We fall back to stupid mode.
  393       
  394       protected void generateContextMappings(Context context, PrintWriter mod_jk )
  395       {
  396   	String ctxPath  = context.getPath();
  397   	Host vhost = getHost(context);
  398   
  399           if( noRoot &&  "".equals(ctxPath) ) {
  400               log.debug("Ignoring root context in non-forward-all mode  ");
  401               return;
  402           }
  403   
  404   	mod_jk.println();
  405   	mod_jk.println(indent + "#################### " +
  406   		       ((vhost!=null ) ? vhost.getName() + ":" : "" ) +
  407   		       (("".equals(ctxPath)) ? "/" : ctxPath ) +
  408   		       " ####################" );
  409           mod_jk.println();
  410   	// Dynamic /servet pages go to Tomcat
  411    
  412   	generateStaticMappings( context, mod_jk );
  413   
  414   	// InvokerInterceptor - it doesn't have a container,
  415   	// but it's implemented using a special module.
  416   	
  417   	// XXX we need to better collect all mappings
  418   
  419   	if(context.getLoginConfig() != null) {
  420   	    String loginPage = context.getLoginConfig().getLoginPage();
  421   	    if(loginPage != null) {
  422   		int lpos = loginPage.lastIndexOf("/");
  423   		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
  424   		addMapping( ctxPath, jscurl, mod_jk);
  425   	    }
  426   	}
  427   	String [] servletMaps = context.findServletMappings();
  428   	for(int ii=0; ii < servletMaps.length; ii++) {
  429   	      addMapping( ctxPath, servletMaps[ii] , mod_jk );
  430   	}
  431       }
  432   
  433       /** Add an Apache extension mapping.
  434        */
  435       protected boolean addExtensionMapping( String ctxPath, String ext,
  436   					 PrintWriter mod_jk )
  437       {
  438           if( log.isDebugEnabled() )
  439               log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
  440   	mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext
  441   		       + " " + jkWorker);
  442   	return true;
  443       }
  444       
  445       
  446       /** Add a fulling specified Appache mapping.
  447        */
  448       protected boolean addMapping( String fullPath, PrintWriter mod_jk ) {
  449           if( log.isDebugEnabled() )
  450               log.debug( "Adding map for " + fullPath );
  451   	mod_jk.println(indent + "JkMount " + fullPath + "  " + jkWorker );
  452   	return true;
  453       }
  454       /** Add a partially specified Appache mapping.
  455        */
  456       protected boolean addMapping( String ctxP, String ext, PrintWriter mod_jk ) {
  457           if( log.isDebugEnabled() )
  458               log.debug( "Adding map for " + ext );
  459   	if(! ext.startsWith("/") )
  460   	    ext = "/" + ext;
  461   	if(ext.length() > 1)
  462   	    mod_jk.println(indent + "JkMount " + ctxP + ext+ "  " + jkWorker );
  463   	return true;
  464       }
  465   
  466       private void generateWelcomeFiles(Context context, PrintWriter mod_jk ) {
  467   	String wf[]=context.findWelcomeFiles();
  468   	if( wf==null || wf.length == 0 )
  469   	    return;
  470   	mod_jk.print(indent + "    DirectoryIndex ");
  471   	for( int i=0; i<wf.length ; i++ ) {
  472   	    mod_jk.print( wf[i] + " " );
  473   	}
  474   	mod_jk.println();
  475       }
  476   
  477       /** Mappings for static content. XXX need to add welcome files,
  478        *  mime mappings ( all will be handled by Mime and Static modules of
  479        *  apache ).
  480        */
  481       private void generateStaticMappings(Context context, PrintWriter mod_jk ) {
  482   	String ctxPath  = context.getPath();
  483   
  484   	// Calculate the absolute path of the document base
  485   	String docBase = getApacheDocBase(context);
  486   
  487           if( !"".equals(ctxPath) ) {
  488               // Static files will be served by Apache
  489               mod_jk.println(indent + "# Static files ");		    
  490               mod_jk.println(indent + "Alias " + ctxPath + " \"" + docBase + "\"");
  491               mod_jk.println();
  492           } else {
  493               if ( getHost(context) != null ) {
  494                   mod_jk.println(indent + "DocumentRoot \"" +
  495                               getApacheDocBase(context) + "\"");
  496               } else {
  497                   // For root context, ask user to update DocumentRoot setting.
  498                   // Using "Alias / " interferes with the Alias for other contexts.
  499                   mod_jk.println(indent +
  500                           "# Be sure to update DocumentRoot");
  501                   mod_jk.println(indent +
  502                           "# to point to: \"" + docBase + "\"");
  503               }
  504           }
  505   	mod_jk.println(indent + "<Directory \"" + docBase + "\">");
  506   	mod_jk.println(indent + "    Options Indexes FollowSymLinks");
  507   
  508   	generateWelcomeFiles(context, mod_jk);
  509   
  510   	// XXX XXX Here goes the Mime types and welcome files !!!!!!!!
  511   	mod_jk.println(indent + "</Directory>");
  512   	mod_jk.println();            
  513   	
  514   
  515   	// Deny serving any files from WEB-INF
  516   	mod_jk.println();            
  517   	mod_jk.println(indent +
  518   		       "# Deny direct access to WEB-INF and META-INF");
  519   	mod_jk.println(indent + "#");                        
  520   	mod_jk.println(indent + "<Location \"" + ctxPath + "/WEB-INF/*\">");
  521   	mod_jk.println(indent + "    AllowOverride None");
  522   	mod_jk.println(indent + "    deny from all");
  523   	mod_jk.println(indent + "</Location>");
  524   	// Deny serving any files from META-INF
  525   	mod_jk.println();            
  526   	mod_jk.println(indent + "<Location \"" + ctxPath + "/META-INF/*\">");
  527   	mod_jk.println(indent + "    AllowOverride None");
  528   	mod_jk.println(indent + "    deny from all");
  529   	mod_jk.println(indent + "</Location>");
  530   	if (File.separatorChar == '\\') {
  531   	    mod_jk.println(indent + "#");		    
  532   	    mod_jk.println(indent +
  533   			   "# Use Directory too. On Windows, Location doesn't"
  534   			   + " work unless case matches");
  535   	    mod_jk.println(indent + "#");                        
  536   	    mod_jk.println(indent +
  537   			   "<Directory \"" + docBase + "/WEB-INF/\">");
  538   	    mod_jk.println(indent + "    AllowOverride None");
  539   	    mod_jk.println(indent + "    deny from all");
  540   	    mod_jk.println(indent + "</Directory>");
  541   	    mod_jk.println();
  542   	    mod_jk.println(indent +
  543   			   "<Directory \"" + docBase + "/META-INF/\">");
  544   	    mod_jk.println(indent + "    AllowOverride None");
  545   	    mod_jk.println(indent + "    deny from all");
  546   	    mod_jk.println(indent + "</Directory>");
  547   	}
  548   	mod_jk.println();
  549       }    
  550   
  551       // -------------------- Utils --------------------
  552   
  553       private String getApacheDocBase(Context context)
  554       {
  555   	// Calculate the absolute path of the document base
  556   	String docBase = getAbsoluteDocBase(context);
  557   	if (File.separatorChar == '\\') {
  558   	    // use separator preferred by Apache
  559   	    docBase = docBase.replace('\\','/');
  560   	}
  561           return docBase;
  562       }
  563   
  564       private String getVirtualHostAddress(String vhost, String vhostip) {
  565           if( vhostip == null ) {
  566               if ( vhost != null && vhost.length() > 0 && Character.isDigit(vhost.charAt(0)) )
  567                   vhostip=vhost;
  568               else
  569                   vhostip="*";
  570           }
  571           return vhostip;
  572       }
  573   
  574   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache.jk » config » [javadoc | source]