Save This Page
Home » apache-tomcat-6.0.16-src » org.apache.jk » server » [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.server;
   19   
   20   import java.io.File;
   21   import java.io.FileInputStream;
   22   import java.io.FileOutputStream;
   23   import java.io.IOException;
   24   import java.io.PrintStream;
   25   import java.util.Enumeration;
   26   import java.util.Hashtable;
   27   import java.util.Properties;
   28   import java.util.StringTokenizer;
   29   import java.util.Vector;
   30   
   31   import javax.management.MBeanRegistration;
   32   import javax.management.MBeanServer;
   33   import javax.management.ObjectName;
   34   
   35   import org.apache.jk.core.JkHandler;
   36   import org.apache.jk.core.WorkerEnv;
   37   import org.apache.tomcat.util.IntrospectionUtils;
   38   import org.apache.tomcat.util.modeler.Registry;
   39   
   40   /** Main class used to startup and configure jk. It manages the conf/jk2.properties file
   41    *  and is the target of JMX proxy.
   42    *
   43    *  It implements a policy of save-on-change - whenever a property is changed at
   44    *  runtime the jk2.properties file will be overriden. 
   45    *
   46    *  You can edit the config file when tomcat is stoped ( or if you don't use JMX or
   47    *  other admin tools ).
   48    *
   49    *  The format of jk2.properties:
   50    *  <dl>
   51    *   <dt>TYPE[.LOCALNAME].PROPERTY_NAME=VALUE
   52    *   <dd>Set a property on the associated component. TYPE will be used to
   53    *   find the class name and instantiate the component. LOCALNAME allows
   54    *   multiple instances. In JMX mode, TYPE and LOCALNAME will form the
   55    *   JMX name ( eventually combined with a 'jk2' component )
   56    *
   57    *   <dt>NAME=VALUE
   58    *   <dd>Define global properties to be used in ${} substitutions
   59    *
   60    *   <dt>class.COMPONENT_TYPE=JAVA_CLASS_NAME
   61    *   <dd>Adds a new 'type' of component. We predefine all known types.
   62    * </dl>
   63    *
   64    * Instances are created the first time a component name is found. In addition,
   65    * 'handler.list' property will override the list of 'default' components that are
   66    * loaded automatically.
   67    *
   68    *  Note that the properties file is just one (simplistic) way to configure jk. We hope
   69    *  to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better )
   70    * 
   71    * @author Costin Manolache
   72    */
   73   public class JkMain implements MBeanRegistration
   74   {
   75       WorkerEnv wEnv;
   76       String propFile;
   77       Properties props=new Properties();
   78   
   79       Properties modules=new Properties();
   80       boolean modified=false;
   81       boolean started=false;
   82       boolean saveProperties=false;
   83   
   84       public JkMain()
   85       {
   86           JkMain.jkMain=this;
   87           modules.put("channelSocket", "org.apache.jk.common.ChannelSocket");
   88           modules.put("channelNioSocket", "org.apache.jk.common.ChannelNioSocket");
   89           modules.put("channelUnix", "org.apache.jk.common.ChannelUn");
   90           modules.put("channelJni", "org.apache.jk.common.ChannelJni");
   91           modules.put("apr", "org.apache.jk.apr.AprImpl");
   92           modules.put("mx", "org.apache.jk.common.JkMX");
   93           modules.put("modeler", "org.apache.jk.common.JkModeler");
   94           modules.put("shm", "org.apache.jk.common.Shm");
   95           modules.put("request","org.apache.jk.common.HandlerRequest");
   96           modules.put("container","org.apache.jk.common.HandlerRequest");
   97           modules.put("modjk","org.apache.jk.common.ModJkMX");
   98   
   99       }
  100   
  101       public static JkMain getJkMain() {
  102           return jkMain;
  103       }
  104   
  105       private static String DEFAULT_HTTPS="com.sun.net.ssl.internal.www.protocol";
  106       private void initHTTPSUrls() {
  107           try {
  108               // 11657: if only ajp is used, https: redirects need to work ( at least for 1.3+)
  109               String value = System.getProperty("java.protocol.handler.pkgs");
  110               if (value == null) {
  111                   value = DEFAULT_HTTPS;
  112               } else if (value.indexOf(DEFAULT_HTTPS) >= 0  ) {
  113                   return; // already set
  114               } else {
  115                   value += "|" + DEFAULT_HTTPS;
  116               }
  117               System.setProperty("java.protocol.handler.pkgs", value);
  118           } catch(Exception ex ) {
  119               log.info("Error adding SSL Protocol Handler",ex);
  120           }
  121       }
  122   
  123       // -------------------- Setting --------------------
  124       
  125       /** Load a .properties file into and set the values
  126        *  into jk2 configuration.
  127        */
  128       public void setPropertiesFile( String p  ) {
  129           propFile=p;
  130           if( started ) {
  131               loadPropertiesFile();
  132           }
  133       }
  134   
  135       public String getPropertiesFile() {
  136           return propFile;
  137       }
  138   
  139       public void setSaveProperties( boolean b ) {
  140           saveProperties=b;
  141       }
  142   
  143       /** Set a name/value as a jk2 property
  144        */
  145       public void setProperty( String n, String v ) {
  146           if( "jkHome".equals( n ) ) {
  147               setJkHome( v );
  148           } 
  149           if( "propertiesFile".equals( n ) ) {
  150               setPropertiesFile( v );
  151           }
  152           props.put( n, v );
  153           if( started ) {
  154               processProperty( n, v );
  155               saveProperties();
  156           }
  157       }
  158       /**
  159        * Retrieve a property.
  160        */
  161       public Object getProperty(String name) {
  162           String alias = (String)replacements.get(name);
  163           Object result = null;
  164           if(alias != null) {
  165               result = props.get(alias);
  166           }
  167           if(result == null) {
  168               result = props.get(name);
  169           }
  170           return result;
  171       }
  172       /**
  173        * Set the <code>channelClassName</code> that will used to connect to
  174        * httpd.
  175        */
  176       public void setChannelClassName(String name) {
  177           props.put( "handler.channel.className",name);
  178       }
  179   
  180       public String getChannelClassName() {
  181           return (String)props.get( "handler.channel.className");
  182       }
  183   
  184       /**
  185        * Set the <code>workerClassName</code> that will handle the request.
  186        * ( sort of 'pivot' in axis :-)
  187        */
  188       public void setWorkerClassName(String name) {
  189           props.put( "handler.container.className",name);
  190       }
  191   
  192       public String getWorkerClassName() {
  193           return (String)props.get( "handler.container.className");
  194       }
  195   
  196       /** Set the base dir of jk2. ( including WEB-INF if in a webapp ).
  197        *  We'll try to guess it from classpath if none is set ( for
  198        *  example on command line ), but if in a servlet environment
  199        *  you need to use Context.getRealPath or a system property or
  200        *  set it expliciltey.
  201        */
  202       public void setJkHome( String s ) {
  203           getWorkerEnv().setJkHome(s);
  204       }
  205   
  206       public String getJkHome() {
  207           return getWorkerEnv().getJkHome();
  208       }
  209   
  210       String out;
  211       String err;
  212       File propsF;
  213       
  214       public void setOut( String s ) {
  215           this.out=s;
  216       }
  217   
  218       public String getOut() {
  219           return this.out;
  220       }
  221   
  222       public void setErr( String s ) {
  223           this.err=s;
  224       }
  225       
  226       public String getErr() {
  227           return this.err;
  228       }
  229       
  230       // -------------------- Initialization --------------------
  231       
  232       public void init() throws IOException
  233       {
  234           long t1=System.currentTimeMillis();
  235           if(null != out) {
  236               PrintStream outS=new PrintStream(new FileOutputStream(out));
  237               System.setOut(outS);
  238           }
  239           if(null != err) {
  240               PrintStream errS=new PrintStream(new FileOutputStream(err));
  241               System.setErr(errS);
  242           }
  243   
  244           String home=getWorkerEnv().getJkHome();
  245           if( home==null ) {
  246               // XXX use IntrospectionUtil to find myself
  247               this.guessHome();
  248           }
  249           home=getWorkerEnv().getJkHome();
  250           if( home==null ) {
  251               log.info( "Can't find home, jk2.properties not loaded");
  252           }
  253           if(log.isDebugEnabled())
  254               log.debug("Starting Jk2, base dir= " + home  );
  255           loadPropertiesFile();
  256   
  257           String initHTTPS = (String)props.get("class.initHTTPS");
  258           if("true".equalsIgnoreCase(initHTTPS)) {
  259               initHTTPSUrls();
  260           }
  261   
  262           long t2=System.currentTimeMillis();
  263           initTime=t2-t1;
  264       }
  265       
  266       static String defaultHandlers[]= { "request",
  267                                          "container",
  268                                          "channelSocket"};
  269       /*
  270        static String defaultHandlers[]= { "apr",
  271                                          "shm",
  272                                          "request",
  273                                          "container",
  274                                          "channelSocket",
  275                                          "channelJni",
  276                                          "channelUnix"};
  277       */
  278       
  279       public void stop() 
  280       {
  281           for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
  282               if( wEnv.getHandler(i) != null ) {
  283                   try {
  284                       wEnv.getHandler(i).destroy();
  285                   } catch( IOException ex) {
  286                       log.error("Error stopping " + wEnv.getHandler(i).getName(), ex);
  287                   }
  288               }
  289           }
  290   
  291           started=false;
  292       }
  293       
  294       public void start() throws IOException
  295       {
  296           long t1=System.currentTimeMillis();
  297           // We must have at least 3 handlers:
  298           // channel is the 'transport'
  299           // request is the request processor or 'global' chain
  300           // container is the 'provider'
  301           // Additional handlers may exist and be used internally
  302           // or be chained to create one of the standard handlers 
  303   
  304           String handlers[]=defaultHandlers;
  305           // backward compat
  306           String workers=props.getProperty( "handler.list", null );
  307           if( workers!=null ) {
  308               handlers= split( workers, ",");
  309           }
  310   
  311           // Load additional component declarations
  312           processModules();
  313           
  314           for( int i=0; i<handlers.length; i++ ) {
  315               String name= handlers[i];
  316               JkHandler w=getWorkerEnv().getHandler( name );
  317               if( w==null ) {
  318                   newHandler( name, "", name );
  319               }
  320           }
  321   
  322           // Process properties - and add aditional handlers.
  323           processProperties();
  324   
  325           for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
  326               if( wEnv.getHandler(i) != null ) {
  327                   try {
  328                       wEnv.getHandler(i).init();
  329                   } catch( IOException ex) {
  330                       if( "apr".equals(wEnv.getHandler(i).getName() )) {
  331                           log.info( "APR not loaded, disabling jni components: " + ex.toString());
  332                       } else {
  333                           log.error( "error initializing " + wEnv.getHandler(i).getName(), ex );
  334                       }
  335                   }
  336               }
  337           }
  338   
  339           started=true;
  340           long t2=System.currentTimeMillis();
  341           startTime=t2-t1;
  342   
  343           this.saveProperties();
  344           log.info("Jk running ID=" + wEnv.getLocalId() + " time=" + initTime + "/" + startTime +
  345                    "  config=" + propFile);
  346       }
  347   
  348       // -------------------- Usefull methods --------------------
  349       
  350       public WorkerEnv getWorkerEnv() {
  351           if( wEnv==null ) { 
  352               wEnv=new WorkerEnv();
  353           }
  354           return wEnv;
  355       }
  356   
  357       public void setWorkerEnv(WorkerEnv wEnv) {
  358           this.wEnv = wEnv;
  359       }
  360   
  361       /* A bit of magic to support workers.properties without giving
  362          up the clean get/set
  363       */
  364       public void setBeanProperty( Object target, String name, String val ) {
  365           if( val!=null )
  366               val=IntrospectionUtils.replaceProperties( val, props, null );
  367           if( log.isDebugEnabled())
  368               log.debug( "setProperty " + target + " " + name + "=" + val );
  369           
  370           IntrospectionUtils.setProperty( target, name, val );
  371       }
  372   
  373       /* 
  374        * Set a handler property
  375        */
  376       public void setPropertyString( String handlerN, String name, String val ) {
  377           if( log.isDebugEnabled() )
  378               log.debug( "setProperty " + handlerN + " " + name + "=" + val );
  379           Object target=getWorkerEnv().getHandler( handlerN );
  380   
  381           setBeanProperty( target, name, val );
  382           if( started ) {
  383               saveProperties();
  384           }
  385   
  386       }
  387   
  388       /** The time it took to initialize jk ( ms)
  389        */
  390       public long getInitTime() {
  391           return initTime;
  392       }
  393   
  394       /** The time it took to start jk ( ms )
  395        */
  396       public long getStartTime() {
  397           return startTime;
  398       }
  399       
  400       // -------------------- Main --------------------
  401   
  402       long initTime;
  403       long startTime;
  404       static JkMain jkMain=null;
  405   
  406       public static void main(String args[]) {
  407           try {
  408               if( args.length == 1 &&
  409                   ( "-?".equals(args[0]) || "-h".equals( args[0])) ) {
  410                   System.out.println("Usage: ");
  411                   System.out.println("  JkMain [args]");
  412                   System.out.println();
  413                   System.out.println("  Each bean setter corresponds to an arg ( like -debug 10 )");
  414                   System.out.println("  System properties:");
  415                   System.out.println("    jk2.home    Base dir of jk2");
  416                   return;
  417               }
  418   
  419               jkMain=new JkMain();
  420   
  421               IntrospectionUtils.processArgs( jkMain, args, new String[] {},
  422                                               null, new Hashtable());
  423   
  424               jkMain.init();
  425               jkMain.start();
  426           } catch( Exception ex ) {
  427               log.warn("Error running",ex);
  428           }
  429       }
  430   
  431       // -------------------- Private methods --------------------
  432   
  433   
  434       private boolean checkPropertiesFile() {
  435           if(propFile == null) {
  436               return false;
  437           }
  438           propsF = new File(propFile);
  439           if(!propsF.isAbsolute()) {
  440               String home = getWorkerEnv().getJkHome();
  441               if( home == null ) {
  442                   return false;
  443               }
  444               propsF = new File(home, propFile);
  445           }
  446           return propsF.exists();
  447       }
  448               
  449       private void loadPropertiesFile() {
  450           if(!checkPropertiesFile()) {
  451               return;
  452           }
  453   
  454           try {
  455               props.load( new FileInputStream(propsF) );
  456           } catch(IOException ex ){
  457               log.warn("Unable to load properties from "+propsF,ex);
  458           }
  459       }
  460   
  461       public  void saveProperties() {
  462           if( !saveProperties) return;
  463           
  464           if(propsF == null) {
  465               log.warn("No properties file specified. Unable to save");
  466               return;
  467           }
  468           // Temp - to check if it works
  469           File outFile= new File(propsF.getParentFile(), propsF.getName()+".save");
  470           log.debug("Saving properties " + outFile );
  471           try {
  472               props.store( new FileOutputStream(outFile), "AUTOMATICALLY GENERATED" );
  473           } catch(IOException ex ){
  474               log.warn("Unable to save to "+outFile,ex);
  475           }
  476       }
  477   
  478       // translate top-level keys ( from coyote or generic ) into component keys
  479       static Hashtable replacements=new Hashtable();
  480       static {
  481           replacements.put("port","channelSocket.port");
  482           replacements.put("maxThreads", "channelSocket.maxThreads");   
  483           replacements.put("minSpareThreads", "channelSocket.minSpareThreads");   
  484           replacements.put("maxSpareThreads", "channelSocket.maxSpareThreads");   
  485           replacements.put("backlog", "channelSocket.backlog");   
  486           replacements.put("tcpNoDelay", "channelSocket.tcpNoDelay");
  487           replacements.put("soTimeout", "channelSocket.soTimeout");
  488           replacements.put("timeout", "channelSocket.timeout");
  489           replacements.put("address", "channelSocket.address");            
  490           replacements.put("bufferSize", "channelSocket.bufferSize");
  491           replacements.put("tomcatAuthentication", "request.tomcatAuthentication");
  492           replacements.put("packetSize", "channelSocket.packetSize");
  493       }
  494   
  495       private void preProcessProperties() {
  496           Enumeration keys=props.keys();
  497           Vector v=new Vector();
  498           
  499           while( keys.hasMoreElements() ) {
  500               String key=(String)keys.nextElement();          
  501               Object newName=replacements.get(key);
  502               if( newName !=null ) {
  503                   v.addElement(key);
  504               }
  505           }
  506           keys=v.elements();
  507           while( keys.hasMoreElements() ) {
  508               String key=(String)keys.nextElement();
  509               Object propValue=props.getProperty( key );
  510               String replacement=(String)replacements.get(key);
  511               props.put(replacement, propValue);
  512               if( log.isDebugEnabled()) 
  513                   log.debug("Substituting " + key + " " + replacement + " " + 
  514                       propValue);
  515           }
  516       }
  517       
  518       private void processProperties() {
  519           preProcessProperties();
  520           Enumeration keys=props.keys();
  521   
  522           while( keys.hasMoreElements() ) {
  523               String name=(String)keys.nextElement();
  524               String propValue=props.getProperty( name );
  525   
  526               processProperty( name, propValue );
  527           }
  528       }
  529   
  530       private void processProperty(String name, String propValue) {
  531           String type=name;
  532           String fullName=name;
  533           String localName="";
  534           String propName="";
  535           // ignore
  536           if( name.startsWith("key.")) return;
  537   
  538           int dot=name.indexOf(".");
  539           int lastDot=name.lastIndexOf(".");
  540           if( dot > 0 ) {
  541               type=name.substring(0, dot );
  542               if( dot != lastDot ) {
  543                   localName=name.substring( dot + 1, lastDot );
  544                   fullName=type + "." + localName;
  545               } else {
  546                   fullName=type;
  547               }
  548               propName=name.substring( lastDot+1);
  549           } else {
  550               return;
  551           }
  552           
  553           if( log.isDebugEnabled() )
  554               log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName );
  555           if( "class".equals( type ) || "handler".equals( type ) ) {
  556               return;
  557           }
  558           
  559           JkHandler comp=getWorkerEnv().getHandler( fullName );
  560           if( comp==null ) {
  561               comp=newHandler( type, localName, fullName );
  562           }
  563           if( comp==null )
  564               return;
  565           
  566           if( log.isDebugEnabled() ) 
  567               log.debug("Setting " + propName + " on " + fullName + " " + comp);
  568           this.setBeanProperty( comp, propName, propValue );
  569       }
  570   
  571       private JkHandler newHandler( String type, String localName, String fullName )
  572       {
  573           JkHandler handler;
  574           String classN=modules.getProperty(type);
  575           if( classN == null ) {
  576               log.error("No class name for " + fullName + " " + type );
  577               return null;
  578           }
  579           try {
  580               Class channelclass = Class.forName(classN);
  581               handler=(JkHandler)channelclass.newInstance();
  582           } catch (Throwable ex) {
  583               handler=null;
  584               log.error( "Can't create " + fullName, ex );
  585               return null;
  586           }
  587           if( this.domain != null ) {
  588               try {
  589                   ObjectName handlerOname = new ObjectName
  590                       (this.domain + ":" + "type=JkHandler,name=" + fullName);
  591                   Registry.getRegistry(null, null).registerComponent(handler, handlerOname, classN);
  592               } catch (Exception e) {
  593                   log.error( "Error registering " + fullName, e );
  594               }
  595   
  596           }
  597           wEnv.addHandler( fullName, handler );
  598           return handler;
  599       }
  600   
  601       private void processModules() {
  602           Enumeration keys=props.keys();
  603           int plen=6;
  604           
  605           while( keys.hasMoreElements() ) {
  606               String k=(String)keys.nextElement();
  607               if( ! k.startsWith( "class." ) )
  608                   continue;
  609   
  610               String name= k.substring( plen );
  611               String propValue=props.getProperty( k );
  612   
  613               if( log.isDebugEnabled()) log.debug("Register " + name + " " + propValue );
  614               modules.put( name, propValue );
  615           }
  616       }
  617   
  618       private String[] split(String s, String delim ) {
  619            Vector v=new Vector();
  620           StringTokenizer st=new StringTokenizer(s, delim );
  621           while( st.hasMoreTokens() ) {
  622               v.addElement( st.nextToken());
  623           }
  624           String res[]=new String[ v.size() ];
  625           for( int i=0; i<res.length; i++ ) {
  626               res[i]=(String)v.elementAt(i);
  627           }
  628           return res;
  629       }
  630   
  631       // guessing home
  632       private static String CNAME="org/apache/jk/server/JkMain.class";
  633   
  634       private void guessHome() {
  635           String home= wEnv.getJkHome();
  636           if( home != null )
  637               return;
  638           home=IntrospectionUtils.guessInstall( "jk2.home","jk2.home",
  639                                                 "tomcat-jk2.jar", CNAME );
  640           if( home != null ) {
  641               log.info("Guessed home " + home );
  642               wEnv.setJkHome( home );
  643           }
  644       }
  645   
  646       static org.apache.juli.logging.Log log=
  647           org.apache.juli.logging.LogFactory.getLog( JkMain.class );
  648   
  649       protected String domain;
  650       protected ObjectName oname;
  651       protected MBeanServer mserver;
  652   
  653       public ObjectName getObjectName() {
  654           return oname;
  655       }
  656   
  657       public String getDomain() {
  658           return domain;
  659       }
  660   
  661       public ObjectName preRegister(MBeanServer server,
  662                                     ObjectName name) throws Exception {
  663           oname=name;
  664           mserver=server;
  665           domain=name.getDomain();
  666           return name;
  667       }
  668   
  669       public void postRegister(Boolean registrationDone) {
  670       }
  671   
  672       public void preDeregister() throws Exception {
  673       }
  674   
  675       public void postDeregister() {
  676       }
  677   
  678       public void pause() throws Exception {
  679           for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
  680               if( wEnv.getHandler(i) != null ) {
  681                   wEnv.getHandler(i).pause();
  682               }
  683           }
  684       }
  685   
  686       public void resume() throws Exception {
  687           for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
  688               if( wEnv.getHandler(i) != null ) {
  689                   wEnv.getHandler(i).resume();
  690               }
  691           }
  692       }
  693   
  694   
  695   }

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