
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "axis2_dep_engine.h"
#include <axutil_array_list.h>
#include <axis2_deployment.h>
#include <axutil_file_handler.h>
#include <axis2_flow.h>
#include <axis2_arch_reader.h>
#include <axis2_module_builder.h>
#include <axis2_svc_builder.h>
#include <axis2_svc_grp_builder.h>
#include <axiom_node.h>
#include <axutil_class_loader.h>
#include <axutil_string.h>
#include <axutil_utils.h>
#include <axis2_core_utils.h>
#include <axis2_module.h>

struct axis2_dep_engine
{
    axis2_arch_file_data_t *curr_file;
    axis2_arch_reader_t *arch_reader;

    /**
     * To keep a reference to engine configuration.
     * This reference will pass to engine when it call start()
     * function
     */
    axis2_conf_t *conf;
    axis2_char_t *axis2_repos;
    axis2_bool_t hot_dep;       /* to do hot deployment or not */
    axis2_bool_t hot_update;    /* to do hot update or not */
	
	/* Whether dep_engine built using axis2.xml */
	axis2_bool_t file_flag;

    /**
     * This will store all the web services to deploy
     */
    axutil_array_list_t *ws_to_deploy;

    /**
     * This will store all the web services to undeploy
     */
    axutil_array_list_t *ws_to_undeploy;
    axis2_phases_info_t *phases_info;   /* To store phases list in axis2.xml */

    axis2_char_t *folder_name;

	/**
	 * Module directory, dep_engine holds in the module build scenario.
	 */
	axis2_char_t *module_dir;

   /**
    * Services directory, services are avialble in services directory
    */

    axis2_char_t *svc_dir;
	
    /**
     * Full path to the server xml file(axis2.xml)
     */
    axis2_char_t *conf_name;

    /**
     * To store the module specified in the server.xml(axis2.xml) at the 
     * document parsing time
     */
    axutil_array_list_t *module_list;
    axis2_repos_listener_t *repos_listener; /*Added this here to help with freeing
                                              memory allocated for this - Samisa */
    axis2_conf_builder_t *conf_builder;
    axis2_svc_builder_t *svc_builder;
    axutil_array_list_t *desc_builders;
    axutil_array_list_t *module_builders;
    axutil_array_list_t *svc_builders;
    axutil_array_list_t *svc_grp_builders;
};

static axis2_status_t axis2_dep_engine_set_dep_features(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env);

static axis2_status_t axis2_dep_engine_check_client_home(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    const axis2_char_t * client_home);

static axis2_status_t axis2_dep_engine_engage_modules(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env);

static axis2_status_t axis2_dep_engine_validate_system_predefined_phases(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env);

static axis2_status_t axis2_dep_engine_add_new_svc(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_svc_grp_t * svc_metadata);

static axis2_status_t axis2_dep_engine_load_module_dll(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_module_desc_t * module_desc);

static axis2_status_t axis2_dep_engine_add_module_flow_handlers(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_flow_t * flow,
    axutil_hash_t * handler_create_func_map);

static axis2_status_t axis2_dep_engine_add_new_module(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_module_desc_t * module_metadata);

static axis2_char_t *axis2_dep_engine_get_axis_svc_name(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_char_t * file_name);

static axis2_status_t axis2_dep_engine_set_svc_and_module_dir_path (
    axis2_dep_engine_t *dep_engine,
    const axutil_env_t *env);

AXIS2_EXTERN axis2_dep_engine_t *AXIS2_CALL
axis2_dep_engine_create(
    const axutil_env_t * env)
{
    axis2_dep_engine_t *dep_engine = NULL;

    AXIS2_ENV_CHECK(env, NULL);

    dep_engine = (axis2_dep_engine_t *) AXIS2_MALLOC(env->allocator,
                                                     sizeof
                                                     (axis2_dep_engine_t));

    if (!dep_engine)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }
  	dep_engine = (axis2_dep_engine_t *) memset (dep_engine, 0, 
        sizeof (axis2_dep_engine_t));
    dep_engine->curr_file = NULL;
    dep_engine->arch_reader = NULL;
    dep_engine->conf = NULL;
    dep_engine->axis2_repos = NULL;
    dep_engine->ws_to_deploy = NULL;
    dep_engine->ws_to_undeploy = NULL;
    dep_engine->phases_info = NULL;
    dep_engine->folder_name = NULL;
    dep_engine->module_dir = NULL;
    dep_engine->svc_dir = NULL;
    dep_engine->conf_name = NULL;
    dep_engine->module_list = NULL;
    dep_engine->repos_listener = NULL;
    dep_engine->conf_builder = NULL;
    dep_engine->svc_builder = NULL;
    dep_engine->desc_builders = NULL;
    dep_engine->module_builders = NULL;
    dep_engine->svc_builders = NULL;
    dep_engine->svc_grp_builders = NULL;

    dep_engine->ws_to_deploy = axutil_array_list_create(env, 0);
    if (!(dep_engine->ws_to_deploy))
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }

    dep_engine->desc_builders = axutil_array_list_create(env, 0);
    dep_engine->module_builders = axutil_array_list_create(env, 0);
    dep_engine->svc_builders = axutil_array_list_create(env, 0);
    dep_engine->svc_grp_builders = axutil_array_list_create(env, 0);

    dep_engine->phases_info = axis2_phases_info_create(env);
    if (!(dep_engine->phases_info))
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }

    return dep_engine;
}

AXIS2_EXTERN axis2_dep_engine_t *AXIS2_CALL
axis2_dep_engine_create_with_repos_name(
    const axutil_env_t * env,
    const axis2_char_t * repos_path)
{
    axis2_dep_engine_t *dep_engine = NULL;

    AXIS2_ENV_CHECK(env, NULL);

    dep_engine = (axis2_dep_engine_t *) axis2_dep_engine_create_with_repos_name_and_svr_xml_file(env, 
            repos_path, AXIS2_SERVER_XML_FILE);

    if (!dep_engine)
    {
        return NULL;
    }

	dep_engine->file_flag = AXIS2_FALSE;

    return dep_engine;
}

AXIS2_EXTERN axis2_dep_engine_t *AXIS2_CALL
axis2_dep_engine_create_with_axis2_xml(
    const axutil_env_t * env,
    const axis2_char_t * axis2_xml)
{
    axis2_dep_engine_t *dep_engine = NULL;

    AXIS2_ENV_CHECK(env, NULL);

    dep_engine = (axis2_dep_engine_t *) axis2_dep_engine_create_with_svr_xml_file(env, axis2_xml);
    if (!dep_engine)
    {
        return NULL;
    }
	dep_engine->file_flag = AXIS2_TRUE;

    return dep_engine;
}


AXIS2_EXTERN axis2_dep_engine_t *AXIS2_CALL
axis2_dep_engine_create_with_repos_name_and_svr_xml_file(
    const axutil_env_t * env,
    const axis2_char_t * repos_path,
    const axis2_char_t * svr_xml_file)
{
    axis2_dep_engine_t *dep_engine = NULL;
    axis2_char_t *conf_file_l = NULL;
    axis2_status_t status = AXIS2_FAILURE;

    AXIS2_ENV_CHECK(env, NULL);
    AXIS2_PARAM_CHECK(env->error, repos_path, NULL);
    AXIS2_PARAM_CHECK(env->error, svr_xml_file, NULL);
    if (!axutil_strcmp("", repos_path))
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_REPO_CAN_NOT_BE_NULL, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Repository path cannot be empty");
        return NULL;
    }

    dep_engine = (axis2_dep_engine_t *) axis2_dep_engine_create(env);

    if (!dep_engine)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }

    status = axutil_file_handler_access(repos_path, AXIS2_F_OK);
    if (AXIS2_SUCCESS != status)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_REPOSITORY_NOT_EXIST, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Repository path %s does not exist", repos_path);
        return NULL;
    }

    dep_engine->folder_name = axutil_strdup(env, repos_path);
    if (!dep_engine->folder_name)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }

    dep_engine->axis2_repos = axutil_strdup(env, repos_path);
    if (!dep_engine->axis2_repos)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }

    conf_file_l = axutil_stracat(env, repos_path, AXIS2_PATH_SEP_STR);
    dep_engine->conf_name = axutil_stracat(env, conf_file_l, svr_xml_file);
	
    AXIS2_FREE(env->allocator, conf_file_l);
    if (!dep_engine->conf_name)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_REPO_CAN_NOT_BE_NULL, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Axis2 Configuration file name cannot be NULL");
        return NULL;
    }
	
    status = axutil_file_handler_access(dep_engine->conf_name, AXIS2_F_OK);
    if (AXIS2_SUCCESS != status)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_CONFIG_NOT_FOUND,
                        AXIS2_FAILURE);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Axis2 Configuration file name not found");
        return NULL;
    }

    return dep_engine;
}

AXIS2_EXTERN axis2_dep_engine_t *AXIS2_CALL
axis2_dep_engine_create_with_svr_xml_file(
    const axutil_env_t * env,
    const axis2_char_t * svr_xml_file)
{
    axis2_dep_engine_t *dep_engine = NULL;
    axis2_status_t status = AXIS2_FAILURE;

    AXIS2_ENV_CHECK(env, NULL);
    AXIS2_PARAM_CHECK(env->error, svr_xml_file, NULL);

    dep_engine = (axis2_dep_engine_t *) axis2_dep_engine_create(env);
	
    if (!dep_engine)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return NULL;
    }

    dep_engine->conf_name = axutil_strdup (env, (axis2_char_t *)svr_xml_file);
    if (!dep_engine->conf_name)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_REPO_CAN_NOT_BE_NULL, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Axis2 Configuration file name cannot be NULL");
        return NULL;
    }
    status = axutil_file_handler_access(dep_engine->conf_name, AXIS2_F_OK);
    if (AXIS2_SUCCESS != status)
    {
        axis2_dep_engine_free(dep_engine, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_CONFIG_NOT_FOUND, AXIS2_FAILURE);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Axis2 Configuration file name not found");
        return NULL;
    }

    return dep_engine;
}


AXIS2_EXTERN void AXIS2_CALL
axis2_dep_engine_free(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_ENV_CHECK(env, void);
    if (!dep_engine)
    {
        return;
    }

    if (dep_engine->curr_file)
    {
        axis2_arch_file_data_free(dep_engine->curr_file, env);
    }

    if (dep_engine->phases_info)
    {
        axis2_phases_info_free(dep_engine->phases_info, env);
    }

    if (dep_engine->conf_builder)
    {
        axis2_conf_builder_free(dep_engine->conf_builder, env);
    }

    if (dep_engine->arch_reader)
    {
        axis2_arch_reader_free(dep_engine->arch_reader, env);
    }

    if (dep_engine->svc_builder)
    {
        axis2_svc_builder_free(dep_engine->svc_builder, env);
    }

    if (dep_engine->ws_to_deploy)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(dep_engine->ws_to_deploy, env);
        for (i = 0; i < size; i++)
        {
            axis2_arch_file_data_t *file_data = NULL;

            file_data = (axis2_arch_file_data_t *) axutil_array_list_get(dep_engine->ws_to_deploy, 
                    env, i);

            axis2_arch_file_data_free(file_data, env);
        }

        axutil_array_list_free(dep_engine->ws_to_deploy, env);
        dep_engine->ws_to_deploy = NULL;
    }

    if (dep_engine->desc_builders)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(dep_engine->desc_builders, env);
        for (i = 0; i < size; i++)
        {
            axis2_desc_builder_t *desc_builder = NULL;

            desc_builder = (axis2_desc_builder_t *) axutil_array_list_get(dep_engine->desc_builders, 
                    env, i);

            axis2_desc_builder_free(desc_builder, env);
        }

        axutil_array_list_free(dep_engine->desc_builders, env);
    }

    if (dep_engine->module_builders)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(dep_engine->module_builders, env);
        for (i = 0; i < size; i++)
        {
            axis2_module_builder_t *module_builder = NULL;

            module_builder = (axis2_module_builder_t *) axutil_array_list_get(
                    dep_engine->module_builders, env, i);

            axis2_module_builder_free(module_builder, env);
        }

        axutil_array_list_free(dep_engine->module_builders, env);
    }

    if (dep_engine->svc_builders)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(dep_engine->svc_builders, env);
        for (i = 0; i < size; i++)
        {
            axis2_svc_builder_t *svc_builder = NULL;

            svc_builder = (axis2_svc_builder_t *) axutil_array_list_get(dep_engine->svc_builders, 
                    env, i);

            axis2_svc_builder_free(svc_builder, env);
        }

        axutil_array_list_free(dep_engine->svc_builders, env);
    }

    if (dep_engine->svc_grp_builders)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(dep_engine->svc_grp_builders, env);
        for (i = 0; i < size; i++)
        {
            axis2_svc_grp_builder_t *svc_grp_builder = NULL;

            svc_grp_builder = (axis2_svc_grp_builder_t *) axutil_array_list_get(
                    dep_engine->svc_grp_builders, env, i);

            axis2_svc_grp_builder_free(svc_grp_builder, env);
        }

        axutil_array_list_free(dep_engine->svc_grp_builders, env);
    }

    if (dep_engine->ws_to_undeploy)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(dep_engine->ws_to_undeploy, env);

        for (i = 0; i < size; i++)
        {
            axis2_arch_file_data_t *file_data = NULL;

            file_data = (axis2_arch_file_data_t *) axutil_array_list_get(dep_engine->ws_to_undeploy, 
                    env, i);

            axis2_arch_file_data_free(file_data, env);
        }

        axutil_array_list_free(dep_engine->ws_to_undeploy, env);
        dep_engine->ws_to_undeploy = NULL;
    }

    if (dep_engine->module_list)
    {
        int size = 0;
        int i = 0;

        size = axutil_array_list_size(dep_engine->module_list, env);

        for (i = 0; i < size; i++)
        {
            axutil_qname_t *qname = NULL;
            qname = axutil_array_list_get(dep_engine->module_list, env, i);
            if (qname)
            {
                axutil_qname_free(qname, env);
            }
        }

        axutil_array_list_free(dep_engine->module_list, env);
    }

    if (dep_engine->folder_name)
    {
        AXIS2_FREE(env->allocator, dep_engine->folder_name);
    }

    if (dep_engine->conf_name)
    {
        AXIS2_FREE(env->allocator, dep_engine->conf_name);
    }

    if (dep_engine->axis2_repos)
    {
        AXIS2_FREE(env->allocator, dep_engine->axis2_repos);
    }

    if (dep_engine->repos_listener)
    {
        axis2_repos_listener_free(dep_engine->repos_listener, env);
    }

    if (dep_engine)
    {
        AXIS2_FREE(env->allocator, dep_engine);
    }

    return;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_module(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axutil_qname_t * module_qname)
{
    axutil_qname_t *qname = NULL;

    AXIS2_PARAM_CHECK(env->error, module_qname, AXIS2_FAILURE);

    qname = axutil_qname_clone(module_qname, env);
    if (!dep_engine->module_list)
    {
        dep_engine->module_list = axutil_array_list_create(env, 0);
        if (!dep_engine->module_list)
        {
            axutil_qname_free(qname, env);
		    AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "No memory");
            return AXIS2_FAILURE;
        }
    }
    return axutil_array_list_add(dep_engine->module_list, env, qname);
}

struct axis2_module_desc *AXIS2_CALL
axis2_dep_engine_get_module(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axutil_qname_t * module_qname)
{
    AXIS2_PARAM_CHECK(env->error, module_qname, NULL);
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);

    return axis2_conf_get_module(dep_engine->conf, env, module_qname);
}

AXIS2_EXTERN struct axis2_arch_file_data *AXIS2_CALL
axis2_dep_engine_get_current_file_item(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);
    return dep_engine->curr_file;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_ws_to_deploy(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_arch_file_data_t * file)
{
    AXIS2_PARAM_CHECK(env->error, file, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    return axutil_array_list_add(dep_engine->ws_to_deploy, env, file);
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_ws_to_undeploy(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_ws_info_t * file)
{
    AXIS2_PARAM_CHECK(env->error, file, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    if (!(dep_engine->ws_to_undeploy))
    {
        dep_engine->ws_to_undeploy = axutil_array_list_create(env, 0);
    }
    return axutil_array_list_add(dep_engine->ws_to_undeploy, env, file);
}

AXIS2_EXTERN axis2_phases_info_t *AXIS2_CALL
axis2_dep_engine_get_phases_info(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);
    return dep_engine->phases_info;
}

AXIS2_EXTERN axis2_conf_t *AXIS2_CALL
axis2_dep_engine_get_axis_conf(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);
    return dep_engine->conf;
}

/**
 * To set hot deployment and hot update
 */
static axis2_status_t
axis2_dep_engine_set_dep_features(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    axis2_char_t *value = NULL;
    axutil_param_t *para_hot_dep = NULL;
    axutil_param_t *para_hot_update = NULL;

    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    para_hot_dep = axis2_conf_get_param(dep_engine->conf, env, AXIS2_HOTDEPLOYMENT);
    para_hot_update = axis2_conf_get_param(dep_engine->conf, env, AXIS2_HOTUPDATE);

    if (para_hot_dep)
    {
        value = (axis2_char_t *) axutil_param_get_value(para_hot_dep, env);
        if (0 == axutil_strcasecmp(AXIS2_VALUE_FALSE, value))
        {
            dep_engine->hot_dep = AXIS2_FALSE;
        }
    }

    if (para_hot_update)
    {
        value = (axis2_char_t *) axutil_param_get_value(para_hot_update, env);
        if (0 == axutil_strcasecmp(AXIS2_VALUE_FALSE, value))
        {
            dep_engine->hot_update = AXIS2_FALSE;
        }
    }

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_conf_t *AXIS2_CALL
axis2_dep_engine_load(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    axis2_status_t status = AXIS2_FAILURE;
    axutil_array_list_t *out_fault_phases = NULL;

    if (!dep_engine->conf_name)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_PATH_TO_CONFIG_CAN_NOT_BE_NULL, AXIS2_FAILURE);

		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
            "Path to axis2 configuration file is NULL. Unable to continue");

        return NULL;
    }

    dep_engine->conf = axis2_conf_create(env);

    if (!dep_engine->conf)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "No memory. Allocation to configuration failed");
        return NULL;
    }
	
	/* Set a flag to mark that conf is created using axis2 xml. To find out that conf is build using 
     * axis2 xml , this flag can be used.
	 */
	axis2_conf_set_axis2_flag (dep_engine->conf, env, dep_engine->file_flag);
	axis2_conf_set_axis2_xml (dep_engine->conf, env, dep_engine->conf_name);

    dep_engine->conf_builder = axis2_conf_builder_create_with_file_and_dep_engine_and_conf(env,
            dep_engine->conf_name, dep_engine, dep_engine->conf);

    if (!(dep_engine->conf_builder))
    {
        axis2_conf_free(dep_engine->conf, env);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Configuration builder creation failed");
        dep_engine->conf = NULL;
    }

    /* Populate the axis2 configuration from reading axis2.xml.
     */
    status = axis2_conf_builder_populate_conf(dep_engine->conf_builder, env);

    if (AXIS2_SUCCESS != status)
    {
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Populating Axis2 Configuration failed");
        return NULL;
    }

    status = axis2_dep_engine_set_svc_and_module_dir_path (dep_engine, env);
    if (AXIS2_SUCCESS != status)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Setting service and module directory paths failed");
        return NULL;
    }

    status = axis2_dep_engine_set_dep_features(dep_engine, env);
    if (AXIS2_SUCCESS != status)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Setting deployment features failed");
        return NULL;
    }

    if (dep_engine->repos_listener)
    {
        axis2_repos_listener_free(dep_engine->repos_listener, env);
    }
	
    dep_engine->repos_listener = axis2_repos_listener_create_with_folder_name_and_dep_engine(env, 
            dep_engine->folder_name, dep_engine);

    if (!dep_engine->repos_listener)
    {
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;

        AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
            "dep_engine repos listener creation failed, folder name is %s", dep_engine->folder_name);

        return NULL;
    }

    axis2_conf_set_repo(dep_engine->conf, env, dep_engine->axis2_repos);
    axis2_core_utils_calculate_default_module_version(env, axis2_conf_get_all_modules(
                dep_engine->conf, env), dep_engine->conf);

    status = axis2_dep_engine_validate_system_predefined_phases(dep_engine, env);
   
	if (AXIS2_SUCCESS != status)
    {
        axis2_repos_listener_free(dep_engine->repos_listener, env);
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;

        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_MODULE_VALIDATION_FAILED, AXIS2_FAILURE);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Validating system predefined phases failed");

        return NULL;
    }

    status = axis2_conf_set_phases_info(dep_engine->conf, env, dep_engine->phases_info);
	if (AXIS2_SUCCESS != status)
    {
        axis2_repos_listener_free(dep_engine->repos_listener, env);
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;

		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Setting phases info into Axis2 Configuration failed");

        return NULL;
    }
	
    out_fault_phases = axis2_phases_info_get_op_out_faultphases(dep_engine->phases_info, env);
    if (out_fault_phases)
    {
        axis2_conf_set_out_fault_phases(dep_engine->conf, env, out_fault_phases);
    }

    if (AXIS2_SUCCESS != status)
    {
        axis2_repos_listener_free(dep_engine->repos_listener, env);
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;

		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Setting out fault phases into Axis2 Configuratin failed");

        return NULL;
    }
	
    status = axis2_dep_engine_engage_modules(dep_engine, env);
    if (AXIS2_SUCCESS != status)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "dep engine failed to engaged_modules");
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;

        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_MODULE_VALIDATION_FAILED, AXIS2_FAILURE);
        return NULL;
    }

    return dep_engine->conf;
}

AXIS2_EXTERN axis2_conf_t *AXIS2_CALL
axis2_dep_engine_load_client(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    const axis2_char_t * client_home)
{
    axis2_bool_t is_repos_exist = AXIS2_FALSE;
    axis2_status_t status = AXIS2_FAILURE;
    axis2_bool_t flag = AXIS2_FALSE;

    AXIS2_PARAM_CHECK(env->error, client_home, NULL);

    flag = axis2_dep_engine_get_file_flag (dep_engine, env);

    if (!flag)
    {
        dep_engine->axis2_repos = axutil_strdup(env, client_home);
        if (!dep_engine->axis2_repos)
        {
            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
		    AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "No memory");
            return NULL;
        }

        if (client_home && axutil_strcmp("", client_home))
        {
            status =
                axis2_dep_engine_check_client_home(dep_engine, env, client_home);
            if (AXIS2_SUCCESS == status)
            {
                is_repos_exist = AXIS2_TRUE;
            }
            else
            {
                AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                        "axis2.xml is not available in client repo %s ", client_home);

                AXIS2_ERROR_SET (env->error, AXIS2_ERROR_CONFIG_NOT_FOUND, AXIS2_FAILURE);

                return NULL;
            }
        }
        else
        {
            dep_engine->conf_name = axutil_strdup(env, AXIS2_CONFIGURATION_RESOURCE);

            if (!dep_engine->conf_name)
            {
                AXIS2_ERROR_SET(env->error, AXIS2_ERROR_REPO_CAN_NOT_BE_NULL, AXIS2_FAILURE);
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Axis2 Configuration file name cannot be NULL");
                return NULL;
            }
        }
    }

    else
    {
        is_repos_exist = AXIS2_TRUE;
    }

    dep_engine->conf = axis2_conf_create(env);
    if (!dep_engine->conf)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "No memory. Allocation for Axis2 Configuration failed");
        return NULL;
    }
    dep_engine->conf_builder =
        axis2_conf_builder_create_with_file_and_dep_engine_and_conf(env, dep_engine->conf_name, 
                dep_engine, dep_engine->conf);

    if (!(dep_engine->conf_builder))
    {
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;
    }

   /**
      Very important: Only after populating we will be able to access
      parameters in axis2 xml.
    */

	axis2_conf_set_axis2_flag (dep_engine->conf, env, dep_engine->file_flag);
	axis2_conf_set_axis2_xml (dep_engine->conf, env, dep_engine->conf_name);

    status = axis2_conf_builder_populate_conf(dep_engine->conf_builder, env);
    if (AXIS2_SUCCESS != status)
    {
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Populating Axis2 Configuration failed");
        return NULL;
    }

    status = axis2_dep_engine_set_svc_and_module_dir_path (dep_engine, env);
    if (AXIS2_SUCCESS != status)
    {
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Setting service and module paths failed");
        return NULL;
    }


    if (is_repos_exist)
    {
        dep_engine->hot_dep = AXIS2_FALSE;
        dep_engine->hot_update = AXIS2_FALSE;
        if (dep_engine->repos_listener)
        {
            axis2_repos_listener_free(dep_engine->repos_listener, env);
        }

        dep_engine->repos_listener = axis2_repos_listener_create_with_folder_name_and_dep_engine(env,
                dep_engine->folder_name, dep_engine);
    }

    axis2_conf_set_repo(dep_engine->conf, env, dep_engine->axis2_repos);
    axis2_core_utils_calculate_default_module_version(env, axis2_conf_get_all_modules(
                dep_engine->conf, env), dep_engine->conf);

    axis2_conf_set_phases_info(dep_engine->conf, env, dep_engine->phases_info);
    status = axis2_dep_engine_engage_modules(dep_engine, env);
    if (AXIS2_SUCCESS != status)
    {
        axis2_repos_listener_free(dep_engine->repos_listener, env);
        axis2_conf_free(dep_engine->conf, env);
        dep_engine->conf = NULL;
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_MODULE_VALIDATION_FAILED, AXIS2_FAILURE);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Module engage failed for deployment engine");
        return NULL;
    }

    return dep_engine->conf;
}

static axis2_status_t
axis2_dep_engine_check_client_home(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    const axis2_char_t * client_home)
{
    axis2_char_t *path_l = NULL;
    axis2_status_t status = AXIS2_FAILURE;

    dep_engine->folder_name = axutil_strdup(env, client_home);
    if (!dep_engine->folder_name)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "No memory");
        return AXIS2_FAILURE;
    }
    path_l = axutil_stracat(env, client_home, AXIS2_PATH_SEP_STR);
    dep_engine->conf_name = axutil_stracat(env, path_l, AXIS2_SERVER_XML_FILE);
    AXIS2_FREE(env->allocator, path_l);

    if (!dep_engine->conf_name)
    {
        dep_engine->conf_name =
            axutil_strdup(env, AXIS2_CONFIGURATION_RESOURCE);
        if (!dep_engine->conf_name)
        {
            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_CONFIG_NOT_FOUND, AXIS2_FAILURE);
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Axis2 Configuration file name cannot be NULL");
            return AXIS2_FAILURE;
        }
    }

    status = axutil_file_handler_access(dep_engine->conf_name, AXIS2_F_OK);
    if (AXIS2_SUCCESS != status)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_CONFIG_NOT_FOUND, AXIS2_FAILURE);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Axis2 Configuration file name not found");
        return AXIS2_FAILURE;
    }

    return AXIS2_SUCCESS;
}

static axis2_status_t
axis2_dep_engine_engage_modules(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    int size = 0;
    int i = 0;
    axis2_status_t status = AXIS2_FAILURE;

    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    if (!dep_engine->module_list)
    {
        /* There are no modules */
		AXIS2_LOG_DEBUG (env->log, AXIS2_LOG_SI, "No modules configured");
        return AXIS2_SUCCESS;
    }

    size = axutil_array_list_size(dep_engine->module_list, env);

    for (i = 0; i < size; i++)
    {
        axutil_qname_t *qname = NULL;
        qname = (axutil_qname_t *) axutil_array_list_get(dep_engine->module_list, env, i);
        if (qname && dep_engine->conf)
        {
            status = axis2_conf_engage_module(dep_engine->conf, env, qname);
            if (AXIS2_SUCCESS != status)
            {
                AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                        "Engaging module %s to Axis2 Configuration failed",
                        axutil_qname_get_localpart(qname, env));

                return status;
            }
        }
    }

    return AXIS2_SUCCESS;
}

static axis2_status_t
axis2_dep_engine_validate_system_predefined_phases(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    axutil_array_list_t *in_phases = NULL;
    axis2_char_t *phase0 = NULL;
    axis2_char_t *phase1 = NULL;
    axis2_char_t *phase2 = NULL;
    axis2_char_t *phase3 = NULL;

    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    in_phases = axis2_phases_info_get_in_phases(dep_engine->phases_info, env);
    if (in_phases)
    {
        phase0 = (axis2_char_t *) axutil_array_list_get(in_phases, env, 0);
        phase1 = (axis2_char_t *) axutil_array_list_get(in_phases, env, 1);
        phase2 = (axis2_char_t *) axutil_array_list_get(in_phases, env, 2);
        phase3 = (axis2_char_t *) axutil_array_list_get(in_phases, env, 3);
    }

    if ((phase0 && 0 != axutil_strcmp(phase0, AXIS2_PHASE_TRANSPORT_IN)) ||
        (phase1 && 0 != axutil_strcmp(phase1, AXIS2_PHASE_PRE_DISPATCH)) ||
        (phase2 && 0 != axutil_strcmp(phase2, AXIS2_PHASE_DISPATCH)) ||
        (phase3 && 0 != axutil_strcmp(phase3, AXIS2_PHASE_POST_DISPATCH)))
    {
        AXIS2_ERROR_SET(env->error, AXI2_ERROR_INVALID_PHASE, AXIS2_FAILURE);
        return AXIS2_SUCCESS;
    }

    return AXIS2_SUCCESS;
}

/* For each searvices belonging to the service group passed as parameter, 
 * 1) Modules defined to be engaged to passed service group are engaged.
 * 2) Modules defined to be engaged to service are engaged.
 *
 * Then for each service operation modules defined to be engaged to that operation are engaged.
 */
static axis2_status_t
axis2_dep_engine_add_new_svc(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_svc_grp_t * svc_metadata)
{
    axutil_array_list_t *svcs = NULL;
    int sizei = 0;
    int i = 0;

    AXIS2_PARAM_CHECK(env->error, svc_metadata, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    svcs = axis2_arch_file_data_get_deployable_svcs(dep_engine->curr_file, env);
    if (svcs)
    {
        sizei = axutil_array_list_size(svcs, env);
    }

    for (i = 0; i < sizei; i++)
    {
        axis2_svc_t *svc = NULL;
        axutil_file_t *file = NULL;
        axutil_array_list_t *grp_modules = NULL;
        axutil_array_list_t *list = NULL;
        int sizej = 0;
        int j = 0;
        axutil_hash_t *ops = NULL;
        axutil_hash_index_t *index_i = NULL;
        axis2_char_t *file_name = NULL;

        svc = (axis2_svc_t *) axutil_array_list_get(svcs, env, i);

        file = axis2_arch_file_data_get_file(dep_engine->curr_file, env);
        file_name = axutil_file_get_name(file, env);
        axis2_svc_set_file_name(svc, env, file_name);

        /* Modules from service group */
        grp_modules = axis2_svc_grp_get_all_module_qnames(svc_metadata, env);
        if (grp_modules)
        {
            sizej = axutil_array_list_size(grp_modules, env);
        }
        for (j = 0; j < sizej; j++)
        {
            axis2_module_desc_t *module_desc = NULL;
            axutil_qname_t *qmodulename = NULL;

            qmodulename = (axutil_qname_t *) axutil_array_list_get(grp_modules, env, j);
            module_desc = axis2_conf_get_module(dep_engine->conf, env, qmodulename);
            if (module_desc)
            {
                axis2_svc_engage_module(svc, env, module_desc, dep_engine->conf);
            }
            else
            {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Invalid module reference taken from conf");
                AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_MODUELE_REF, AXIS2_FAILURE);
                return AXIS2_FAILURE;
            }
        }

        /* Modules from service */
        list = axis2_svc_get_all_module_qnames(svc, env);
        sizej = axutil_array_list_size(list, env);
        for (j = 0; j < sizej; j++)
        {
            axis2_module_desc_t *module_desc = NULL;
            axutil_qname_t *qmodulename = NULL;

            qmodulename = (axutil_qname_t *) axutil_array_list_get(list, env, j);
            module_desc = axis2_conf_get_module(dep_engine->conf, env, qmodulename);
            if (module_desc)
            {
                axis2_status_t status = AXIS2_FAILURE;
                status = axis2_svc_engage_module(svc, env, module_desc, dep_engine->conf);
                if (!status)
                {
		            AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                        "Engaging module %s to service %s failed", 
                        axutil_qname_get_localpart(qmodulename, env), file_name);
                    return status;
                }
            }
            else
            {
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Invalid module reference taken from conf");
                AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_MODUELE_REF, AXIS2_FAILURE);
                return AXIS2_FAILURE;
            }
        }

        ops = axis2_svc_get_all_ops(svc, env);
        for (index_i = axutil_hash_first(ops, env); index_i; index_i = axutil_hash_next(env, index_i))
        {
            void *v = NULL;
            axis2_op_t *op_desc = NULL;
            axutil_array_list_t *modules = NULL;
            int sizek = 0;
            int k = 0;

            axutil_hash_this(index_i, NULL, NULL, &v);
            op_desc = (axis2_op_t *) v;

            modules = axis2_op_get_all_module_qnames(op_desc, env);
            if (modules)
            {
                sizek = axutil_array_list_size(modules, env);
            }
            for (k = 0; k < sizek; k++)
            {
                axutil_qname_t *module_qname = NULL;
                axis2_module_desc_t *module = NULL;

                module_qname = (axutil_qname_t *) axutil_array_list_get(modules, env, k);
                module = axis2_conf_get_module(dep_engine->conf, env, module_qname);

                if (module)
                {
                    axis2_op_engage_module(op_desc, env, module, dep_engine->conf);
                }
                else
                {
                    AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_MODUELE_REF_BY_OP, AXIS2_FAILURE);
		            AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                            "Module %s is not added to the Axis2 Configuration", 
                            axutil_qname_get_localpart(module_qname, env));

                    return AXIS2_FAILURE;
                }
            }
        }

        axis2_svc_grp_add_svc(svc_metadata, env, svc);
    }

    return axis2_conf_add_svc_grp(dep_engine->conf, env, svc_metadata);
}

/* Here we will load the actual module implementation dll using the class loader and store it in
 * module description.
 */
static axis2_status_t
axis2_dep_engine_load_module_dll(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_module_desc_t * module_desc)
{
    axis2_char_t *read_in_dll = NULL;
    axis2_module_t *module = NULL;
    axutil_dll_desc_t *dll_desc = NULL;
    axutil_param_t *impl_info_param = NULL;
    axutil_file_t *module_folder = NULL;
    AXIS2_TIME_T timestamp = 0;
    axis2_char_t *module_folder_path = NULL;
    axis2_char_t *temp_path = NULL;
    axis2_char_t *dll_path = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    axis2_char_t *dll_name = NULL;

    AXIS2_PARAM_CHECK(env->error, module_desc, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    read_in_dll = axis2_arch_file_data_get_module_dll_name(dep_engine->curr_file, env);
    dll_desc = axutil_dll_desc_create(env);
    dll_name = axutil_dll_desc_create_platform_specific_dll_name(dll_desc, env, read_in_dll);

    module_folder = axis2_arch_file_data_get_file(dep_engine->curr_file, env);
    timestamp = axutil_file_get_timestamp(module_folder, env);
    axutil_dll_desc_set_timestamp(dll_desc, env, timestamp);
    module_folder_path = axutil_file_get_path(module_folder, env);
    temp_path = axutil_stracat(env, module_folder_path, AXIS2_PATH_SEP_STR);
    dll_path = axutil_stracat(env, temp_path, dll_name);

    AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI,
                    "axis2_dep_engine_load_module_dll: DLL path is : %s", dll_path);
    status = axutil_dll_desc_set_name(dll_desc, env, dll_path);
    if (AXIS2_SUCCESS != status)
    {
        axutil_dll_desc_free(dll_desc, env);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Setting dll path %s to the dll description failed", 
                dll_path);

        return AXIS2_FAILURE;
    }

    /* Free all temp vars */
    AXIS2_FREE(env->allocator, temp_path);
    temp_path = NULL;
    AXIS2_FREE(env->allocator, dll_path);
    dll_path = NULL;

    axutil_dll_desc_set_type(dll_desc, env, AXIS2_MODULE_DLL);
    impl_info_param = axutil_param_create(env, read_in_dll, NULL);
    axutil_param_set_value(impl_info_param, env, dll_desc);
    axutil_param_set_value_free(impl_info_param, env, axutil_dll_desc_free_void_arg);
    axutil_class_loader_init(env);
    module = (axis2_module_t *) axutil_class_loader_create_dll(env, impl_info_param);

    /* We cannot free the created impl_info_param here because by freeing
     * so, it will free dll_desc which in turn unload the module. So we
     * add this as a param to module_desc
     */
    axis2_module_desc_add_param(module_desc, env, impl_info_param);

    return axis2_module_desc_set_module(module_desc, env, module);
}

/* For each handler description of the module flow take the corresponding handler create function 
 * from handler_create_func_map and create the handler instance for the handler description.
 */
static axis2_status_t
axis2_dep_engine_add_module_flow_handlers(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_flow_t * flow,
    axutil_hash_t * handler_create_func_map)
{
    int count = 0;
    int j = 0;

    AXIS2_PARAM_CHECK(env->error, flow, AXIS2_FAILURE);

    count = axis2_flow_get_handler_count(flow, env);

    for (j = 0; j < count; j++)
    {
        axis2_handler_desc_t *handlermd = NULL;
        axis2_handler_t *handler = NULL;
        const axutil_string_t *handler_name = NULL;
        AXIS2_HANDLER_CREATE_FUNC handler_create_func = NULL;

        handlermd = axis2_flow_get_handler(flow, env, j);
        handler_name = axis2_handler_desc_get_name(handlermd, env);
        handler_create_func = axutil_hash_get(handler_create_func_map, axutil_string_get_buffer(
                    handler_name, env), AXIS2_HASH_KEY_STRING);

        handler = handler_create_func(env, handler_name);
        axis2_handler_init(handler, env, handlermd);
        axis2_handler_desc_set_handler(handlermd, env, handler);
    }

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN void *AXIS2_CALL
axis2_dep_engine_get_handler_dll(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_char_t * class_name)
{
    axutil_dll_desc_t *dll_desc = NULL;
    axutil_param_t *impl_info_param = NULL;
    axis2_handler_t *handler = NULL;
    axis2_char_t *dll_name = NULL;

    AXIS2_PARAM_CHECK(env->error, class_name, NULL);
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);

    dll_desc = axutil_dll_desc_create(env);
    dll_name = axutil_dll_desc_create_platform_specific_dll_name(dll_desc, env, class_name);
    axutil_dll_desc_set_name(dll_desc, env, dll_name);
    axutil_dll_desc_set_type(dll_desc, env, AXIS2_HANDLER_DLL);
    axutil_class_loader_init(env);
    impl_info_param = axutil_param_create(env, NULL, NULL);
    axutil_param_set_value(impl_info_param, env, dll_desc);
    handler = (axis2_handler_t *) axutil_class_loader_create_dll(env, impl_info_param);

    return handler;
}

/* Caller has module description filled with the information in module.xml by the time this 
 * function is called. Now it will load the actual module implementation and fill the module
 * flows with the actual handler instances. Finally module description will be added into the
 * configuration module list.
 */
static axis2_status_t
axis2_dep_engine_add_new_module(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_module_desc_t * module_metadata)
{
    axis2_flow_t *in_flow = NULL;
    axis2_flow_t *out_flow = NULL;
    axis2_flow_t *in_fault_flow = NULL;
    axis2_flow_t *out_fault_flow = NULL;
    axis2_module_t *module = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    const axutil_qname_t *module_qname = NULL;
    axis2_char_t *module_name = NULL;

    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    module_qname = axis2_module_desc_get_qname(module_metadata, env);
    module_name = axutil_qname_get_localpart(module_qname, env);
    status = axis2_dep_engine_load_module_dll(dep_engine, env, module_metadata);

    if (AXIS2_SUCCESS != status)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Loading module description %s failed", 
                module_name);

        return status;
    }

    module = axis2_module_desc_get_module(module_metadata, env);
    if (!module)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                "Retrieving module from module description %s failed", module_name);

        return AXIS2_FAILURE;
    }

    /* Module implementor will provide functions for creating his handlers and by calling this
     * function these function pointers will be stored in a hash map in the module.
     */
    status = axis2_module_fill_handler_create_func_map(module, env);
    if (AXIS2_SUCCESS != status)
    {
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
            "Filling handler create function for module map %s failed", module_name);
        return status;
    }

    in_flow = axis2_module_desc_get_in_flow(module_metadata, env);
    if (in_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, in_flow, 
                module->handler_create_func_map);
    }

    out_flow = axis2_module_desc_get_out_flow(module_metadata, env);
    if (out_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, out_flow, 
                module->handler_create_func_map);
    }

    in_fault_flow = axis2_module_desc_get_fault_in_flow(module_metadata, env);
    if (in_fault_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, in_fault_flow, 
                module->handler_create_func_map);
    }

    out_fault_flow = axis2_module_desc_get_fault_out_flow(module_metadata, env);
    if (out_fault_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, out_fault_flow, 
                module->handler_create_func_map);
    }

    /* Add the module description into the axis2 configuration. Axis2 configuration will keep these
     * handlers in a hash_map called all_modules.
     */
    axis2_conf_add_module(dep_engine->conf, env, module_metadata);

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_do_deploy(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    int size = 0;
    axis2_status_t status = AXIS2_FAILURE;

    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    size = axutil_array_list_size(dep_engine->ws_to_deploy, env);

    if (size > 0)
    {
        int i = 0;
        for (i = 0; i < size; i++)
        {
            int type = 0;
            axis2_svc_grp_t *svc_grp = NULL;
            axis2_char_t *file_name = NULL;
            axis2_module_desc_t *meta_data = NULL;

            dep_engine->curr_file = (axis2_arch_file_data_t *) axutil_array_list_get(
                    dep_engine->ws_to_deploy, env, i);

            type = axis2_arch_file_data_get_type(dep_engine->curr_file, env);
            switch (type)
            {
                case AXIS2_SVC:
                {
                    if (dep_engine->arch_reader)
                    {
                        axis2_arch_reader_free(dep_engine->arch_reader, env);
                        dep_engine->arch_reader = NULL;
                    }

                    dep_engine->arch_reader = axis2_arch_reader_create (env);
                    svc_grp = axis2_svc_grp_create_with_conf(env, dep_engine->conf);
                    file_name = axis2_arch_file_data_get_name(dep_engine->curr_file, env);
                    status = axis2_arch_reader_process_svc_grp(dep_engine->arch_reader, env, 
                            file_name, dep_engine, svc_grp);

                    if (AXIS2_SUCCESS != status)
                    {
                        axis2_arch_reader_free(dep_engine->arch_reader, env);
                        dep_engine->arch_reader = NULL;
                        dep_engine->curr_file = NULL;
                        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_SVC, AXIS2_FAILURE);
		                AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Processing service group %s failed", 
                                file_name);

                        return status;
                    }

                    status = axis2_dep_engine_add_new_svc(dep_engine, env, svc_grp);
                    if (AXIS2_SUCCESS != status)
                    {
                        axis2_arch_reader_free(dep_engine->arch_reader, env);
                        dep_engine->arch_reader = NULL;
                        dep_engine->curr_file = NULL;
                        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_SVC, AXIS2_FAILURE);
		                AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                            "Adding new service %s to the deployment engine failed", file_name);

                        return status;
                    }

                    dep_engine->curr_file = NULL;
                    break;
                }

                case AXIS2_MODULE:
                {
                    if (dep_engine->arch_reader)
                    {
                        axis2_arch_reader_free(dep_engine->arch_reader, env);
                        dep_engine->arch_reader = NULL;
                    }
                    dep_engine->arch_reader = axis2_arch_reader_create(env);
                    meta_data = axis2_module_desc_create(env);
                    file_name = axis2_arch_file_data_get_name(dep_engine->curr_file, env);
                    status = axis2_arch_reader_read_module_arch(env, file_name, dep_engine, meta_data);
                    if (AXIS2_SUCCESS != status)
                    {
                        axis2_arch_reader_free (dep_engine->arch_reader, env);
                        dep_engine->arch_reader = NULL;
                        dep_engine->curr_file = NULL;
                        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_MODULE, AXIS2_FAILURE);
		                AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                                "Reading module archive for file %s failed", file_name);

                        return AXIS2_FAILURE;
                    }

                    status = axis2_dep_engine_add_new_module(dep_engine, env, meta_data);
                    if (AXIS2_SUCCESS != status)
                    {
                        axis2_arch_reader_free (dep_engine->arch_reader, env);
                        dep_engine->arch_reader = NULL;
                        dep_engine->curr_file = NULL;
                        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_MODULE, AXIS2_FAILURE);

		                AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, 
                            "Adding new module %s to the deployment engine failed", file_name);

                        return AXIS2_FAILURE;
                    }

                    dep_engine->curr_file = NULL;
                    break;
                }
            };

            axis2_arch_reader_free (dep_engine->arch_reader, env);
            dep_engine->arch_reader = NULL;
            dep_engine->curr_file = NULL;
        }
    }

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_undeploy(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    int size = 0;
    axis2_char_t *svc_name = NULL;

    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    size = axutil_array_list_size(dep_engine->ws_to_undeploy, env);

    if (size > 0)
    {
        int i = 0;
        for (i = 0; i < size; i++)
        {
            int type = 0;
            axis2_ws_info_t *ws_info = NULL;
            axutil_hash_t *faulty_svcs = NULL;

            ws_info = (axis2_ws_info_t *)
                axutil_array_list_get(dep_engine->ws_to_undeploy, env, i);
            type = axis2_ws_info_get_type(ws_info, env);
            if (type == AXIS2_SVC)
            {
                axis2_char_t *file_name = NULL;

                file_name = axis2_ws_info_get_file_name(ws_info, env);
                svc_name = axis2_dep_engine_get_axis_svc_name(dep_engine, env, file_name);

                axis2_conf_remove_svc(dep_engine->conf, env, svc_name);
            }

            faulty_svcs = axis2_conf_get_all_faulty_svcs(dep_engine->conf, env);
            axutil_hash_set(faulty_svcs, svc_name, AXIS2_HASH_KEY_STRING, NULL);
        }

    }

    axutil_array_list_free(dep_engine->ws_to_undeploy, env);

    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_dep_engine_is_hot_update(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    return dep_engine->hot_update;
}

static axis2_char_t *
axis2_dep_engine_get_axis_svc_name(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_char_t * file_name)
{
    axis2_char_t name_sep = '.';
    axis2_char_t *temp_name = NULL;
    axis2_char_t *ptr = NULL;
    axis2_char_t *file_name_l = NULL;
    axis2_char_t *svc_name = NULL;
    int len = 0;

    file_name_l = axutil_strdup(env, file_name);
    ptr = AXIS2_STRRCHR(file_name_l, AXIS2_PATH_SEP_CHAR);

    temp_name = ptr + 1;
    ptr = AXIS2_STRRCHR(temp_name, name_sep);
    ptr[0] = '\0';
    len = (int)strlen(temp_name);
    /* We are sure that the difference lies within the int range */
    svc_name = AXIS2_MALLOC(env->allocator, len + 1);
    sscanf(temp_name, "%s", svc_name);
    AXIS2_FREE(env->allocator, file_name_l);

    return svc_name;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_set_phases_info(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_phases_info_t * phases_info)
{
    AXIS2_PARAM_CHECK(env->error, phases_info, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    dep_engine->phases_info = phases_info;
    return AXIS2_SUCCESS;
}

/**
 * This method is used to fill a axis2 service instance using services.xml ,
 * first it should create an axis service instance and then fill that using 
 * given service.xml and load all the required class and build the chains , 
 * finally add the  service context to engine context and axis2 service into 
 * Engine Configuration.
 */
AXIS2_EXTERN axis2_svc_t *AXIS2_CALL
axis2_dep_engine_build_svc(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_svc_t * svc,
    axis2_char_t * file_name)
{
    axiom_node_t *node = NULL;

    AXIS2_PARAM_CHECK(env->error, file_name, NULL);
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);

    dep_engine->curr_file = axis2_arch_file_data_create_with_type_and_name(env, AXIS2_SVC, "");

    dep_engine->svc_builder = axis2_svc_builder_create_with_file_and_dep_engine_and_svc(env, 
            file_name, dep_engine, svc);

    node = axis2_desc_builder_build_om(axis2_svc_builder_get_desc_builder(dep_engine->svc_builder, 
                env), env);

    axis2_svc_builder_populate_svc(dep_engine->svc_builder, env, node);

    return svc;
}

/**
 * This function can be used to build Module Description for a given module 
 * archieve file.
 */
AXIS2_EXTERN axis2_module_desc_t *AXIS2_CALL
axis2_dep_engine_build_module(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axutil_file_t * module_archive,
    axis2_conf_t * conf)
{
    axis2_module_desc_t *module_desc = NULL;
    axis2_module_t *module = NULL;
    axis2_phases_info_t *phases_info = NULL;
    axis2_arch_reader_t *arch_reader = NULL;
    axis2_flow_t *in_flow = NULL;
    axis2_flow_t *out_flow = NULL;
    axis2_flow_t *in_fault_flow = NULL;
    axis2_flow_t *out_fault_flow = NULL;
    axis2_char_t *file_name = NULL;
    axis2_status_t status = AXIS2_FAILURE;

    AXIS2_PARAM_CHECK(env->error, module_archive, NULL);
    AXIS2_PARAM_CHECK(env->error, conf, NULL);
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);

    phases_info = axis2_conf_get_phases_info(conf, env);
    axis2_dep_engine_set_phases_info(dep_engine, env, phases_info);
    dep_engine->curr_file = axis2_arch_file_data_create_with_type_and_file(env, AXIS2_MODULE, 
            module_archive);

    module_desc = axis2_module_desc_create(env);
    arch_reader = axis2_arch_reader_create(env);
    file_name = axutil_file_get_name(module_archive, env);
    status = axis2_arch_reader_read_module_arch(env, file_name, dep_engine, module_desc);
    axis2_arch_reader_free(arch_reader, env);
    if (AXIS2_SUCCESS != status)
    {
        axis2_module_desc_free(module_desc, env);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Reading module archive for file %s failed", file_name);
        return NULL;
    }
    status = axis2_dep_engine_load_module_dll(dep_engine, env, module_desc);
    if (AXIS2_SUCCESS != status)
    {
        axis2_module_desc_free(module_desc, env);
		AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Loading module dll %s failed", file_name);
        return NULL;
    }

    module = axis2_module_desc_get_module(module_desc, env);
    
    /* Module implementor will provide functions for creating his handlers and by calling this
     * function these function pointers will be stored in a hash map in the module.
     */
    axis2_module_fill_handler_create_func_map(module, env);

    in_flow = axis2_module_desc_get_in_flow(module_desc, env);
    if (in_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, in_flow, 
                module->handler_create_func_map);
    }

    out_flow = axis2_module_desc_get_out_flow(module_desc, env);
    if (out_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, out_flow, 
                module->handler_create_func_map);
    }

    in_fault_flow = axis2_module_desc_get_fault_in_flow(module_desc, env);
    if (in_fault_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, in_fault_flow, 
                module->handler_create_func_map);
    }

    out_fault_flow = axis2_module_desc_get_fault_out_flow(module_desc, env);
    if (out_fault_flow)
    {
        axis2_dep_engine_add_module_flow_handlers(dep_engine, env, out_fault_flow, 
                module->handler_create_func_map);
    }

    dep_engine->curr_file = NULL;

    return module_desc;
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_dep_engine_get_repos_path(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);
    return dep_engine->folder_name;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_set_current_file_item(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_arch_file_data_t * file_data)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);
    if (dep_engine->curr_file)
    {
        axis2_arch_file_data_free(dep_engine->curr_file, env);
        dep_engine->curr_file = NULL;
    }
    dep_engine->curr_file = file_data;
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_set_arch_reader(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_arch_reader_t * arch_reader)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    if (dep_engine->arch_reader)
    {
        axis2_arch_reader_free(dep_engine->arch_reader, env);
        dep_engine->arch_reader = NULL;
    }
    dep_engine->arch_reader = arch_reader;
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_module_builder(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_module_builder_t * module_builder)
{
    AXIS2_PARAM_CHECK(env->error, module_builder, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    return axutil_array_list_add(dep_engine->module_builders, env, module_builder);
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_svc_builder(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_svc_builder_t * svc_builder)
{
    AXIS2_PARAM_CHECK(env->error, svc_builder, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    return axutil_array_list_add(dep_engine->svc_builders, env, svc_builder);
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_svc_grp_builder(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    axis2_svc_grp_builder_t * svc_grp_builder)
{
    AXIS2_PARAM_CHECK(env->error, svc_grp_builder, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    return axutil_array_list_add(dep_engine->svc_grp_builders, env, svc_grp_builder);
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_add_desc_builder(
    axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env,
    struct axis2_desc_builder * desc_builder)
{
    AXIS2_PARAM_CHECK(env->error, desc_builder, AXIS2_FAILURE);
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);

    return axutil_array_list_add(dep_engine->desc_builders, env, desc_builder);
}

AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_dep_engine_get_module_dir(
	const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);
	return axutil_strdup (env, dep_engine->module_dir);
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_set_module_dir(
	axis2_dep_engine_t * dep_engine,
	const axutil_env_t * env,
	const axis2_char_t *module_dir)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);
	AXIS2_PARAM_CHECK (env->error, module_dir, AXIS2_FAILURE);
	dep_engine->module_dir = axutil_strdup (env, module_dir);
	return AXIS2_SUCCESS;
}
	

AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_dep_engine_get_file_flag(
    const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FALSE);
    return dep_engine->file_flag;
}



AXIS2_EXTERN axis2_char_t *AXIS2_CALL
axis2_dep_engine_get_svc_dir(
	const axis2_dep_engine_t * dep_engine,
    const axutil_env_t * env)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, NULL);
	return axutil_strdup (env, dep_engine->svc_dir);
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_dep_engine_set_svc_dir(
	axis2_dep_engine_t * dep_engine,
	const axutil_env_t * env,
	const axis2_char_t *svc_dir)
{
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);
	AXIS2_PARAM_CHECK (env->error, svc_dir, AXIS2_FAILURE);
	dep_engine->svc_dir = axutil_strdup (env, svc_dir);
	return AXIS2_SUCCESS;
}

static axis2_status_t axis2_dep_engine_set_svc_and_module_dir_path (
    axis2_dep_engine_t *dep_engine,
    const axutil_env_t *env)
{
    axis2_bool_t flag;
    axis2_conf_t *conf;
    axis2_char_t *dirpath;
    axutil_param_t *dep_param;
    AXIS2_PARAM_CHECK (env->error, dep_engine, AXIS2_FAILURE);
    flag = dep_engine->file_flag;
    if (!flag)
    {
        return AXIS2_SUCCESS;
    }
    else
    {
        conf = dep_engine->conf;
        if (!conf)
        {
		    AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI, "Axis2 Configuration cannot be NULL");
            return AXIS2_FAILURE;
        }

        dep_param = axis2_conf_get_param (conf, env, AXIS2_MODULE_DIR);
        if (dep_param)
        {
            dirpath = (axis2_char_t *)axutil_param_get_value(dep_param, env);
            if (dirpath)
            {
                dep_engine->module_dir = dirpath;
                dirpath = NULL;
            }
        }
        dep_param = NULL;

        dep_param = axis2_conf_get_param (conf, env, AXIS2_SERVICE_DIR);
        if (dep_param)
        {
            dirpath = (axis2_char_t *)axutil_param_get_value(dep_param, env);
            if (dirpath)
            {
                dep_engine->svc_dir = dirpath;
                dirpath = NULL;
            }
        }
    }

    return AXIS2_SUCCESS;
}


