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>