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/03/18 19:26:15 UTC

cvs commit: jakarta-tomcat-connectors/jk/native2/common jk_config.c

costin      02/03/18 10:26:15

  Added:       jk/native2/common jk_config.c
  Log:
  The initial jk_config implementation.
  
  Based on code from jk_map ( reading config file from properties ), jk_workerEnv
  ( setting properties of various components - abstracted using jk_bean )
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-connectors/jk/native2/common/jk_config.c
  
  Index: jk_config.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: General purpose config object                                 *
   * Author:      Gal Shachor <sh...@il.ibm.com>                           *
   * Version:     $Revision: 1.1 $                                           *
   ***************************************************************************/
  
  #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 void jk2_trim_prp_comment(char *prp);
  static int  jk2_trim(char *s);
  static char **jk2_config_getValues(jk_env_t *env, jk_config_t *m,
                                     struct jk_pool *resultPool,
                                     char *name,
                                     char *sep,
                                     int *countP);
  
  
  /* ==================== Backward compatibility ==================== */
  
  static int jk2_config_setWorkerFile( jk_env_t *env,
                                       jk_config_t *cfg,
                                       jk_workerEnv_t *wEnv,
                                       char *workerFile)
  {
      struct stat statbuf;
      int err;
      jk_map_t *props;
      int i;
      
      /* We should make it relative to JK_HOME or absolute path.
         ap_server_root_relative(cmd->pool,opt); */
      
      /* Avoid recursivity */
      for( i=0; i<cfg->map->size( env, cfg->map ); i++ ) {
          char *name=cfg->map->nameAt(env, cfg->map, i);
          char *val=cfg->map->valueAt(env, cfg->map, i);
          if( strcmp( name, "workerFile" )==0 &&
              strcmp( val, workerFile ) == 0 ) {
              env->l->jkLog(env, env->l, JK_LOG_ERROR,
                            "Recursive init - already read %s", workerFile );
              return JK_FALSE;
          }
      }
  
      if (stat(workerFile, &statbuf) == -1) {
          env->l->jkLog(env, env->l, JK_LOG_ERROR,
                        "Can't find the workers file %s", workerFile );
          return JK_FALSE;
      }
      
      /** Read worker files
       */
      env->l->jkLog(env, env->l, JK_LOG_DEBUG, "Reading properties %s %d\n",
                    workerFile, cfg->map->size(env, cfg->map) );
      
      jk2_map_default_create(env, &props, wEnv->pool);
      
      err=jk2_config_read(env, cfg, props, workerFile );
      
      if( err==JK_TRUE ) {
          env->l->jkLog(env, env->l, JK_LOG_INFO, 
                        "mod_jk.initJk() Reading worker properties %s %d\n",
                        workerFile, props->size( env, props ) );
      } else {
          env->l->jkLog(env, env->l, JK_LOG_ERROR,
                        "mod_jk.initJk() Error reading worker properties %s\n",
                        workerFile );
          return JK_FALSE;
      }
  
      for( i=0; i<props->size( env, props); i++ ) {
          char *name=props->nameAt(env, props, i);
          char *val=props->valueAt(env, props, i);
  
          cfg->setPropertyString( env, cfg, name, val );
      }
      
      return JK_TRUE;
  }
  
  
  static int jk2_config_setLogLevel( struct jk_env *env,
                                     char *level)
  {
      if(0 == strcasecmp(level, JK_LOG_INFO_VERB)) {
          env->l->level=JK_LOG_INFO_LEVEL;
      }
      if(0 == strcasecmp(level, JK_LOG_DEBUG_VERB)) {
          env->l->level=JK_LOG_DEBUG_LEVEL;
      }
      fprintf( stderr, "Setting %s %d \n", level, env->l->level );
      return JK_TRUE;
  }
  
  /* Backward compatiblity ? This is not used in jk2, all workers are loaded
   */
  static int jk2_config_setWorkerList( struct jk_env *env,
                                       struct jk_workerEnv *wEnv,
                                       char *wlist)
  {
      wEnv->worker_list=jk2_config_split( env, wEnv->pool,
                                          wlist, NULL, & wEnv->declared_workers );
  }
  
  /** Backward compat
        host:port/path=worker
   */
  static int jk2_config_setUriProperty( jk_env_t *env,
                                        jk_config_t *cfg,
                                        char *name, char *val)
  
  {
      /* only /path supported for now */
      jk_pool_t *workerPool=cfg->pool->create(env, cfg->pool, HUGE_POOL_SIZE);
      
      env->createInstance( env, workerPool, "uri", name );
      return JK_TRUE;
  }
  
  static int jk2_config_setWorkerProperty( jk_env_t *env,
                                          jk_config_t *cfg,
                                          char *name, char *val)
  
  {
      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= rindex( objName, (int)'.' );
  
      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 );
  
      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;
          } 
          
          workerPool=cfg->pool->create(env, cfg->pool, HUGE_POOL_SIZE);
          
          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 ) {
              env->l->jkLog(env, env->l, JK_LOG_ERROR,
                            "Error creating  %s %s\n", objName, type);
          }
      }
  
      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 );
      }
  
      return JK_FALSE;
  }
  
  
  static int jk2_config_setProperty(jk_env_t *env, jk_config_t *cfg,
                                    jk_bean_t *mbean, const 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 );
      
      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 );
  }
  
  static int jk2_config_setPropertyString(jk_env_t *env, jk_config_t *cfg,
                                            const char *name, char *value)
  {
      jk_bean_t *mbean;
  
      jk_workerEnv_t *wEnv=cfg->workerEnv;
      jk_map_t *initData=cfg->map;
      int status;
  
      value = jk2_config_replaceProperties(env, initData, initData->pool, value);
  
      if( strcmp( name, "workerFile" ) == 0 ) {
          return jk2_config_setWorkerFile(env, cfg, wEnv, value);
      } else if( strcmp( name, "logLevel") == 0 ) {
          return jk2_config_setLogLevel( env, value );
          /* XXX other special cases, backward compat, /, etc */
      }
      
      /* Default format */
      status=jk2_config_setWorkerProperty(env, cfg, name, value );
      if( status==JK_TRUE ) return status;
  
      /* It may be a 'normal' property */
      cfg->map->add( env, cfg->map, name, value );
      return JK_TRUE;
  }
  
  
  static char *jk2_config_getString(jk_env_t *env, jk_config_t *conf,
                                    const char *name, char *def)
  {
      char *val= conf->map->get( env, conf->map, name );
      if( val==NULL )
          return def;
      return val;
  }
  
  static int jk2_config_getBool(jk_env_t *env, jk_config_t *conf,
                                const char *prop, const char *def)
  {
      char *val=jk2_config_getString( env, conf, prop, (char *)def );
  
      if( val==NULL )
          return JK_FALSE;
  
      if( strcmp( val, "1" ) == 0 ||
          strcasecmp( val, "TRUE" ) == 0 ||
          strcasecmp( val, "ON" ) == 0 ) {
          return JK_TRUE;
      }
      return JK_FALSE;
  }
  
  /** Get a string property, using the worker's style
      for properties.
      Example worker.ajp13.host=localhost.
  */
  static char *jk2_config_getStrProp(jk_env_t *env, jk_config_t *conf,
                                     const char *objType, const char *objName,
                                     const char *pname, char *def)
  {
      char buf[1024];
      char *res;
  
      if(  objName==NULL || pname==NULL ) {
          return def;
      }
      if( objType==NULL ) 
          sprintf(buf, "%s.%s", objName, pname);
      else
          sprintf(buf, "%s.%s.%s", objType, objName, pname);
      res = jk2_config_getString(env, conf, buf, def );
      return res;
  }
  
  
  static int jk2_config_getIntProp(jk_env_t *env, jk_config_t *conf,
                         const char *objType, const char *objName,
                         const char *pname, int def)
  {
      char *val=jk2_config_getStrProp( env, conf, objType, objName, pname, NULL );
  
      if( val==NULL )
          return def;
  
      return jk2_config_str2int( env, val );
  }
  
  /* ==================== */
  /* Conversions */
  
  /* Convert a string to int, using 'M', 'K' suffixes
   */
  int jk2_config_str2int(jk_env_t *env, char *val )
  {   /* map2int:
         char *v=getString();
         return (c==NULL) ? def : str2int( v );
      */ 
      int  len;
      int  int_res;
      char org='\0';
      int  multit = 1;
      char *lastchar;
  
      if( val==NULL ) return 0;
      
      /* sprintf(buf, "%d", def); */
      /* rc = map_get_string(m, name, buf); */
  
      len = strlen(val);
      if(len==0)
          return 0;
      
      lastchar = val + len - 1;
      if('m' == *lastchar || 'M' == *lastchar) {
          org=*lastchar;
          *lastchar = '\0';
          multit = 1024 * 1024;
      } else if('k' == *lastchar || 'K' == *lastchar) {
          org=*lastchar;
          *lastchar = '\0';
          multit = 1024;
      }
  
      int_res = atoi(val);
      if( org!='\0' )
          *lastchar=org;
  
      return int_res * multit;
  }
  
  
  char **jk2_config_split(jk_env_t *env, jk_pool_t *pool,
                          const char *listStr, const char *sep,
                          unsigned *list_len )
  {
      char **ar = NULL;
      unsigned capacity = 0;
      unsigned idex = 0;    
      char *v;
      char *l;
  
      if( sep==NULL )
          sep=" \t,*";
      
      if( list_len != NULL )
          *list_len = 0;
  
      if(listStr==NULL)
          return NULL;
  
      v = pool->pstrdup( env, pool, listStr);
      
      if(v==NULL) {
          return NULL;
      }
  
      /*
       * GS, in addition to VG's patch, we now need to 
       * strtok also by a "*"
       */
  
      /* Not thread safe */
      for(l = strtok(v, sep) ; l ; l = strtok(NULL, sep)) {
          /* We want at least one space after idex for the null*/
          if(idex+1 >= capacity) {
              ar = pool->realloc(env, pool, 
                                 sizeof(char *) * (capacity + 5),
                                 ar,
                                 sizeof(char *) * capacity);
              if(!ar) {
                  return NULL;
              }
              capacity += 5;
          }
          ar[idex] = pool->pstrdup(env, pool, l);
          idex ++;
      }
  
      /* Append a NULL, we have space */
      ar[idex]=NULL;
  
      if( list_len != NULL )
          *list_len = idex;
  
      return ar;
  }
  
  
  /* ==================== */
  /*  Reading / parsing */
  
  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;
      char *v;
          
      if(m==NULL || f==NULL )
          return JK_FALSE;
  
      fp= fopen(f, "r");
          
      if(fp==NULL)
          return JK_FALSE;
  
      rc = JK_TRUE;
  
      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));
      }
  
      fclose(fp);
      return rc;
  }
  
  /** For multi-value properties, return the concatenation
   *  of all values.
   *
   * @param sep Separators used to separate multi-values and
   *       when concatenating the values, NULL for none. The first
   *       char will be used on the result, the other will be
   *       used to split. ( i.e. the map may either have multiple
   *       values or values separated by one of the sep's chars )
   *    
   */
  static char *jk2_config_getValuesString(jk_env_t *env, jk_config_t *m,
                                       struct jk_pool *resultPool,
                                       char *name,
                                       char *sep )
  {
      char **values;
      int valuesCount;
      int i;
      int len=0;
      int pos=0;
      int sepLen=0;
      char *result;
      char sepStr[2];
      
      if(sep==NULL)
          values=jk2_config_getValues( env, m, resultPool, name," \t,*", &valuesCount );
      else
          values=jk2_config_getValues( env, m, resultPool, name, sep, &valuesCount );
  
      if( values==NULL ) return NULL;
      if( valuesCount<=0 ) return NULL;
  
      if( sep!= NULL )
          sepLen=strlen( sep );
  
      for( i=0; i< valuesCount; i++ ) {
          len+=strlen( values[i] );
          if( sep!= NULL )
              len+=1; /* Separator */
      }
  
      result=(char *)resultPool->alloc( env, resultPool, len + 1 );
  
      result[0]='\0';
      if( sep!=NULL ) {
          sepStr[0]=sep[0];
          sepStr[1]='\0';
      }
      
      for( i=0; i< valuesCount; i++ ) {
          strcat( values[i], result );
          if( sep!=NULL )
              strcat( sepStr, result );
      }
      return result;
  }
  
  /** For multi-value properties, return the array containing
   * all values.
   *
   * @param sep Optional separator, it'll be used to split existing values.
   *            Curently only single-char separators are supported. 
   */
  static char **jk2_config_getValues(jk_env_t *env, jk_config_t *m,
                                  struct jk_pool *resultPool,
                                  char *name,
                                  char *sep,
                                  int *countP)
  {
      char **result;
      int count=0;
      int capacity=8;
      int mapSz= m->map->size(env, m->map );
      int i;
      char *l;
  
      *countP=0;
      result=(char **)resultPool->alloc( env, resultPool,
                                         capacity * sizeof( char *));
      for(i=0; i<mapSz; i++ ) {
          char *cName= m->map->nameAt( env, m->map, i );
          char *cVal= m->map->valueAt( env, m->map, i );
  
          if(0 == strcmp(cName, name)) {
              /* Split the value by sep, and add it to the result list
               */
              for(l = strtok(cVal, sep) ; l ; l = strtok(NULL, sep)) {
                  if(count == capacity) {
                      result = resultPool->realloc(env, resultPool, 
                                                   sizeof(char *) * (capacity + 5),
                                                   result,
                                                   sizeof(char *) * capacity);
                      if(result==NULL) 
                          return NULL;
                      capacity += 5;
                  }
                  result[count] = resultPool->pstrdup(env, resultPool, l);
                  count++;
              }
          }
      }
      *countP=count;
      return result;
  }
                                 
  
  /**
   *  Replace $(property) in value.
   * 
   */
  char *jk2_config_replaceProperties(jk_env_t *env, jk_map_t *m,
                                     struct jk_pool *resultPool, 
                                     char *value)
  {
      char *rc = value;
      char *env_start = rc;
      int rec = 0;
  
      while(env_start = strstr(env_start, "$(")) {
          char *env_end = strstr(env_start, ")");
          if( rec++ > 20 ) return rc;
          if(env_end) {
              char env_name[LENGTH_OF_LINE + 1] = ""; 
              char *env_value;
  
              *env_end = '\0';
              strcpy(env_name, env_start + 2);
              *env_end = ')';
  
              env_value = m->get(env, m, env_name);
  	    if(env_value == NULL ) {
  	      env_value=getenv( env_name );
  	    }
              /* fprintf(stderr, "XXXjk_map %s %s \n", env_name, env_value ); */
  
              if(env_value != NULL ) {
                  int offset=0;
                  char *new_value = resultPool->alloc(env, resultPool, 
                                                      (strlen(rc) + strlen(env_value)));
                  if(!new_value) {
                      break;
                  }
                  *env_start = '\0';
                  strcpy(new_value, rc);
                  strcat(new_value, env_value);
                  strcat(new_value, env_end + 1);
  		offset= env_start - rc + strlen( env_value );
                  rc = new_value;
  		/* Avoid recursive subst */
                  env_start = rc + offset; 
              } else {
                  env_start = env_end;
              }
          } else {
              break;
          }
      }
  
      return rc;
  }
  
  
  
  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_factory( jk_env_t *env, jk_pool_t *pool,
                          jk_bean_t *result,
                          const char *type, const char *name)
  {
      jk_config_t *_this;
  
      _this=(jk_config_t *)pool->alloc(env, pool, sizeof(jk_config_t));
      if( _this == NULL )
          return JK_FALSE;
      _this->pool = pool;
  
      _this->setPropertyString=jk2_config_setPropertyString;
      _this->setProperty=jk2_config_setProperty;
      
      result->object=_this;
  
      
      return JK_TRUE;
  }
  
  
  

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