costin 02/03/23 09:21:56 Modified: jk/native2/common jk_config.c Log: - add experimental support for saving the config. That will enable 'autoconf' and runtime changes via ajp13/status worker. ( the problem was that even if you have autoconf, it is lost when you restart and that means you need tomcat up every time ) - add support for [name], i.e. ini-style properties file. This allows a much cleaner and intuitive config format ( and it is still a familiar format, based on a common standard ). - store the 'original' properties ( with un-replaced $(prp) ), to be saved. - clean up the code that deals with processing the property format. - various fixes Revision Changes Path 1.4 +298 -121 jakarta-tomcat-connectors/jk/native2/common/jk_config.c Index: jk_config.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/common/jk_config.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- jk_config.c 19 Mar 2002 05:31:57 -0000 1.3 +++ jk_config.c 23 Mar 2002 17:21:56 -0000 1.4 @@ -58,7 +58,7 @@ /*************************************************************************** * Description: General purpose config object * * Author: Gal Shachor <[EMAIL PROTECTED]> * - * Version: $Revision: 1.3 $ * + * Version: $Revision: 1.4 $ * ***************************************************************************/ #include "jk_global.h" @@ -80,9 +80,8 @@ /* ==================== ==================== */ -/* Set the file where the config will be read and - * ( in future ) stored. - * +/* Set the config file, read it. The property will also be + used for storing modified properties. */ static int jk2_config_setConfigFile( jk_env_t *env, jk_config_t *cfg, @@ -130,6 +129,55 @@ return JK_TRUE; } +/* Experimental. Dangerous. The file param will go away, for security + reasons - it can save only in the original file. + */ +static int jk2_config_saveConfig( jk_env_t *env, + jk_config_t *cfg, + jk_workerEnv_t *wEnv, + char *workerFile) +{ + FILE *fp; + char buf[LENGTH_OF_LINE + 1]; + int i,j; + + fp= fopen(workerFile, "w"); + + if(fp==NULL) + return JK_FALSE; + + /* We'll save only the objects/properties that were set + via config, and to the original 'string'. That keeps the config + small ( withou redundant ) and close to the original. Comments + will be saved/loaded later. + */ + for( i=0; i < env->_objects->size( env, env->_objects ); i++ ) { + char *name=env->_objects->nameAt( env, env->_objects, i ); + jk_bean_t *mbean=env->_objects->valueAt( env, env->_objects, i ); + + if( mbean==NULL || mbean->settings==NULL ) + continue; + + fprintf( fp, "[%s]\n", mbean->name ); + + for( j=0; j < mbean->settings->size( env, mbean->settings ); j++ ) { + char *pname=mbean->settings->nameAt( env, mbean->settings, j); + /* Don't save redundant information */ + if( strcmp( pname, "name" ) != NULL ) { + fprintf( fp, "%s=%s\n", + pname, + mbean->settings->valueAt( env, mbean->settings, j)); + } + } + fprintf( fp, "\n" ); + } + + fclose(fp); + + return JK_TRUE; +} + + /** Interpret the 'name' as [OBJECT].[PROPERTY]. If the [OBJECT] is not found, construct it using the prefix ( i.e. we'll search for a factory that matches @@ -137,115 +185,147 @@ Then set the property on the object that is found or constructed. + + No replacement or saving is done on the val - this is + a private method */ -static int jk2_config_setBeanPropertyString( jk_env_t *env, - jk_config_t *cfg, - char *name, char *val) + + +static int jk2_config_processBeanPropertyString( jk_env_t *env, + jk_config_t *cfg, + char *propertyString, + char **objName, char **propertyName ) { jk_bean_t *w = NULL; char *type=NULL; - char *objName= cfg->pool->pstrdup( env, cfg->pool, name ); - char *propName=NULL; char *dot=0; int i; char **comp; int nrComp; + char *lastDot; + char *lastDot1; + + propertyString=cfg->pool->pstrdup( env, cfg->pool, propertyString ); + + lastDot= rindex( propertyString, (int)'.' ); + lastDot1= rindex( propertyString, (int)':' ); - char *lastDot= rindex( objName, (int)'.' ); - + if( lastDot1==NULL ) + lastDot1=lastDot; + + if( lastDot==NULL || lastDot < lastDot1 ) + lastDot=lastDot1; + if( lastDot==NULL || *lastDot=='\0' ) return JK_FALSE; *lastDot='\0'; lastDot++; - propName=lastDot; - /* fprintf(stderr, "%d %s %s\n", *lastDot, lastDot, propName); */ - w=env->getMBean( env, objName ); + *objName=propertyString; + *propertyName=lastDot; - if( w==NULL ) { - jk_pool_t *workerPool; - - /** New object. Create it using the prefix - */ - for( i=0; i< env->_registry->size( env, env->_registry ) ; i++ ) { - char *factName=env->_registry->nameAt( env, env->_registry, i ); - int len=strlen(factName ); - - if( (strncmp( objName, factName, len) == 0) && - ( (objName[len] == '.') || - (objName[len] == '_') || - (objName[len] == '\0') ) ) { - /* We found the factory. */ - type=factName; - env->l->jkLog(env, env->l, JK_LOG_ERROR, - "Found %s %s %s %d %d\n", type, objName, - factName, len, strncmp( objName, factName, len)); - break; - } - } - if( type==NULL ) { - env->l->jkLog(env, env->l, JK_LOG_ERROR, - "Can't find type for %s \n", objName); - return JK_FALSE; - } + /* fprintf(stderr, "ProcessBeanProperty string %s %s\n", *objName, *propertyName); */ + + return JK_TRUE; +} + +/** Create a jk component using the name prefix + */ +static jk_bean_t *jk2_config_createInstance( jk_env_t *env, jk_config_t *cfg, + char *objName ) +{ + jk_pool_t *workerPool; + jk_bean_t *w=NULL; + int i; + char *type=NULL; - workerPool=cfg->pool->create(env, cfg->pool, HUGE_POOL_SIZE); + /** New object. Create it using the prefix + */ + for( i=0; i< env->_registry->size( env, env->_registry ) ; i++ ) { + char *factName=env->_registry->nameAt( env, env->_registry, i ); + int len=strlen(factName ); - env->l->jkLog(env, env->l, JK_LOG_ERROR, - "Create %s %s\n", type, objName); - env->createInstance( env, workerPool, type, objName ); - w=env->getMBean( env, objName ); - if( w==NULL ) { + if( (strncmp( objName, factName, len) == 0) && + ( (objName[len] == '.') || + (objName[len] == ':') || + (objName[len] == '_') || + (objName[len] == '\0') ) ) { + /* We found the factory. */ + type=factName; env->l->jkLog(env, env->l, JK_LOG_ERROR, - "Error creating %s %s\n", objName, type); + "Found %s %s %s %d %d\n", type, objName, + factName, len, strncmp( objName, factName, len)); + break; } } - - if( w != NULL ) { - /* If we have an object with that name, set the prop */ - env->l->jkLog(env, env->l, JK_LOG_INFO, - "Setting %s %s=%s\n", objName, propName, val); - - if( w->setAttribute != NULL ) - return w->setAttribute( env, w, propName, val ); + if( type==NULL ) { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "Can't find type for %s \n", objName); + return NULL; + } + + workerPool=cfg->pool->create(env, cfg->pool, HUGE_POOL_SIZE); + + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "Create %s name=%s\n", type, objName); + env->createInstance( env, workerPool, type, objName ); + w=env->getMBean( env, objName ); + if( w==NULL ) { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "Error creating %s %s\n", objName, type); + return NULL; } + if( w->settings == NULL ) + jk2_map_default_create(env, &w->settings, cfg->pool); - return JK_FALSE; + return w; } -/** Set a property for this config object + +/** Set a property on a bean. Call this when you know the bean. + The name and values will be saved in the config tables. + + @param mbean coresponds to the object beeing configured + @param name the property to be set ( can't have '.' or ':' in it ) + @param val the value, $(property) will be replaced. */ -static int jk2_config_setAttribute( struct jk_env *env, struct jk_bean *mbean, - char *name, void *valueP) +static int jk2_config_setProperty(jk_env_t *env, jk_config_t *cfg, + jk_bean_t *mbean, char *name, void *val) { - jk_config_t *cfg=mbean->object; - char *value=valueP; - - if( strcmp( name, "file" )==0 ) { - return jk2_config_setConfigFile(env, cfg, cfg->workerEnv, value); + char *pname; + if( mbean == cfg->mbean ) { + pname=name; } else { - return JK_FALSE; + pname=cfg->pool->calloc( env, cfg->pool, + strlen( name ) + strlen( mbean->name ) + 4 ); + strcpy( pname, mbean->name ); + strcat( pname, "." ); + strcat( pname, name ); } - return JK_TRUE; -} + fprintf( stderr, "config.setProperty %s %s %s \n", mbean->name, name, val ); -/** Set a property on a bean - */ -static int jk2_config_setProperty(jk_env_t *env, jk_config_t *cfg, - jk_bean_t *mbean, char *name, void *val) -{ - char *pname=cfg->pool->calloc( env, cfg->pool, - strlen( name ) + strlen( mbean->name ) + 4 ); - strcpy( pname, mbean->name ); - strcat( pname, "." ); - strcat( pname, name ); + /** Save it on the config. XXX no support for deleting yet */ + /* The _original_ value. Will be saved with $() in it */ + if( mbean->settings == NULL ) + jk2_map_default_create(env, &mbean->settings, cfg->pool); + mbean->settings->add( env, mbean->settings, name, val ); + + /* Call the 'active' setter + */ + val = jk2_config_replaceProperties(env, cfg->map, cfg->map->pool, val); + + /** Used for future replacements + */ cfg->map->add( env, cfg->map, pname, val ); - env->l->jkLog( env, env->l, JK_LOG_INFO, "config: set %s %s %s\n", - mbean->name, name, pname); - - return mbean->setAttribute( env, mbean, name, val ); + + env->l->jkLog( env, env->l, JK_LOG_ERROR, "config: set %s / %s / %s=%s\n", + mbean->name, name, pname, val); + + if(mbean->setAttribute) + return mbean->setAttribute( env, mbean, name, val ); + return JK_FALSE; } static int jk2_config_setPropertyString(jk_env_t *env, jk_config_t *cfg, @@ -256,16 +336,29 @@ jk_workerEnv_t *wEnv=cfg->workerEnv; jk_map_t *initData=cfg->map; int status; + char *objName=NULL; + char *propName=NULL; - value = jk2_config_replaceProperties(env, initData, initData->pool, value); + fprintf( stderr, "setPropertyString %s %s \n", name, value ); - /* Default format */ - status=jk2_config_setBeanPropertyString(env, cfg, name, value ); - if( status==JK_TRUE ) return status; + status=jk2_config_processBeanPropertyString(env, cfg, name, &objName, &propName ); + if( status!=JK_TRUE ) { + /* Unknown properties ends up in our config, as 'unclaimed' or global */ + jk2_config_setProperty( env, cfg, cfg->mbean, name, value ); + return status; + } + + mbean=env->getMBean( env, objName ); + if( mbean==NULL ) { + mbean=jk2_config_createInstance( env, cfg, objName ); + } + if( mbean == NULL ) { + /* Can't create it, save the value in our map */ + jk2_config_setProperty( env, cfg, cfg->mbean, name, value ); + return JK_FALSE; + } - /* It may be a 'normal' property */ - cfg->map->add( env, cfg->map, name, value ); - return JK_TRUE; + return jk2_config_setProperty( env, cfg, mbean, propName, value ); } @@ -432,10 +525,101 @@ /* ==================== */ /* Reading / parsing */ +int jk2_config_parseProperty(jk_env_t *env, jk_config_t *cfg, jk_map_t *m, char *prp ) +{ + int rc = JK_FALSE; + char *v; + + jk2_trim_prp_comment(prp); + + if( jk2_trim(prp)==0 ) + return JK_TRUE; + + /* Support windows-style 'sections' - for cleaner config + */ + if( prp[0] == '[' ) { + char *dummyProp; + v=strchr(prp, ']' ); + *v='\0'; + jk2_trim( v ); + prp++; + cfg->section=cfg->pool->pstrdup(env, cfg->pool, prp); + /* Add a dummy property, so the object will be created */ + dummyProp=cfg->pool->calloc( env, cfg->pool, strlen( prp ) + 7 ); + strcpy(dummyProp, prp ); + strcat( dummyProp, ".name"); + m->add( env, m, dummyProp, cfg->section); + + return JK_TRUE; + } + + v = strchr(prp, '='); + if(v==NULL) + return JK_TRUE; + + *v = '\0'; + v++; + + if(strlen(v)==0 || strlen(prp)==0) + return JK_TRUE; + + /* [ ] Shortcut */ + if( cfg->section != NULL ) { + char *newN=cfg->pool->calloc( env, cfg->pool, strlen( prp ) + strlen( cfg->section ) + 4 ); + strcpy( newN, cfg->section ); + strcat( newN, "." ); + strcat( newN, prp ); + prp=newN; + } + + /* Don't replace now - the caller may want to + save the file, and it'll replace them anyway for runtime changes + v = jk2_config_replaceProperties(env, cfg->map, cfg->pool, v); */ + + /* We don't contatenate the values - but use multi-value + fields. This eliminates the ugly hack where readProperties + tried to 'guess' the separator, and the code is much + cleaner. If we have multi-valued props, it's better + to deal with that instead of forcing a single-valued + model. + */ + m->add( env, m, cfg->pool->pstrdup(env, cfg->pool, prp), + cfg->pool->pstrdup(env, cfg->pool, v)); + + return JK_TRUE; +} + +/** Read a query string into the map + */ +int jk2_config_queryRead(jk_env_t *env, jk_config_t *cfg, jk_map_t *m, const char *query) +{ + char *sep; + char *value; + char *qry=cfg->pool->pstrdup( env, cfg->pool, query ); + + while( qry != NULL ) { + sep=strchr( qry, '&'); + if( sep !=NULL ) { + *sep='\0'; + sep++; + } + value = strchr(qry, '='); + if(value==NULL) { + value=""; + } else { + *value = '\0'; + value++; + } + m->add( env, m, cfg->pool->pstrdup( env, cfg->pool, qry ), + cfg->pool->pstrdup( env, cfg->pool, value )); + qry=sep; + } + return JK_TRUE; +} + int jk2_config_read(jk_env_t *env, jk_config_t *cfg, jk_map_t *m, const char *f) { - int rc = JK_FALSE; FILE *fp; char buf[LENGTH_OF_LINE + 1]; char *prp; @@ -449,41 +633,13 @@ if(fp==NULL) return JK_FALSE; - rc = JK_TRUE; - + cfg->section=NULL; while(NULL != (prp = fgets(buf, LENGTH_OF_LINE, fp))) { - char *oldv; - - jk2_trim_prp_comment(prp); - - if( jk2_trim(prp)==0 ) - continue; - - v = strchr(prp, '='); - if(v==NULL) - continue; - - *v = '\0'; - v++; - - if(strlen(v)==0 || strlen(prp)==0) - continue; - - v = jk2_config_replaceProperties(env, cfg->map, cfg->pool, v); - - /* We don't contatenate the values - but use multi-value - fields. This eliminates the ugly hack where readProperties - tried to 'guess' the separator, and the code is much - cleaner. If we have multi-valued props, it's better - to deal with that instead of forcing a single-valued - model. - */ - m->add( env, m, cfg->pool->pstrdup(env, cfg->pool, prp), - cfg->pool->pstrdup(env, cfg->pool, v)); + jk2_config_parseProperty( env, cfg, m, prp ); } fclose(fp); - return rc; + return JK_TRUE; } /** For multi-value properties, return the concatenation @@ -648,6 +804,27 @@ } +/** Set a property for this config object + */ +static int jk2_config_setAttribute( struct jk_env *env, struct jk_bean *mbean, + char *name, void *valueP) +{ + jk_config_t *cfg=mbean->object; + char *value=valueP; + + if( strcmp( name, "file" )==0 ) { + return jk2_config_setConfigFile(env, cfg, cfg->workerEnv, value); + } else if( strcmp( name, "save" )==0 ) { + /* Experimental. Setting save='foo' will save the current config in + foo + */ + return jk2_config_saveConfig(env, cfg, cfg->workerEnv, value); + } else { + return JK_FALSE; + } + return JK_TRUE; +} + static void jk2_trim_prp_comment(char *prp) { @@ -689,10 +866,10 @@ _this->setPropertyString=jk2_config_setPropertyString; _this->setProperty=jk2_config_setProperty; + _this->mbean=result; result->object=_this; result->setAttribute=jk2_config_setAttribute; - return JK_TRUE; }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>