costin 02/04/18 10:48:00 Modified: jk/java/org/apache/jk/server JkMain.java Log: Added comments on the format used for properties. Added method to save the properties file ( for now in a separate location ) whenever a property is changed after startup ( by JMX or another admin application ). Removed the need to specify the class name for the known components ( we do know them, no need for the user to do that ). Try to load all components - if they don't have the needed resources ( native libs, etc ) they'll just report so and do nothing. Made the format closer to what's used in mod_jk ( except ':' can't be used since it's a delimiter, etc ). It seems implementing the ini format in java is not much easier than C ... Revision Changes Path 1.18 +163 -50 jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java Index: JkMain.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/jk/server/JkMain.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- JkMain.java 13 Apr 2002 05:53:30 -0000 1.17 +++ JkMain.java 18 Apr 2002 17:48:00 -0000 1.18 @@ -70,9 +70,38 @@ import org.apache.tomcat.util.http.*; import org.apache.tomcat.util.IntrospectionUtils; -/** Main class used to startup jk. +/** Main class used to startup and configure jk. It manages the conf/jk2.properties file + * and is the target of JMX proxy. * - * It is also useable standalone for testing or as a minimal socket server. + * It implements a policy of save-on-change - whenever a property is changed at + * runtime the jk2.properties file will be overriden. + * + * You can edit the config file when tomcat is stoped ( or if you don't use JMX or + * other admin tools ). + * + * The format of jk2.properties: + * <dl> + * <dt>TYPE[.LOCALNAME].PROPERTY_NAME=VALUE + * <dd>Set a property on the associated component. TYPE will be used to + * find the class name and instantiate the component. LOCALNAME allows + * multiple instances. In JMX mode, TYPE and LOCALNAME will form the + * JMX name ( eventually combined with a 'jk2' component ) + * + * <dt>NAME=VALUE + * <dd>Define global properties to be used in ${} substitutions + * + * <dt>class.COMPONENT_TYPE=JAVA_CLASS_NAME + * <dd>Adds a new 'type' of component. We predefine all known types. + * </dl> + * + * Instances are created the first time a component name is found. In addition, + * 'handler.list' property will override the list of 'default' components that are + * loaded automatically. + * + * Note that the properties file is just one (simplistic) way to configure jk. We hope + * to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better ) + * + * @author Costin Manolache */ public class JkMain { @@ -80,8 +109,19 @@ String propFile; Properties props=new Properties(); + Properties modules=new Properties(); + boolean modified=false; + boolean started=false; + public JkMain() { + modules.put("channelSocket", "org.apache.jk.common.ChannelSocket"); + modules.put("channelUnix", "org.apache.jk.common.ChannelUn"); + modules.put("channelJni", "org.apache.jk.common.ChannelJni"); + modules.put("apr", "org.apache.jk.apr.AprImpl"); + modules.put("shm", "org.apache.jk.common.Shm"); + modules.put("request","org.apache.jk.common.HandlerRequest"); + modules.put("container","org.apache.jk.common.HandlerRequest"); } // -------------------- Setting -------------------- @@ -104,6 +144,10 @@ setJkHome( v ); } props.put( n, v ); + if( started ) { + processProperty( n, v ); + saveProperties(); + } } /** @@ -182,49 +226,45 @@ } } + static String defaultHandlers[]= { "apr", + "shm", + "request", + "container" }; public void start() throws IOException { - if( props.get( "handler.request.className" )==null ) - props.put( "handler.request.className", - "org.apache.jk.common.HandlerRequest" ); - - if( props.get( "handler.channel.className" )==null ) - props.put( "handler.channel.className", - "org.apache.jk.common.ChannelSocket" ); - // We must have at least 3 handlers: // channel is the 'transport' // request is the request processor or 'global' chain // container is the 'provider' // Additional handlers may exist and be used internally // or be chained to create one of the standard handlers + + String handlers[]=defaultHandlers; + String workers=props.getProperty( "handler.list", null ); + if( workers!=null ) { + handlers= split( workers, ","); + } + + // Load additional component declarations + processModules(); - String workers=props.getProperty( "handler.list", - "channel,request,container" ); - Vector workerNamesV= split( workers, ","); - if( log.isDebugEnabled() ) - log.debug("workers: " + workers + " " + workerNamesV.size() ); - - for( int i=0; i<workerNamesV.size(); i++ ) { - String name= (String)workerNamesV.elementAt( i ); - if( log.isDebugEnabled() ) - log.debug("Configuring " + name ); + for( int i=0; i<handlers.length; i++ ) { + String name= handlers[i]; JkHandler w=wEnv.getHandler( name ); - if( w==null ) - w=(JkHandler)newInstance( "handler", name, null ); if( w==null ) { - log.warn("Can't create handler for name " + name ); - continue; + newHandler( name, "", name ); } - - wEnv.addHandler( name, w ); - - processProperties( w, "handler."+ name + "." ); } + + // Process properties - and add aditional handlers. + processProperties(); wEnv.start(); + started=true; long initTime=System.currentTimeMillis() - start_time; + + this.saveProperties(); log.info("Jk running... init time=" + initTime + " ms"); } @@ -255,6 +295,10 @@ Object target=wEnv.getHandler( handlerN ); setBeanProperty( target, name, val ); + if( started ) { + saveProperties(); + } + } public long getStartTime() { @@ -292,47 +336,116 @@ // -------------------- Private methods -------------------- + public void saveProperties() { + // Temp - to check if it works + String outFile=propFile + ".save"; + log.info("Saving properties " + outFile ); + try { + props.save( new FileOutputStream(outFile), "AUTOMATICALLY GENERATED" ); + } catch(IOException ex ){ + ex.printStackTrace(); + } + } - private void processProperties(Object o, String prefix) { + private void processProperties() { Enumeration keys=props.keys(); - int plen=prefix.length(); - + while( keys.hasMoreElements() ) { - String k=(String)keys.nextElement(); - if( ! k.startsWith( prefix ) ) - continue; + String name=(String)keys.nextElement(); + String propValue=props.getProperty( name ); - String name= k.substring( plen ); - String propValue=props.getProperty( k ); - if( "className".equals( name ) ) - continue; - this.setBeanProperty( o, name, propValue ); + processProperty( name, propValue ); } } - private Object newInstance( String type, String name, String def ) - throws IOException + private void processProperty(String name, String propValue) { + String type=name; + String fullName=name; + String localName=""; + String propName=""; + int dot=name.indexOf("."); + int lastDot=name.lastIndexOf("."); + if( dot > 0 ) { + type=name.substring(0, dot ); + if( dot != lastDot ) { + localName=name.substring( dot + 1, lastDot ); + fullName=type + "." + localName; + } else { + fullName=type; + } + propName=name.substring( lastDot+1); + } else { + // No . -> global property, will be used in substitutions + return; + } + + if( log.isDebugEnabled() ) + log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName ); + if( "class".equals( type ) || "handler".equals( type ) ) { + return; + } + + JkHandler comp=wEnv.getHandler( fullName ); + if( comp==null ) { + comp=newHandler( type, localName, fullName ); + } + if( comp==null ) + return; + + if( log.isDebugEnabled() ) + log.debug("Setting " + propName + " on " + fullName + " " + comp); + this.setBeanProperty( comp, propName, propValue ); + } + + private JkHandler newHandler( String type, String localName, String fullName ) { - String classN=null; + JkHandler handler; + String classN=modules.getProperty(type); + if( classN == null ) { + System.err.println("No class name for " + fullName + " " + type ); + return null; + } try { - classN=props.getProperty( type + "." + name + ".className", - def ); - if( classN== null ) return null; Class channelclass = Class.forName(classN); - return channelclass.newInstance(); + handler=(JkHandler)channelclass.newInstance(); } catch (Throwable ex) { - ex.printStackTrace(); - throw new IOException("Cannot create channel class " + classN); + handler=null; + log.error( "Can't create " + fullName, ex ); + return null; } + + wEnv.addHandler( fullName, handler ); + return handler; } - private Vector split(String s, String delim ) { + private void processModules() { + Enumeration keys=props.keys(); + int plen=6; + + while( keys.hasMoreElements() ) { + String k=(String)keys.nextElement(); + if( ! k.startsWith( "class." ) ) + continue; + + String name= k.substring( plen ); + String propValue=props.getProperty( k ); + + System.out.println("Register " + name + " " + propValue ); + modules.put( name, propValue ); + } + } + + private String[] split(String s, String delim ) { Vector v=new Vector(); StringTokenizer st=new StringTokenizer(s, delim ); while( st.hasMoreTokens() ) { v.addElement( st.nextToken()); } - return v; + String res[]=new String[ v.size() ]; + for( int i=0; i<res.length; i++ ) { + res[i]=(String)v.elementAt(i); + } + return res; } // guessing home
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>