blob: 207897f244249d1c01233fd9cd2d73d4ba58b073 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "jk_global.h"
#include "jk_env.h"
#include "jk_objCache.h"
jk_env_t *jk_env_globalEnv;
void *jkGlobalAprPool = NULL;
/* Private methods
*/
static void jk2_env_initEnv(jk_env_t *env, char *id);
/* We should have one env per thread to avoid sync problems.
The env provides access to tmp pools, exception
*/
/* -------------------- Env management -------------------- */
static void *JK_METHOD jk2_env_getAprPool(jk_env_t *env)
{
/* We don't want to have to recreate the scoreboard after
* restarts, so we'll create a global pool and never clean it.
*/
if (jkGlobalAprPool == NULL) {
int rc;
rc = apr_pool_create((apr_pool_t **) & jkGlobalAprPool, NULL);
if (rc != APR_SUCCESS || jkGlobalAprPool == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"Unable to create global apr pool\n");
return NULL;
}
}
return jkGlobalAprPool;
}
void JK_METHOD jk2_env_setAprPool(jk_env_t *env, void *aprPool)
{
jkGlobalAprPool = aprPool;
}
/** Public method, creates/get the global env
*/
jk_env_t *JK_METHOD jk2_env_getEnv(char *id, jk_pool_t *pool)
{
if (jk_env_globalEnv == NULL) {
if (pool == NULL)
return NULL;
jk_env_globalEnv =
(jk_env_t *)pool->calloc(NULL, pool, sizeof(jk_env_t));
jk_env_globalEnv->globalPool = pool;
jk2_env_initEnv((jk_env_t *)jk_env_globalEnv, id);
/* fprintf( stderr, "env: top level env %#lx\n", jk_env_globalEnv); */
}
return jk_env_globalEnv;
}
/** Get a local env - either a new one or a recycled one
* XXX Try TLD too
*/
static jk_env_t *JK_METHOD jk2_env_get(jk_env_t *parentEnv)
{
jk_env_t *env =
(jk_env_t *)parentEnv->envCache->get(parentEnv, parentEnv->envCache);
if (env == NULL) {
jk_pool_t *parentPool = parentEnv->globalPool;
env =
(jk_env_t *)parentPool->calloc(parentEnv, parentPool,
sizeof(jk_env_t));
env->tmpPool =
parentPool->create(parentEnv, parentPool, HUGE_POOL_SIZE);
env->registerFactory = parentEnv->registerFactory;
env->getByName = parentEnv->getByName;
env->getByName2 = parentEnv->getByName2;
env->getBean2 = parentEnv->getBean2;
env->getBean = parentEnv->getBean;
env->alias = parentEnv->alias;
env->createBean2 = parentEnv->createBean2;
env->createBean = parentEnv->createBean;
env->getEnv = parentEnv->getEnv;
env->releaseEnv = parentEnv->releaseEnv;
env->jkClearException = parentEnv->jkClearException;
env->jkException = parentEnv->jkException;
env->getAprPool = parentEnv->getAprPool;
env->setAprPool = parentEnv->setAprPool;
env->_registry = parentEnv->_registry;
env->_objects = parentEnv->_objects;
env->l = parentEnv->l;
env->globalPool = parentEnv->globalPool;
env->envCache = parentEnv->envCache;
env->debug = parentEnv->debug;
env->soName = parentEnv->soName;
if (env->debug > 0) {
if (env->l == NULL)
fprintf(stderr, "env:Create child env %#lx %#lx\n", parentEnv,
env);
else
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env:Create child env %#lx %#lx\n", parentEnv,
env);
}
}
return env;
}
/** Release the env ( clean and recycle )
*/
static int JK_METHOD jk2_env_recycleEnv(jk_env_t *env)
{
env->tmpPool->reset(env, env->tmpPool);
env->jkClearException(env);
return JK_OK;
}
/** Release the env ( clean and recycle )
*/
static int JK_METHOD jk2_env_put(jk_env_t *parent, jk_env_t *chld)
{
jk2_env_recycleEnv(chld);
return parent->envCache->put(parent, parent->envCache, chld);
}
/* -------------------- Object management -------------------- */
/** Create a jk component, using only the name.
* Now things are simpler - the 'type' is the prefix, separated by ':' - no
* guessing involved.
*/
static jk_bean_t *jk2_env_createBean(jk_env_t *env, jk_pool_t *pool,
char *objName)
{
char *type = NULL;
/* void *obj; */
char *localName;
localName = strchr(objName, ':');
if (localName == NULL) {
type = objName;
}
else {
/* Funny pointer arithmetic. I hope I got it right */
type =
env->tmpPool->calloc(env, env->tmpPool, localName - objName + 2);
strncpy(type, objName, localName - objName);
localName++;
}
return env->createBean2(env, pool, type, localName);
}
/** Create a component using type and local part ( pre-cooked ).
*/
static jk_bean_t *jk2_env_createBean2(jk_env_t *env, jk_pool_t *pool,
char *type, char *localName)
{
jk_env_objectFactory_t fac;
jk_bean_t *result = NULL;
jk_pool_t *workerPool;
char *name;
int i;
if (localName != NULL)
result = env->getBean2(env, type, localName);
if (result != NULL)
return result;
if (pool == NULL) {
pool = env->globalPool;
}
if (type == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"env.createBean2(): NullPointerException\n");
return NULL;
}
if (strcmp("disabled", type) == 0) {
return NULL;
}
/* if( localName!=NULL && strncmp( localName, type, strlen( type )) == 0 ) { */
/* Common error, make it 'localName' */
/* if( strcmp( type, localName ) == 0 ) { */
/* localName=""; */
/* } else { */
/* localName= localName + strlen(type) + 1; */
/* } */
/* } */
if (env->debug > 0) {
if (env->l != NULL) {
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env.createBean2(): Create [%s] %s\n", type,
localName);
}
else {
fprintf(stderr, "env.createBean2(): Create [%s] %s\n", type,
localName);
}
}
fac =
(jk_env_objectFactory_t) env->_registry->get(env, env->_registry,
type);
if (fac == NULL) {
if (env->l) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"env.createBean2(): Error getting factory for [%s] %s\n",
type, localName);
}
else {
fprintf(stderr, "Error getting factory for %s \n", type);
}
return NULL;
}
workerPool = pool->create(env, pool, HUGE_POOL_SIZE);
/** Generate a unique name if none is specified
*/
if (localName == NULL) {
localName = workerPool->calloc(env, workerPool, 10);
sprintf((char *)localName, "%d", jk_env_globalEnv->id++);
}
name =
workerPool->calloc(env, workerPool,
strlen(type) + strlen(localName) + 2);
strcpy(name, type);
strcat(name, ":");
strcat(name, localName);
result =
(jk_bean_t *)workerPool->calloc(env, workerPool, sizeof(jk_bean_t));
result->pool = workerPool;
result->type = workerPool->pstrdup(env, workerPool, type);
result->name = workerPool->pstrdup(env, workerPool, name);
result->localName = workerPool->pstrdup(env, workerPool, localName);
result->debug = 0;
result->state = JK_STATE_NEW;
result->disabled = JK_FALSE;
result->settings = NULL;
result->getAttributeInfo = NULL;
result->setAttributeInfo = NULL;
fac(env, workerPool, result, result->type, result->name);
if (result->object == NULL) {
if (env->l) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"env.createBean2(): Factory error creating %s ( %s, %s)\n",
name, type, localName);
}
else {
fprintf(stderr,
"env.createBean2(): Factory error creating %s ( %s, %s)\n",
name, type, localName);
}
return NULL;
}
if (env->debug > 0) {
if (env->l == NULL)
fprintf(stderr, "env.createBean2(): register %s %#lx\n",
result->name, result->object);
else
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env.createBean2(): register %s %#lx\n",
result->name, result->object);
}
jk_env_globalEnv->_objects->put(env, jk_env_globalEnv->_objects,
result->name, result, NULL);
for (i =
jk_env_globalEnv->_objects->size(env,
jk_env_globalEnv->_objects) - 1;
i >= 0; i--) {
if (jk_env_globalEnv->_objects->
valueAt(env, jk_env_globalEnv->_objects, i) == result) {
result->objId = i;
break;
}
}
if (strcmp(localName, "") == 0) {
/* "" for local name is used as 'default'. Allow "type" as an alias for "type:"
*/
jk_env_globalEnv->_objects->put(env, jk_env_globalEnv->_objects,
result->type, result, NULL);
}
return result;
}
/** Define an alias, for simpler config / less typing
*/
static void JK_METHOD jk2_env_alias(jk_env_t *env, const char *name,
const char *alias)
{
jk_bean_t *jkb = env->getBean(env, name);
if (jkb == NULL) {
if (env->l == NULL) {
if (env->debug > 0)
fprintf(stderr, "env.alias(): Not found %s\n", name);
}
else {
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env.alias(): Not found %s\n", name);
}
return;
}
if (env->debug > 0) {
if (env->l == NULL)
fprintf(stderr, "env.alias(): alias %s %s\n", name, alias);
else
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env.alias(): alias %s %s\n", name, alias);
}
jk_env_globalEnv->_objects->put(env, jk_env_globalEnv->_objects, alias,
jkb, NULL);
}
/** Get the object by name. Returns the real object, not the wrapper
*/
static void *JK_METHOD jk2_env_getByName(jk_env_t *env, const char *name)
{
jk_bean_t *result = env->getBean(env, name);
if (result == NULL) {
if (env->debug > 0) {
if (env->l == NULL)
fprintf(stderr, "env.getByName(): Can't find %#lx %s\n", env,
name);
else
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env.getByName(): Can't find %#lx %s\n", env,
name);
}
return NULL;
}
if (env->debug > 0) {
if (env->l == NULL)
fprintf(stderr, "env.getByName(): Get by name %s %#lx\n", name,
result->object);
else
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"env.getByName(): Get by name %s %#lx\n", name,
result->object);
}
return result->object;
}
static void *JK_METHOD jk2_env_getByName2(jk_env_t *env, const char *type,
const char *localName)
{
jk_bean_t *result = env->getBean2(env, type, localName);
if (result == NULL)
return NULL;
return result->object;
}
/** Get the wrapper for the named object
*/
static jk_bean_t *JK_METHOD jk2_env_getBean(jk_env_t *env, const char *name)
{
if (name == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"env.getBean(): NullPointerException\n");
return NULL;
}
return (jk_bean_t *)env->_objects->get(env, env->_objects, name);
}
static jk_bean_t *JK_METHOD jk2_env_getBean2(jk_env_t *env, const char *type,
const char *localName)
{
char *name;
if (type == NULL || localName == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"env.getBean2(): NullPointerException\n");
return NULL;
}
name =
env->tmpPool->calloc(env, env->tmpPool,
strlen(type) + strlen(localName) + 2);
strcpy(name, type);
strcat(name, ":");
strcat(name, localName);
return (jk_bean_t *)env->_objects->get(env, env->_objects, name);
}
/** Register the type and the factory
*/
static void JK_METHOD jk2_env_registerFactory(jk_env_t *env,
const char *type,
jk_env_objectFactory_t fact)
{
if (type == NULL || fact == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"env.registerFactory(): NullPointerException\n");
return;
}
env->_registry->put(env, env->_registry, (char *)type, (void *)fact,
NULL);
}
/* -------------------- Exceptions -------------------- */
/* Exceptions.
*/
static void JK_METHOD jkThrow(jk_env_t *env,
const char *file, int line,
const char *type, const char *fmt, ...)
{
va_list args;
/* char *buf; */
va_start(args, fmt);
env->l->jkVLog(env, env->l, file, line, JK_LOG_ERROR_LEVEL, fmt, args);
va_end(args);
}
/** re-throw the exception and record the current pos.
* in the stack trace
* XXX Not implemented/not used
*/
static void JK_METHOD jkReThrow(jk_env_t *env, const char *file, int line)
{
/* Nothing yet. It should record the file/line for stack trace */
}
/* Last exception that occured
*/
static jk_exception_t *JK_METHOD jk_env_jkException(jk_env_t *env)
{
return env->lastException;
}
/** Clear the exception state
*/
static void JK_METHOD jk_env_jkClearException(jk_env_t *env)
{
env->lastException = NULL;
}
/* -------------------- Util -------------------- */
/* It should be in some util class */
char *JK_METHOD jk2_env_itoa(jk_env_t *env, int i)
{
char *buf = env->tmpPool->calloc(env, env->tmpPool, 20);
sprintf(buf, "%d", i);
return buf;
}
/* -------------------- Init method -------------------- */
static void jk2_env_initEnv(jk_env_t *env, char *id)
{
env->registerFactory = jk2_env_registerFactory;
env->getByName = jk2_env_getByName;
env->getByName2 = jk2_env_getByName2;
env->getBean = jk2_env_getBean;
env->getBean2 = jk2_env_getBean2;
env->createBean2 = jk2_env_createBean2;
env->createBean = jk2_env_createBean;
env->alias = jk2_env_alias;
env->getEnv = jk2_env_get;
env->recycleEnv = jk2_env_recycleEnv;
env->releaseEnv = jk2_env_put;
env->debug = 0;
env->jkClearException = jk_env_jkClearException;
env->jkException = jk_env_jkException;
env->getAprPool = jk2_env_getAprPool;
env->setAprPool = jk2_env_setAprPool;
env->id = 0;
jk2_map_default_create(env, &env->_registry, env->globalPool);
jk2_map_default_create(env, &env->_objects, env->globalPool);
env->tmpPool =
env->globalPool->create(env, env->globalPool, HUGE_POOL_SIZE);
jk2_registry_init(env);
env->envCache = jk2_objCache_create(env, env->globalPool);
env->envCache->init(env, env->envCache, 64);
env->envCache->maxSize = -1;
}