You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2002/05/31 20:05:29 UTC

cvs commit: jakarta-tomcat-connectors/jk/native2/common jk_config_file.c jk_config.c jk_map.c list.mk

costin      2002/05/31 11:05:29

  Modified:    jk/native2/common jk_config.c jk_map.c list.mk
  Added:       jk/native2/common jk_config_file.c
  Log:
  A bit of refactoring.
  
  All workers2.properties parsing/saving code ( i.e. the properties + [ini] extensions )
  are now in jk_config_file.
  
  jk_config.c contains all generic methods that 'emulate' the bean ( or ant)-like
  configuration of components.
  
  Any alternate config repository can be used - the requirement is to be
  able to create a map with component names as keys and an attribute map
  as value.
  
  ( that's not actually required - you can walk a registry and call processNode
  if you want ).
  
  Note that jk_map.c is back to 'map only', and may be deprecated ( since
  apr has better maps ). We keep using it for now only because it's stable
  and doesn't create problems ( and we can store void * and char *)
  
  Revision  Changes    Path
  1.25      +27 -246   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.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- jk_config.c	30 May 2002 18:20:49 -0000	1.24
  +++ jk_config.c	31 May 2002 18:05:29 -0000	1.25
  @@ -55,100 +55,38 @@
    *                                                                           *
    * ========================================================================= */
   
  -/***************************************************************************
  - * Description: General purpose config object                                 *
  - * Author:      Gal Shachor <sh...@il.ibm.com>                           *
  - * Version:     $Revision: 1.24 $                                           *
  - ***************************************************************************/
  -
  +/**
  + * Common methods for processing config data. Independent of the config
  + * storage ( this is a sort of base class ).
  + *
  + * Config is read from the storage as a map, with 'bean names' as keys
  + * and a map of attributes as values.
  + *
  + * We'll process the map creating new objects and calling the setters, similar
  + * with what we do on the java side ( see ant or tomcat  ).
  + *
  + * There is also support for update, based on a version number. New objects
  + * or existing objects having a 'ver' attribute will have the setter methods
  + * called with the new values. XXX a reconfig method may be needed to notify.
  + * Backends that support notifications may update directly the changed attributes,
  + * but all components must support the simpler store ( where some attributes
  + * may be set multiple times, since we can't detect individual att changes ).
  + *
  + * Note: The current code assumes a backend that is capable of storing
  + * multi-valued attributes. This makes things hard to port to registry and
  + * some other repositories. 
  + *
  + * @author: Gal Shachor <sh...@il.ibm.com>                           
  + * @author: Costin Manolache
  + */
  + 
   #include "jk_global.h"
   #include "jk_map.h"
   #include "jk_pool.h"
   #include "jk_config.h"
   
  -#define CAPACITY_INC_SIZE (50)
   #define LENGTH_OF_LINE    (1024)
   
  -static int jk2_config_readFile(jk_env_t *env,
  -                                         jk_config_t *cfg,
  -                                         int *didReload, int firstTime);
  -
  -/* ==================== ==================== */
  -
  -/* 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,
  -                                     jk_workerEnv_t *wEnv,
  -                                     char *workerFile)
  -{   
  -    cfg->file=workerFile;
  -
  -    return jk2_config_readFile( env, cfg, NULL, 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,
  -                                  char *workerFile)
  -{
  -    FILE *fp;
  -/*    char buf[LENGTH_OF_LINE + 1];            */
  -    int i,j;
  -
  -    if( workerFile==NULL )
  -        workerFile=cfg->file;
  -
  -    if( workerFile== NULL )
  -        return JK_ERR;
  -    
  -    fp= fopen(workerFile, "w");
  -        
  -    if(fp==NULL)
  -        return JK_ERR;
  -
  -    env->l->jkLog(env, env->l, JK_LOG_INFO,
  -                  "config.save(): Saving %s\n", workerFile );
  -    
  -    /* 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;
  -
  -        if( strcmp( name, mbean->name ) != 0 ) {
  -            /* It's an alias. */
  -            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" ) != 0 ) {
  -                fprintf( fp, "%s=%s\n",
  -                         pname,
  -                         mbean->settings->valueAt( env, mbean->settings, j));
  -            }
  -        }
  -        fprintf( fp, "\n" );
  -    }
  -    
  -    fclose(fp);
  -
  -    return JK_OK;
  -}
  -
  -
   /** 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
  @@ -168,9 +106,6 @@
       jk_bean_t *w = NULL;
       char *type=NULL;
       char *dot=0;
  -/*    int i; */
  -/*    char **comp; */
  -/*    int nrComp; */
       char *lastDot;
       char *lastDot1;
       
  @@ -362,9 +297,6 @@
   
   
   
  -
  -
  -
   /**
    *  Replace $(property) in value.
    * 
  @@ -447,7 +379,7 @@
    *  and any removal may have disastrous consequences. Using critical
    *  sections would drastically affect the performance.
    */
  -static int jk2_config_processConfigData(jk_env_t *env, jk_config_t *cfg,int firstTime )
  +int jk2_config_processConfigData(jk_env_t *env, jk_config_t *cfg,int firstTime )
   {
       int i;
       int rc;
  @@ -459,7 +391,7 @@
       return rc;
   }
   
  -static int jk2_config_processNode(jk_env_t *env, jk_config_t *cfg, char *name, int firstTime )
  +int jk2_config_processNode(jk_env_t *env, jk_config_t *cfg, char *name, int firstTime )
   {
       int j;   
       
  @@ -515,156 +447,5 @@
           cfg->setProperty( env, cfg, bean, pname, pvalue );
       }
   
  -    return JK_OK;
  -}
  -
  -static int jk2_config_readFile(jk_env_t *env,
  -                               jk_config_t *cfg,
  -                               int *didReload, int firstTime)
  -{
  -    int rc;
  -    int csOk;
  -    struct stat statbuf;
  -
  -    if( didReload!=NULL )
  -        *didReload=JK_FALSE;
  -
  -    if( cfg->file==NULL ) {
  -        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                      "config.update(): No config file\n" );
  -        return JK_ERR;
  -    }
  -
  -    rc=stat(cfg->file, &statbuf);
  -    if (rc == -1) {
  -        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                      "config.update(): Can't find config file %s\n", cfg->file );
  -        return JK_ERR;
  -    }
  -    
  -    if( !firstTime && statbuf.st_mtime < cfg->mtime ) {
  -        if( cfg->mbean->debug > 0 )
  -            env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                          "config.update(): No reload needed %s %ld %ld\n", cfg->file,
  -                          cfg->mtime, statbuf.st_mtime );
  -        return JK_OK;
  -    }
  -     
  -    JK_ENTER_CS(&cfg->cs, csOk);
  -    
  -    if(csOk !=JK_TRUE) {
  -        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                      "cfg.update() Can't enter critical section\n");
  -        return JK_ERR;
  -    }
  -
  -    /* Check if another thread has updated the config */
  -
  -    rc=stat(cfg->file, &statbuf);
  -    if (rc == -1) {
  -        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                      "config.update(): Can't find config file %s", cfg->file );
  -        JK_LEAVE_CS(&cfg->cs, csOk);
  -        return JK_ERR;
  -    }
  -    
  -    if( ! firstTime && statbuf.st_mtime <= cfg->mtime ) {
  -        JK_LEAVE_CS(&cfg->cs, csOk);
  -        return JK_OK;
  -    }
  -
  -    env->l->jkLog(env, env->l, JK_LOG_INFO,
  -                  "cfg.update() Updating config %s %d %d\n",
  -                  cfg->file, cfg->mtime, statbuf.st_mtime);
  -    
  -    jk2_map_default_create(env, &cfg->cfgData, env->tmpPool);
  -
  -    rc=jk2_map_read(env, cfg->cfgData , cfg->file );
  -    
  -    if( rc==JK_OK ) {
  -        env->l->jkLog(env, env->l, JK_LOG_INFO, 
  -                      "config.setConfig():  Reading properties %s %d\n",
  -                      cfg->file, cfg->cfgData->size( env, cfg->cfgData ) );
  -    } else {
  -        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                      "config.setConfig(): Error reading properties %s\n",
  -                      cfg->file );
  -        JK_LEAVE_CS(&cfg->cs, csOk);
  -        return JK_ERR;
  -    }
  -    
  -    rc=jk2_config_processConfigData( env, cfg, firstTime );
  -
  -    if( didReload!=NULL )
  -        *didReload=JK_TRUE;
  -    
  -    cfg->mtime= statbuf.st_mtime;
  -
  -    JK_LEAVE_CS(&cfg->cs, csOk);
  -    return rc;
  -}
  -
  -
  -static int jk2_config_update(jk_env_t *env,
  -                             jk_config_t *cfg, int *didReload)
  -{
  -    return jk2_config_readFile( env, cfg, didReload, JK_FALSE );
  -}
  -
  -/** Set a property for this config object
  - */
  -static int JK_METHOD 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, "debugEnv" )==0 ) {
  -        env->debug=atoi( value );
  -    } else if( strcmp( name, "save" )==0 ) {
  -        /* Experimental. Setting save='foo' will save the current config in
  -           foo
  -        */
  -        return jk2_config_saveConfig(env, cfg, value);
  -    } else {
  -        return JK_ERR;
  -    }
  -    return JK_OK;
  -}
  -
  -
  -int JK_METHOD jk2_config_factory( jk_env_t *env, jk_pool_t *pool,
  -                        jk_bean_t *result,
  -                        const char *type, const char *name)
  -{
  -    jk_config_t *_this;
  -    int i;
  -
  -    _this=(jk_config_t *)pool->alloc(env, pool, sizeof(jk_config_t));
  -    if( _this == NULL )
  -        return JK_ERR;
  -    _this->pool = pool;
  -
  -    _this->setPropertyString=jk2_config_setPropertyString;
  -    _this->update=jk2_config_update;
  -    _this->setProperty=jk2_config_setProperty;
  -    _this->save=jk2_config_saveConfig;
  -    _this->mbean=result;
  -    _this->processNode=jk2_config_processNode;
  -    _this->ver=0;
  -
  -    result->object=_this;
  -    result->setAttribute=jk2_config_setAttribute;
  -
  -    JK_INIT_CS(&(_this->cs), i);
  -    if (!i) {
  -        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  -                      "config.factory(): Can't init CS\n");
  -        return JK_ERR;
  -    }
  -
  -    
       return JK_OK;
   }
  
  
  
  1.20      +49 -194   jakarta-tomcat-connectors/jk/native2/common/jk_map.c
  
  Index: jk_map.c
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/common/jk_map.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- jk_map.c	18 May 2002 22:34:01 -0000	1.19
  +++ jk_map.c	31 May 2002 18:05:29 -0000	1.20
  @@ -58,7 +58,7 @@
   /***************************************************************************
    * Description: General purpose map object                                 *
    * Author:      Gal Shachor <sh...@il.ibm.com>                           *
  - * Version:     $Revision: 1.19 $                                           *
  + * Version:     $Revision: 1.20 $                                           *
    ***************************************************************************/
   
   #include "jk_global.h"
  @@ -77,11 +77,6 @@
       int size;
   } jk_map_private_t;
   
  -static int  jk2_map_default_realloc(jk_env_t *env, jk_map_t *m);
  -
  -
  -
  -
   static void *jk2_map_default_get(jk_env_t *env, jk_map_t *m,
                                    const char *name)
   {
  @@ -101,6 +96,46 @@
       return NULL;
   }
   
  +/* Make space for more elements
  + */
  +static int jk2_map_default_realloc(jk_env_t *env, jk_map_t *m)
  +{
  +    jk_map_private_t *mPriv=m->_private;
  +    
  +    if(mPriv->size >= mPriv->capacity) {
  +        char **names;
  +        void **values;
  +        int  capacity = mPriv->capacity + CAPACITY_INC_SIZE;
  +
  +        names = (char **)m->pool->calloc(env, m->pool,
  +                                        sizeof(char *) * capacity);
  +        values = (void **)m->pool->calloc(env, m->pool,
  +                                         sizeof(void *) * capacity);
  +
  +        if( names== NULL || values==NULL ) {
  +            env->l->jkLog(env, env->l, JK_LOG_ERROR,
  +                          "map.realloc(): AllocationError\n");
  +            return JK_ERR;
  +        }
  +        m->keys=names;
  +        m->values=values;
  +
  +        if (mPriv->capacity && mPriv->names) 
  +            memcpy(names, mPriv->names, sizeof(char *) * mPriv->capacity);
  +        
  +        if (mPriv->capacity && mPriv->values)
  +            memcpy(values, mPriv->values, sizeof(void *) * mPriv->capacity);
  +        
  +        mPriv->names = ( char **)names;
  +        mPriv->values = ( void **)values;
  +        mPriv->capacity = capacity;
  +        
  +        return JK_OK;
  +    }
  +
  +    return JK_OK;
  +}
  +
   
   static int jk2_map_default_put(jk_env_t *env, jk_map_t *m,
                                  const char *name, void *value,
  @@ -243,146 +278,6 @@
   }
                                  
   
  -/* ==================== */
  -/*  Reading / parsing. 
  - */
  -
  -static void jk2_trim_prp_comment(char *prp)
  -{
  -    char *comment = strchr(prp, '#');
  -    if(comment) {
  -        *comment = '\0';
  -    }
  -}
  -
  -static int jk2_trim(char *s)
  -{
  -    int i;
  -
  -    for(i = strlen(s) - 1 ; (i >= 0) && isspace(s[i]) ;  i--)
  -        ;
  -    
  -    s[i + 1] = '\0';
  -    
  -    for(i = 0 ; ('\0' !=  s[i]) && isspace(s[i]) ; i++)
  -        ;
  -    
  -    if(i > 0) {
  -        strcpy(s, &s[i]);
  -    }
  -
  -    return strlen(s);
  -}
  -
  -
  -
  -int jk2_map_parseProperty(jk_env_t *env, jk_map_t *m, char **section, char *prp )
  -{
  -    int rc = JK_ERR;
  -    char *v;
  -    jk_map_t *prefNode=NULL;
  -
  -    jk2_trim_prp_comment(prp);
  -    
  -    if( jk2_trim(prp)==0 )
  -        return JK_OK;
  -
  -    /* Support windows-style 'sections' - for cleaner config
  -     */
  -    if( (prp[0] == '[') ) {
  -        v=strchr(prp, ']' );
  -        *v='\0';
  -        jk2_trim( v );
  -        prp++;
  -        
  -        *section=m->pool->pstrdup(env, m->pool, prp);
  -
  -        jk2_map_default_create( env, &prefNode, m->pool );
  -
  -        m->add( env, m, *section, prefNode);
  -
  -        return JK_OK;
  -    }
  -    
  -    v = strchr(prp, '=');
  -    if(v==NULL)
  -        return JK_OK;
  -        
  -    *v = '\0';
  -    v++;                        
  -
  -    if(strlen(v)==0 || strlen(prp)==0)
  -        return JK_OK;
  -
  -    if (*section!=NULL){
  -        prefNode=m->get( env, m, *section);
  -    }else{
  -        prefNode=m;
  -    }
  -    
  -    if( prefNode==NULL )
  -        return JK_ERR;
  -
  -    /* fprintf(stderr, "Adding [%s] %s=%s\n", cfg->section, prp, v ); */
  -    prefNode->add( env, prefNode, m->pool->pstrdup(env, m->pool, prp),
  -                   m->pool->pstrdup(env, m->pool, v));
  -
  -    return JK_OK;
  -}
  -
  -/** Read a query string into the map
  - */
  -int jk2_map_queryRead(jk_env_t *env, jk_map_t *m, const char *query)
  -{
  -    char *sep;
  -    char *value;
  -    char *qry=m->pool->pstrdup( env, m->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, m->pool->pstrdup( env, m->pool, qry ),
  -                m->pool->pstrdup( env, m->pool, value ));
  -        qry=sep;
  -    }
  -    return JK_OK;
  -}
  -
  -/** Read the config file
  - */
  -int jk2_map_read(jk_env_t *env, jk_map_t *m,const char *file)
  -{
  -    FILE *fp;
  -    char buf[LENGTH_OF_LINE + 1];            
  -    char *prp;
  -    char *section=NULL;
  -    if(m==NULL || file==NULL )
  -        return JK_ERR;
  -
  -    fp= fopen(file, "r");
  -        
  -    if(fp==NULL)
  -        return JK_ERR;
  -
  -    while(NULL != (prp = fgets(buf, LENGTH_OF_LINE, fp))) {
  -        jk2_map_parseProperty( env, m, &section, prp );
  -    }
  -
  -    fclose(fp);
  -    return JK_OK;
  -}
  -
   
   /* ==================== */
   /* Internal utils */
  @@ -393,15 +288,21 @@
       jk_map_t *_this;
       jk_map_private_t *mPriv;
   
  -    if( m== NULL )
  +    if( m== NULL ) {
  +        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  +                      "map.create(): NullPointerException\n");
           return JK_ERR;
  +    }
       
       _this=(jk_map_t *)pool->calloc(env, pool, sizeof(jk_map_t));
       mPriv=(jk_map_private_t *)pool->calloc(env, pool, sizeof(jk_map_private_t));
       *m=_this;
   
  -    if( _this == NULL || mPriv==NULL )
  +    if( _this == NULL || mPriv==NULL ) {
  +        env->l->jkLog(env, env->l, JK_LOG_ERROR,
  +                      "map.create(): AllocationError\n");
           return JK_ERR;
  +    }
       
       _this->pool = pool;
       _this->_private=mPriv;
  @@ -424,49 +325,3 @@
       return JK_OK;
   }
   
  -/* int map_free(jk_map_t **m) */
  -/* { */
  -/*     int rc = JK_ERR; */
  -
  -/*     if(m && *m) { */
  -/*         (*m)->pool->close((*m)->pool); */
  -/*         rc = JK_OK; */
  -/*         *m = NULL; */
  -/*     } */
  -/*     return rc; */
  -/* } */
  -
  -
  -static int jk2_map_default_realloc(jk_env_t *env, jk_map_t *m)
  -{
  -    jk_map_private_t *mPriv=m->_private;
  -    
  -    if(mPriv->size == mPriv->capacity) {
  -        char **names;
  -        void **values;
  -        int  capacity = mPriv->capacity + CAPACITY_INC_SIZE;
  -
  -        names = (char **)m->pool->calloc(env, m->pool,
  -                                        sizeof(char *) * capacity);
  -        values = (void **)m->pool->calloc(env, m->pool,
  -                                         sizeof(void *) * capacity);
  -
  -        m->keys=names;
  -        m->values=values;
  -        if(values && names) {
  -            if (mPriv->capacity && mPriv->names) 
  -                memcpy(names, mPriv->names, sizeof(char *) * mPriv->capacity);
  -
  -            if (mPriv->capacity && mPriv->values)
  -                memcpy(values, mPriv->values, sizeof(void *) * mPriv->capacity);
  -
  -            mPriv->names = ( char **)names;
  -            mPriv->values = ( void **)values;
  -            mPriv->capacity = capacity;
  -
  -            return JK_OK;
  -        }
  -    }
  -
  -    return JK_ERR;
  -}
  
  
  
  1.2       +3 -0      jakarta-tomcat-connectors/jk/native2/common/list.mk
  
  Index: list.mk
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/common/list.mk,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- list.mk	24 May 2002 07:18:31 -0000	1.1
  +++ list.mk	31 May 2002 18:05:29 -0000	1.2
  @@ -4,6 +4,7 @@
   ${JK}jk_channel_socket${OEXT}\
   ${JK}jk_channel_un${OEXT}\
   ${JK}jk_config${OEXT}\
  +${JK}jk_config_file${OEXT}\
   ${JK}jk_endpoint${OEXT}\
   ${JK}jk_env${OEXT}\
   ${JK}jk_handler_logon${OEXT}\
  @@ -13,6 +14,8 @@
   ${JK}jk_md5${OEXT}\
   ${JK}jk_msg_ajp${OEXT}\
   ${JK}jk_mutex${OEXT}\
  +${JK}jk_mutex_proc${OEXT}\
  +${JK}jk_mutex_thread${OEXT}\
   ${JK}jk_nwmain${OEXT}\
   ${JK}jk_objCache${OEXT}\
   ${JK}jk_pool${OEXT}\
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/native2/common/jk_config_file.c
  
  Index: jk_config_file.c
  ===================================================================
  /* ========================================================================= *
   *                                                                           *
   *                 The Apache Software License,  Version 1.1                 *
   *                                                                           *
   *          Copyright (c) 1999-2001 The Apache Software Foundation.          *
   *                           All rights reserved.                            *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * Redistribution and use in source and binary forms,  with or without modi- *
   * fication, are permitted provided that the following conditions are met:   *
   *                                                                           *
   * 1. Redistributions of source code  must retain the above copyright notice *
   *    notice, this list of conditions and the following disclaimer.          *
   *                                                                           *
   * 2. Redistributions  in binary  form  must  reproduce the  above copyright *
   *    notice,  this list of conditions  and the following  disclaimer in the *
   *    documentation and/or other materials provided with the distribution.   *
   *                                                                           *
   * 3. The end-user documentation  included with the redistribution,  if any, *
   *    must include the following acknowlegement:                             *
   *                                                                           *
   *       "This product includes  software developed  by the Apache  Software *
   *        Foundation <http://www.apache.org/>."                              *
   *                                                                           *
   *    Alternately, this acknowlegement may appear in the software itself, if *
   *    and wherever such third-party acknowlegements normally appear.         *
   *                                                                           *
   * 4. The names  "The  Jakarta  Project",  "Jk",  and  "Apache  Software     *
   *    Foundation"  must not be used  to endorse or promote  products derived *
   *    from this  software without  prior  written  permission.  For  written *
   *    permission, please contact <ap...@apache.org>.                        *
   *                                                                           *
   * 5. Products derived from this software may not be called "Apache" nor may *
   *    "Apache" appear in their names without prior written permission of the *
   *    Apache Software Foundation.                                            *
   *                                                                           *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
   * INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
   * AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
   * THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
   * DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
   * DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
   * OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
   * HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
   * STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
   * POSSIBILITY OF SUCH DAMAGE.                                               *
   *                                                                           *
   * ========================================================================= *
   *                                                                           *
   * This software  consists of voluntary  contributions made  by many indivi- *
   * duals on behalf of the  Apache Software Foundation.  For more information *
   * on the Apache Software Foundation, please see <http://www.apache.org/>.   *
   *                                                                           *
   * ========================================================================= */
  
  /**
   * Description: File based configuration.
   *
   * @author: Gal Shachor <sh...@il.ibm.com>                           
   * @author: Costin Manolache
   */
  
  #include "jk_global.h"
  #include "jk_map.h"
  #include "jk_pool.h"
  #include "jk_config.h"
  
  #define LENGTH_OF_LINE    (1024)
  
  /* 
   */
  static int jk2_config_file_saveConfig( jk_env_t *env,
                                         jk_config_t *cfg, char *workerFile )
  {
      FILE *fp;
      int i,j;
      
      if( workerFile==NULL )
          workerFile=cfg->file;
  
      if( workerFile== NULL )
          return JK_ERR;
      
      fp= fopen(workerFile, "w");
          
      if(fp==NULL)
          return JK_ERR;
  
      env->l->jkLog(env, env->l, JK_LOG_INFO,
                    "config.save(): Saving %s\n", workerFile );
      
      /* 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;
  
          if( strcmp( name, mbean->name ) != 0 ) {
              /* It's an alias. */
              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" ) != 0 ) {
                  fprintf( fp, "%s=%s\n",
                           pname,
                           mbean->settings->valueAt( env, mbean->settings, j));
              }
          }
          fprintf( fp, "\n" );
      }
      
      fclose(fp);
  
      return JK_OK;
  }
  
  /* ==================== */
  /*  Reading / parsing. 
   */
  
  static void jk2_trim_prp_comment(char *prp)
  {
      char *comment = strchr(prp, '#');
      if(comment) {
          *comment = '\0';
      }
  }
  
  static int jk2_trim(char *s)
  {
      int i;
  
      for(i = strlen(s) - 1 ; (i >= 0) && isspace(s[i]) ;  i--)
          ;
      
      s[i + 1] = '\0';
      
      for(i = 0 ; ('\0' !=  s[i]) && isspace(s[i]) ; i++)
          ;
      
      if(i > 0) {
          strcpy(s, &s[i]);
      }
  
      return strlen(s);
  }
  
  
  
  int jk2_config_file_parseProperty(jk_env_t *env, jk_map_t *m, char **section, char *prp )
  {
      int rc = JK_ERR;
      char *v;
      jk_map_t *prefNode=NULL;
  
      jk2_trim_prp_comment(prp);
      
      if( jk2_trim(prp)==0 )
          return JK_OK;
  
      /* Support windows-style 'sections' - for cleaner config
       */
      if( (prp[0] == '[') ) {
          v=strchr(prp, ']' );
          *v='\0';
          jk2_trim( v );
          prp++;
          
          *section=m->pool->pstrdup(env, m->pool, prp);
  
          jk2_map_default_create( env, &prefNode, m->pool );
  
          m->add( env, m, *section, prefNode);
  
          return JK_OK;
      }
      
      v = strchr(prp, '=');
      if(v==NULL)
          return JK_OK;
          
      *v = '\0';
      v++;                        
  
      if(strlen(v)==0 || strlen(prp)==0)
          return JK_OK;
  
      if (*section!=NULL){
          prefNode=m->get( env, m, *section);
      }else{
          prefNode=m;
      }
      
      if( prefNode==NULL )
          return JK_ERR;
  
      /* fprintf(stderr, "Adding [%s] %s=%s\n", cfg->section, prp, v ); */
      prefNode->add( env, prefNode, m->pool->pstrdup(env, m->pool, prp),
                     m->pool->pstrdup(env, m->pool, v));
  
      return JK_OK;
  }
  
  
  
  /** Read the config file
   */
  int jk2_config_file_read(jk_env_t *env, jk_map_t *m,const char *file)
  {
      FILE *fp;
      char buf[LENGTH_OF_LINE + 1];            
      char *prp;
      char *section=NULL;
      if(m==NULL || file==NULL )
          return JK_ERR;
  
      fp= fopen(file, "r");
          
      if(fp==NULL)
          return JK_ERR;
  
      while(NULL != (prp = fgets(buf, LENGTH_OF_LINE, fp))) {
          jk2_config_file_parseProperty( env, m, &section, prp );
      }
  
      fclose(fp);
      return JK_OK;
  }
  
  
  static int jk2_config_file_readFile(jk_env_t *env,
                                      jk_config_t *cfg,
                                      int *didReload, int firstTime)
  {
      int rc;
      int csOk;
      struct stat statbuf;
  
      if( didReload!=NULL )
          *didReload=JK_FALSE;
  
      if( cfg->file==NULL ) {
          env->l->jkLog(env, env->l, JK_LOG_ERROR,
                        "config.update(): No config file\n" );
          return JK_ERR;
      }
  
      rc=stat(cfg->file, &statbuf);
      if (rc == -1) {
          env->l->jkLog(env, env->l, JK_LOG_ERROR,
                        "config.update(): Can't find config file %s\n", cfg->file );
          return JK_ERR;
      }
      
      if( !firstTime && statbuf.st_mtime < cfg->mtime ) {
          if( cfg->mbean->debug > 0 )
              env->l->jkLog(env, env->l, JK_LOG_ERROR,
                            "config.update(): No reload needed %s %ld %ld\n", cfg->file,
                            cfg->mtime, statbuf.st_mtime );
          return JK_OK;
      }
  
      if( cfg->cs == NULL ) {
          jk_bean_t *jkb=env->createBean2(env, cfg->mbean->pool,"threadMutex", NULL);
          if( jkb != NULL && jkb->object != NULL ) {
              cfg->cs=jkb->object;
              jkb->init(env, jkb );
          }
      }
  
      if( cfg->cs != NULL ) 
          cfg->cs->lock( env, cfg->cs );
  
      /* Check if another thread has updated the config */
  
      rc=stat(cfg->file, &statbuf);
      if (rc == -1) {
          env->l->jkLog(env, env->l, JK_LOG_ERROR,
                        "config.update(): Can't find config file %s", cfg->file );
          if( cfg->cs != NULL ) 
              cfg->cs->unLock( env, cfg->cs );
          return JK_ERR;
      }
      
      if( ! firstTime && statbuf.st_mtime <= cfg->mtime ) {
          if( cfg->cs != NULL ) 
              cfg->cs->unLock( env, cfg->cs );
          return JK_OK;
      }
  
      env->l->jkLog(env, env->l, JK_LOG_INFO,
                    "cfg.update() Updating config %s %d %d\n",
                    cfg->file, cfg->mtime, statbuf.st_mtime);
  
      /** The map will be lost - all objects must be saved !
       */
      jk2_map_default_create(env, &cfg->cfgData, env->tmpPool);
  
      rc=jk2_config_file_read(env, cfg->cfgData , cfg->file );
      
      if( rc==JK_OK ) {
          env->l->jkLog(env, env->l, JK_LOG_INFO, 
                        "config.setConfig():  Reading properties %s %d\n",
                        cfg->file, cfg->cfgData->size( env, cfg->cfgData ) );
      } else {
          env->l->jkLog(env, env->l, JK_LOG_ERROR,
                        "config.setConfig(): Error reading properties %s\n",
                        cfg->file );
          if( cfg->cs != NULL ) 
              cfg->cs->unLock( env, cfg->cs );
          return JK_ERR;
      }
      
      rc=jk2_config_processConfigData( env, cfg, firstTime );
  
      if( didReload!=NULL )
          *didReload=JK_TRUE;
      
      cfg->mtime= statbuf.st_mtime;
  
      if( cfg->cs != NULL ) 
          cfg->cs->unLock( env, cfg->cs );
  
      return rc;
  }
  
  
  static int jk2_config_file_update(jk_env_t *env,
                               jk_config_t *cfg, int *didReload)
  {
      return jk2_config_file_readFile( env, cfg, didReload, JK_FALSE );
  }
  
  /** Set a property for this config object
   */
  static int JK_METHOD jk2_config_file_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 ) {
          cfg->file=value;
          return jk2_config_file_readFile( env, cfg, NULL, JK_TRUE );
      } else if( strcmp( name, "debugEnv" )==0 ) {
          env->debug=atoi( value );
      } else if( strcmp( name, "save" )==0 ) {
          return jk2_config_file_saveConfig(env, cfg, value);
      } else {
          return JK_ERR;
      }
      return JK_OK;
  }
  
  
  int JK_METHOD jk2_config_file_factory( jk_env_t *env, jk_pool_t *pool,
                          jk_bean_t *result,
                          const char *type, const char *name)
  {
      jk_config_t *_this;
      jk_bean_t *jkb;
      int i;
  
      _this=(jk_config_t *)pool->alloc(env, pool, sizeof(jk_config_t));
      if( _this == NULL )
          return JK_ERR;
  
      _this->pool = pool;
      _this->ver=0;
  
      _this->setPropertyString=jk2_config_setPropertyString;
      _this->setProperty=jk2_config_setProperty;
      _this->processNode=jk2_config_processNode;
  
      _this->cs=NULL;
      
      _this->update=jk2_config_file_update;
      _this->save=jk2_config_file_saveConfig;
  
      result->object=_this;
      result->setAttribute=jk2_config_file_setAttribute;
      _this->mbean=result;
  
      return JK_OK;
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>