
/*
 * 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_svc_builder.h>
#include <axutil_class_loader.h>
#include <axutil_utils.h>
#include <axutil_property.h>
#include <axis2_msg.h>

struct axis2_svc_builder
{
    axis2_svc_t *svc;
    struct axis2_desc_builder *desc_builder;
};

static axutil_array_list_t *axis2_svc_builder_process_ops(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_children_qname_iterator_t * op_itr);

static void axis2_svc_builder_process_msgs(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_children_qname_iterator_t * iterator,
    axis2_op_t * op);

AXIS2_EXTERN axis2_svc_builder_t *AXIS2_CALL
axis2_svc_builder_create(
    const axutil_env_t * env)
{
    axis2_svc_builder_t *svc_builder = NULL;

    svc_builder = (axis2_svc_builder_t *) AXIS2_MALLOC(env->allocator,
                                                       sizeof
                                                       (axis2_svc_builder_t));

    if (!svc_builder)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "No memory. Allocation to svc_builder failed");
        return NULL;
    }

    svc_builder->desc_builder = NULL;
    svc_builder->svc = NULL;

    return svc_builder;
}

AXIS2_EXTERN axis2_svc_builder_t *AXIS2_CALL
axis2_svc_builder_create_with_file_and_dep_engine_and_svc(
    const axutil_env_t * env,
    axis2_char_t * file_name,
    struct axis2_dep_engine * dep_engine,
    axis2_svc_t * svc)
{
    axis2_svc_builder_t *svc_builder = NULL;

    AXIS2_PARAM_CHECK(env->error, file_name, NULL);
    AXIS2_PARAM_CHECK(env->error, dep_engine, NULL);
    AXIS2_PARAM_CHECK(env->error, svc, NULL);
    svc_builder = (axis2_svc_builder_t *) axis2_svc_builder_create(env);
    if (!svc_builder)
    {
        return NULL;
    }
    svc_builder->desc_builder =
        axis2_desc_builder_create_with_file_and_dep_engine(env, file_name,
                                                           dep_engine);
    if (!svc_builder->desc_builder)
    {
        axis2_svc_builder_free(svc_builder, env);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "Creating description builder for service builder %s failed", 
            file_name);
        return NULL;
    }
    svc_builder->svc = svc;
    return svc_builder;
}

AXIS2_EXTERN axis2_svc_builder_t *AXIS2_CALL
axis2_svc_builder_create_with_dep_engine_and_svc(
    const axutil_env_t * env,
    axis2_dep_engine_t * dep_engine,
    axis2_svc_t * svc)
{
    axis2_svc_builder_t *svc_builder = NULL;

    AXIS2_PARAM_CHECK(env->error, dep_engine, NULL);
    AXIS2_PARAM_CHECK(env->error, svc, NULL);
    svc_builder = (axis2_svc_builder_t *) axis2_svc_builder_create(env);
    if (!svc_builder)
    {
        return NULL;
    }
    svc_builder->desc_builder =
        axis2_desc_builder_create_with_dep_engine(env, dep_engine);
    if (!svc_builder->desc_builder)
    {
        axis2_svc_builder_free(svc_builder, env);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "Creating description builder for service builder failed");
        return NULL;
    }
    svc_builder->svc = svc;
    return svc_builder;
}

AXIS2_EXTERN void AXIS2_CALL
axis2_svc_builder_free(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env)
{
    if (svc_builder->desc_builder)
    {
        axis2_desc_builder_free(svc_builder->desc_builder, env);
    }

    svc_builder->svc = NULL;

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

    return;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_svc_builder_populate_svc(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_node_t * svc_node)
{
    axiom_element_t *svc_element = NULL;
    axiom_children_qname_iterator_t *itr = NULL;
    axiom_children_qname_iterator_t *operation_itr = NULL;
    axutil_qname_t *qparamst = NULL;
    axutil_qname_t *qdesc = NULL;
    axutil_qname_t *qmodulest = NULL;
    axutil_qname_t *qinflowst = NULL;
    axutil_qname_t *qoutflowst = NULL;
    axutil_qname_t *qin_faultflowst = NULL;
    axutil_qname_t *qout_faultflowst = NULL;
    axutil_qname_t *qopst = NULL;
    axutil_qname_t *qattname = NULL;
    axutil_qname_t *qpolicy = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    axis2_svc_grp_t *parent = NULL;
    axiom_element_t *desc_element = NULL;
    axiom_node_t *desc_node = NULL;
    axiom_children_qname_iterator_t *module_refs = NULL;
    axiom_node_t *in_flow_node = NULL;
    axiom_element_t *in_flow_element = NULL;
    axiom_node_t *out_flow_node = NULL;
    axiom_element_t *out_flow_element = NULL;
    axiom_node_t *in_faultflow_node = NULL;
    axiom_element_t *in_faultflow_element = NULL;
    axiom_node_t *out_faultflow_node = NULL;
    axiom_element_t *out_faultflow_element = NULL;
    axiom_attribute_t *name_attr = NULL;
    axutil_array_list_t *ops = NULL;
    axis2_char_t *svc_name = NULL;
    axis2_char_t *class_name = NULL;
    axis2_char_t *svc_dll_name = NULL;
    axutil_dll_desc_t *dll_desc = NULL;
    axutil_param_t *impl_info_param = NULL;
    axutil_param_t *wsdl_path_param = NULL;
    axis2_char_t *wsdl_path = NULL;
    axis2_arch_file_data_t *arch_file_data = NULL;
    axutil_file_t *svc_folder = NULL;
    axis2_char_t *dll_path = NULL;
    axis2_char_t *svc_folder_path = NULL;
    int i = 0;
    int size = 0;
    AXIS2_TIME_T timestamp = 0;
    axis2_desc_t *desc = NULL;
    axis2_policy_include_t *policy_include = NULL;
    axutil_qname_t *qname_addressing = NULL;
    axis2_bool_t addressing_engaged = AXIS2_FALSE;
    axutil_array_list_t *svc_module_qnames = NULL;
    int svc_module_qname_size = 0;

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

    svc_element = axiom_node_get_data_element(svc_node, env);
    /* Processing service level paramters */
    qparamst = axutil_qname_create(env, AXIS2_PARAMETERST, NULL, NULL);
    if (!qparamst)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory");
        return AXIS2_FAILURE;
    }
    itr = axiom_element_get_children_with_qname(svc_element, env, qparamst,
                                                svc_node);
    axutil_qname_free(qparamst, env);
    qparamst = NULL;

    parent = axis2_svc_get_parent(svc_builder->svc, env);

    desc = axis2_svc_get_base(svc_builder->svc, env);
    policy_include = axis2_desc_get_policy_include(desc, env);

    status = axis2_desc_builder_process_params(svc_builder->desc_builder, env,
                                               itr,
                                               axis2_svc_get_param_container
                                               (svc_builder->svc, env),
                                               axis2_svc_grp_get_param_container
                                               (parent, env));
    if (AXIS2_SUCCESS != status)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "Processing parameters failed");
        return status;
    }

    /* process service description */
    qdesc = axutil_qname_create(env, AXIS2_DESCRIPTION, NULL, NULL);
    desc_element = axiom_element_get_first_child_with_qname(svc_element, env,
                                                            qdesc, svc_node,
                                                            &desc_node);
    axutil_qname_free(qdesc, env);
    qdesc = NULL;
    if (desc_element)
    {
        axiom_element_t *desc_value_element = NULL;
        axiom_node_t *desc_value_node = NULL;
        axis2_char_t *description_text = NULL;

        desc_value_element = axiom_element_get_first_element(desc_element,
                                                             env, desc_node,
                                                             &desc_value_node);
        description_text = axiom_element_get_text(desc_element, env, desc_node);
        if (description_text)
        {
            axis2_svc_set_svc_desc(svc_builder->svc, env, description_text);
        }
    }

    /* wsdl path */
    wsdl_path_param =
        axutil_param_container_get_param(axis2_svc_get_param_container
                                         (svc_builder->svc, env), env,
                                         AXIS2_SVC_WSDL_PATH);

    if (wsdl_path_param)
    {
        wsdl_path = axutil_param_get_value(wsdl_path_param, env);
    }

    if (wsdl_path)
    {
        axis2_svc_set_svc_wsdl_path(svc_builder->svc, env, wsdl_path);
    }

    qattname = axutil_qname_create(env, AXIS2_ATTNAME, NULL, NULL);
    name_attr = axiom_element_get_attribute(svc_element, env, qattname);
    svc_name = axiom_attribute_get_value(name_attr, env);
    axis2_svc_set_name(svc_builder->svc, env, svc_name);
    axutil_qname_free(qattname, env);

    /* create dll_desc and set it in a parameter. then set that param in param
     * container taken from svc 
     */
    dll_desc = axutil_dll_desc_create(env);
    impl_info_param =
        axutil_param_container_get_param(axis2_svc_get_param_container
                                         (svc_builder->svc, env), env,
                                         AXIS2_SERVICE_CLASS);
    if (!impl_info_param)
    {
        axutil_dll_desc_free(dll_desc, env);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "%s parameter not found", AXIS2_SERVICE_CLASS);
        return AXIS2_FAILURE;
    }
    class_name = axutil_strtrim(env, 
                     axutil_param_get_value(impl_info_param, env), NULL);
    svc_dll_name =
        axutil_dll_desc_create_platform_specific_dll_name(dll_desc, env,
                                                          class_name);

    if (class_name)
    {
        AXIS2_FREE(env->allocator, class_name);
        class_name = NULL;
    }

    arch_file_data =
        axis2_dep_engine_get_current_file_item(axis2_desc_builder_get_dep_engine
                                               (svc_builder->desc_builder, env),
                                               env);
    svc_folder = axis2_arch_file_data_get_file(arch_file_data, env);
    timestamp = axutil_file_get_timestamp(svc_folder, env);
    axutil_dll_desc_set_timestamp(dll_desc, env, timestamp);
    svc_folder_path = axutil_file_get_path(svc_folder, env);
    axis2_svc_set_svc_folder_path(svc_builder->svc, env, svc_folder_path);
    dll_path = axutil_strcat(env, svc_folder_path, AXIS2_PATH_SEP_STR,
                             svc_dll_name, NULL);
    AXIS2_LOG_DEBUG(env->log, AXIS2_LOG_SI, "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 name to  %s dll description failed", dll_path);
        return status;
    }
    AXIS2_FREE(env->allocator, dll_path);
    dll_path = NULL;

    axutil_dll_desc_set_type(dll_desc, env, AXIS2_SVC_DLL);
    status = 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);
    if (AXIS2_SUCCESS != status)
    {
        axutil_dll_desc_free(dll_desc, env);
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "Setting dll_desc to parameter %s failed", class_name);
        return status;
    }
    /* processing service wide modules which required to engage globally */
    qmodulest = axutil_qname_create(env, AXIS2_MODULEST, NULL, NULL);
    module_refs = axiom_element_get_children_with_qname(svc_element, env,
                                                        qmodulest, svc_node);
    axutil_qname_free(qmodulest, env);
    qmodulest = NULL;
    status =
        axis2_svc_builder_process_module_refs(svc_builder, env, module_refs);
    if (AXIS2_SUCCESS != status)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
            "Processing module references failed");
        return status;
    }
    
    if(!addressing_engaged)
    {
        svc_module_qnames = axis2_svc_get_all_module_qnames(svc_builder->svc, env);
        if (svc_module_qnames)
        {
            svc_module_qname_size = axutil_array_list_size(svc_module_qnames, env);  
            qname_addressing = axutil_qname_create(env, AXIS2_MODULE_ADDRESSING, NULL, NULL);
            for (i = 0; i < svc_module_qname_size; i++)
            {
                if (axutil_qname_equals(axutil_array_list_get(svc_module_qnames, env, i), env, qname_addressing))
                {
                    addressing_engaged = AXIS2_TRUE;
                    break;
                }
            }
            axutil_qname_free(qname_addressing, env);
        }
        svc_module_qnames = NULL;
    }

    /* process IN_FLOW */
    qinflowst = axutil_qname_create(env, AXIS2_IN_FLOW_START, NULL, NULL);
    in_flow_element = axiom_element_get_first_child_with_qname(svc_element,
                                                               env, qinflowst,
                                                               svc_node,
                                                               &in_flow_node);
    axutil_qname_free(qinflowst, env);
    qinflowst = NULL;

    qoutflowst = axutil_qname_create(env, AXIS2_OUT_FLOW_START, NULL, NULL);
    out_flow_element = axiom_element_get_first_child_with_qname(svc_element,
                                                                env, qoutflowst,
                                                                svc_node,
                                                                &out_flow_node);
    axutil_qname_free(qoutflowst, env);
    qoutflowst = NULL;

    qin_faultflowst = axutil_qname_create(env, AXIS2_IN_FAILTFLOW, NULL, NULL);
    in_faultflow_element = axiom_element_get_first_child_with_qname(svc_element,
                                                                    env,
                                                                    qin_faultflowst,
                                                                    svc_node,
                                                                    &in_faultflow_node);
    axutil_qname_free(qin_faultflowst, env);
    qin_faultflowst = NULL;

    qout_faultflowst =
        axutil_qname_create(env, AXIS2_OUT_FAILTFLOW, NULL, NULL);
    out_faultflow_element =
        axiom_element_get_first_child_with_qname(svc_element, env, qoutflowst,
                                                 svc_node, &out_faultflow_node);
    axutil_qname_free(qout_faultflowst, env);
    qout_faultflowst = NULL;

    /* processing operations */
    qopst = axutil_qname_create(env, AXIS2_OPERATIONST, NULL, NULL);
    operation_itr = axiom_element_get_children_with_qname(svc_element, env,
                                                          qopst, svc_node);
    axutil_qname_free(qopst, env);
    qopst = NULL;
    ops = axis2_svc_builder_process_ops(svc_builder, env, operation_itr);
    if (ops)
    {
        size = axutil_array_list_size(ops, env);
    }
    for (i = 0; i < size; i++)
    {
        axis2_op_t *op_desc = NULL;
        axutil_array_list_t *params = NULL;
        int j = 0;
        int sizej = 0;

        op_desc = (axis2_op_t *) axutil_array_list_get(ops, env, i);
        if (addressing_engaged)
        {
            params = axis2_op_get_all_params(op_desc, env);
            /* Adding wsa-mapping into service */
            sizej = axutil_array_list_size(params, env);
            for (j = 0; j < sizej; j++)
            {
                axutil_param_t *param = NULL;
                axis2_char_t *param_name = NULL;

                param = axutil_array_list_get(params, env, j);
                param_name = axutil_param_get_name(param, env);
                if (0 == axutil_strcmp(param_name, AXIS2_WSA_MAPPING))
                {
                    axis2_char_t *key = NULL;

                    key = (axis2_char_t *) axutil_param_get_value(param, env);
                    axis2_svc_add_mapping(svc_builder->svc, env, key, op_desc);
                }
            }
        }
        axis2_svc_add_op(svc_builder->svc, env, op_desc);
        if (axis2_op_get_rest_http_method(op_desc, env) && 
            axis2_op_get_rest_http_location(op_desc, env) )
        {
            axis2_svc_add_rest_mapping(svc_builder->svc, env,
                                       axis2_op_get_rest_http_method(op_desc, env),
                                       axis2_op_get_rest_http_location(op_desc, env),
                                       op_desc);
        }
    }
    axutil_array_list_free(ops, env);

    /*
       <schema targetNamespace="http://x.y.z"/>
       setting the PolicyInclude
       processing <wsp:Policy> .. </..> elements
     */
    qpolicy = axutil_qname_create(env, NEETHI_POLICY, NEETHI_NAMESPACE, NULL);
    itr = axiom_element_get_children_with_qname(svc_element, env, qpolicy, svc_node);
    axutil_qname_free(qpolicy, env);
    qpolicy = NULL;
    if((!itr) || (!axiom_children_qname_iterator_has_next(itr, env)))
    {
        qpolicy = axutil_qname_create(env, NEETHI_POLICY, NEETHI_POLICY_15_NAMESPACE, NULL);
        itr = axiom_element_get_children_with_qname(svc_element, env, qpolicy, svc_node);
        axutil_qname_free(qpolicy, env);
        qpolicy = NULL;
    }

    if (itr)
    {
        axis2_process_policy_elements(env, AXIS2_SERVICE_POLICY, itr,
                                      policy_include);
    }

    /* processing <wsp:PolicyReference> .. </..> elements */
    qpolicy = axutil_qname_create(env, NEETHI_REFERENCE, NEETHI_NAMESPACE, NULL);
    itr = axiom_element_get_children_with_qname(svc_element, env, qpolicy, svc_node);
    axutil_qname_free(qpolicy, env);
    qpolicy = NULL;

    if((!itr) || (!axiom_children_qname_iterator_has_next(itr, env)))
    {
        qpolicy = axutil_qname_create(env, NEETHI_REFERENCE, NEETHI_POLICY_15_NAMESPACE, NULL);
        itr = axiom_element_get_children_with_qname(svc_element, env, qpolicy, svc_node);
        axutil_qname_free(qpolicy, env);
        qpolicy = NULL;
    }
    if (itr)
    {
        axis2_process_policy_reference_elements(env, AXIS2_POLICY_REF, itr,
                                                policy_include);
    }

    return AXIS2_SUCCESS;
}

static axutil_array_list_t *
axis2_svc_builder_process_ops(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_children_qname_iterator_t * op_itr)
{
    axutil_array_list_t *ops = NULL;

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

    ops = axutil_array_list_create(env, 0);
    while (AXIS2_TRUE == axiom_children_qname_iterator_has_next(op_itr, env))
    {
        axiom_element_t *op_element = NULL;
        axiom_node_t *op_node = NULL;
        axiom_attribute_t *op_name_att = NULL;
        axiom_attribute_t *op_mep_att = NULL;
        axutil_qname_t *qmep = NULL;
        axutil_qname_t *qopname = NULL;
        axutil_qname_t *qparamst = NULL;
        axutil_qname_t *qmsgrecv = NULL;
        axutil_qname_t *qmodulest = NULL;
        axutil_qname_t *qattname = NULL;
        axis2_char_t *mep_url = NULL;
        axis2_char_t *op_name = NULL;
        axis2_op_t *op_desc = NULL;
        axiom_children_qname_iterator_t *params_itr = NULL;
        axiom_children_qname_iterator_t *module_itr = NULL;
        axiom_element_t *recv_element = NULL;
        axiom_node_t *recv_node = NULL;
        axis2_status_t status = AXIS2_FAILURE;
        struct axis2_dep_engine *dep_engine = NULL;
        axis2_desc_t *desc = NULL;
        axis2_policy_include_t *policy_include = NULL;
        axiom_children_qname_iterator_t *itr = NULL;
        axutil_qname_t *qpolicy = NULL;
        axutil_qname_t *qmessage = NULL;

        op_node = axiom_children_qname_iterator_next(op_itr, env);
        /* getting operation name */
        op_element = axiom_node_get_data_element(op_node, env);
        qattname = axutil_qname_create(env, AXIS2_ATTNAME, NULL, NULL);
        op_name_att = axiom_element_get_attribute(op_element, env, qattname);
        axutil_qname_free(qattname, env);
        qattname = NULL;
        if (!op_name_att)
        {
            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_OP_NAME_MISSING,
                            AXIS2_FAILURE);
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "");
            return NULL;
        }

        op_name = axiom_attribute_get_value(op_name_att, env);
        qopname = axutil_qname_create(env, op_name, NULL, NULL);
        op_desc = axis2_op_create(env);
        axis2_op_set_qname(op_desc, env, qopname);
        axutil_qname_free(qopname, env);
        qopname = NULL;

        /* set the mep of the operation */
        qmep = axutil_qname_create(env, AXIS2_MEP, NULL, NULL);
        op_mep_att = axiom_element_get_attribute(op_element, env, qmep);
        axutil_qname_free(qmep, env);
        qmep = NULL;
        op_name = axiom_attribute_get_value(op_name_att, env);

        if (op_mep_att)
        {
            mep_url = axiom_attribute_get_value(op_mep_att, env);
            if (mep_url)
            {
                axis2_op_set_msg_exchange_pattern(op_desc, env, mep_url);
            }
        }

        desc = axis2_op_get_base(op_desc, env);
        policy_include = axis2_desc_get_policy_include(desc, env);

        /* operation parameters */
        qparamst = axutil_qname_create(env, AXIS2_PARAMETERST, NULL, NULL);
        params_itr = axiom_element_get_children_with_qname(op_element, env,
                                                           qparamst, op_node);
        axutil_qname_free(qparamst, env);
        qparamst = NULL;
        status = axis2_desc_builder_process_params(svc_builder->desc_builder,
                                                   env, params_itr,
                                                   axis2_op_get_param_container
                                                   (op_desc, env),
                                                   axis2_svc_get_param_container
                                                   (svc_builder->svc, env));
        /* To process wsamapping */
        axis2_desc_builder_process_action_mappings(svc_builder->desc_builder,
                                                   env, op_node, op_desc);

        /* To process REST params */
        axis2_desc_builder_process_rest_params(svc_builder->desc_builder,
                                               env, op_node, op_desc);

        /* loading the message receivers */
        qmsgrecv = axutil_qname_create(env, AXIS2_MESSAGERECEIVER, NULL, NULL);
        recv_element = axiom_element_get_first_child_with_qname(op_element,
                                                                env, qmsgrecv,
                                                                op_node,
                                                                &recv_node);
        axutil_qname_free(qmsgrecv, env);
        qmsgrecv = NULL;
        if (recv_element && NULL != recv_node)
        {
            axis2_msg_recv_t *msg_recv = NULL;
            msg_recv =
                axis2_desc_builder_load_msg_recv(svc_builder->desc_builder, env,
                                                 recv_element);
            axis2_op_set_msg_recv(op_desc, env, msg_recv);

        }
        else
        {
            axis2_msg_recv_t *msg_recv = NULL;
            /* setting the default message receiver */
            msg_recv = axis2_desc_builder_load_default_msg_recv(env);
            axis2_op_set_msg_recv(op_desc, env, msg_recv);
        }
        /* process module refs */
        qmodulest = axutil_qname_create(env, AXIS2_MODULEST, NULL, NULL);
        module_itr = axiom_element_get_children_with_qname(op_element, env,
                                                           qmodulest, op_node);
        axutil_qname_free(qmodulest, env);
        qmodulest = NULL;
        status = axis2_desc_builder_process_op_module_refs(svc_builder->
                                                           desc_builder, env,
                                                           module_itr, op_desc);
        if (AXIS2_SUCCESS != status)
        {
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
                "Processing module operation references failed for operation %s", 
                op_name);
            return NULL;
        }

        /* setting the policy_include */

        /* processing <wsp:Policy> .. </..> elements */

        qpolicy = axutil_qname_create(env, NEETHI_POLICY, NEETHI_NAMESPACE, NULL);
        itr = axiom_element_get_children_with_qname(op_element, env, qpolicy, op_node);
        axutil_qname_free(qpolicy, env);
        qpolicy = NULL;

        if((!itr) || (!axiom_children_qname_iterator_has_next(itr, env)))
        {
            qpolicy = axutil_qname_create(env, NEETHI_POLICY, NEETHI_POLICY_15_NAMESPACE, NULL);
            itr = axiom_element_get_children_with_qname(op_element, env, qpolicy, op_node);
            axutil_qname_free(qpolicy, env);
            qpolicy = NULL;
        }

        if (itr)
        {
            axis2_process_policy_elements(env, AXIS2_SERVICE_POLICY, itr,
                                          policy_include);
        }

        /* processing <wsp:PolicyReference> .. </..> elements */
        qpolicy = axutil_qname_create(env, NEETHI_REFERENCE, NEETHI_NAMESPACE, NULL);
        itr = axiom_element_get_children_with_qname(op_element, env, qpolicy, op_node);
        axutil_qname_free(qpolicy, env);
        qpolicy = NULL;

        if((!itr) || (!axiom_children_qname_iterator_has_next(itr, env)))
        {
            qpolicy = axutil_qname_create(env, NEETHI_REFERENCE, NEETHI_POLICY_15_NAMESPACE, NULL);
            itr = axiom_element_get_children_with_qname(op_element, env, qpolicy, op_node);
            axutil_qname_free(qpolicy, env);
            qpolicy = NULL;        
        }

        if (itr)
        {
            axis2_process_policy_reference_elements(env, AXIS2_POLICY_REF, itr,
                                                    policy_include);
        }

        qmessage = axutil_qname_create(env, AXIS2_MESSAGE, NULL, NULL);
        itr = axiom_element_get_children_with_qname(op_element, env,
                                                    qmessage, op_node);
        axutil_qname_free(qmessage, env);
        qmessage = NULL;

        if (itr)
        {
            axis2_svc_builder_process_msgs(svc_builder, env, itr, op_desc);
        }

        /* setting operation phase */
        dep_engine =
            axis2_desc_builder_get_dep_engine(svc_builder->desc_builder, env);
        if (dep_engine)
        {
            axis2_phases_info_t *info =
                axis2_dep_engine_get_phases_info(dep_engine, env);
            axis2_phases_info_set_op_phases(info, env, op_desc);
        }

        /* adding operation */
        status = axutil_array_list_add(ops, env, op_desc);
    }

    return ops;
}

static void
axis2_svc_builder_process_msgs(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_children_qname_iterator_t * iterator,
    axis2_op_t * op)
{
    while (axiom_children_qname_iterator_has_next(iterator, env))
    {
        axiom_node_t *node = NULL;
        axiom_element_t *element = NULL;
        axutil_qname_t *qname = NULL;
        axis2_char_t *msg_label = NULL;
        axis2_msg_t *msg = NULL;
        axiom_children_qname_iterator_t *itr = NULL;
        axutil_qname_t *qpolicy = NULL;
        axis2_desc_t *desc = NULL;
        axis2_policy_include_t *policy_include = NULL;

        node = axiom_children_qname_iterator_next(iterator, env);
        element = axiom_node_get_data_element(node, env);
        qname = axutil_qname_create(env, AXIS2_LABEL, NULL, NULL);

        if (element)
        {
            msg_label = axiom_element_get_attribute_value(element, env, qname);
        }

        if (msg_label)
        {
            msg = axis2_op_get_msg(op, env, msg_label);
        }

        if (msg)
        {
            /* operation parameters */
            axiom_children_qname_iterator_t *params_itr = NULL;
            axutil_qname_t *qparamst = NULL;
            qparamst = axutil_qname_create(env, AXIS2_PARAMETERST, NULL, NULL);
            params_itr = axiom_element_get_children_with_qname(element, env,
                                                               qparamst, node);
            axutil_qname_free(qparamst, env);
            qparamst = NULL;
            axis2_desc_builder_process_params(svc_builder->desc_builder,
                                              env, params_itr,
                                              axis2_msg_get_param_container(msg,
                                                                            env),
                                              axis2_op_get_param_container(op,
                                                                           env));

            desc = axis2_msg_get_base(msg, env);
            policy_include = axis2_desc_get_policy_include(desc, env);

            /* setting the policy_include */

            /* processing <wsp:Policy> .. </..> elements */

            qpolicy = axutil_qname_create(env, NEETHI_POLICY, NEETHI_NAMESPACE, NULL);
            itr = axiom_element_get_children_with_qname(element, env, qpolicy, node);
            axutil_qname_free(qpolicy, env);
            qpolicy = NULL;
            
            if((!itr) || (!axiom_children_qname_iterator_has_next(itr, env)))
            {
                qpolicy = axutil_qname_create(env, NEETHI_POLICY, NEETHI_POLICY_15_NAMESPACE, NULL);
                itr = axiom_element_get_children_with_qname(element, env, qpolicy, node);
                axutil_qname_free(qpolicy, env);
                qpolicy = NULL;
            }

            if (itr)
            {
                axis2_process_policy_elements(env, AXIS2_SERVICE_POLICY, itr,
                                              policy_include);
                /* axis2_process_policy_elements(env, AXIS2_MESSAGE_POLICY, itr,
                   policy_include); */

            }

            /* processing <wsp:PolicyReference> .. </..> elements */
            qpolicy = axutil_qname_create(env, NEETHI_REFERENCE, NEETHI_NAMESPACE, NULL);
            itr = axiom_element_get_children_with_qname(element, env, qpolicy,node);
            axutil_qname_free(qpolicy, env);
            qpolicy = NULL;

            if((!itr) || (!axiom_children_qname_iterator_has_next(itr, env)))
            {
                qpolicy = axutil_qname_create(env, NEETHI_REFERENCE, NEETHI_POLICY_15_NAMESPACE, NULL);
                itr = axiom_element_get_children_with_qname(element, env, qpolicy,node);
                axutil_qname_free(qpolicy, env);
                qpolicy = NULL;
            }

            if (itr)
            {
                axis2_process_policy_reference_elements(env, AXIS2_POLICY_REF,
                                                        itr, policy_include);
            }
        }
    }
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_svc_builder_process_svc_module_conf(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_children_qname_iterator_t * module_confs,
    axutil_param_container_t * parent,
    axis2_svc_t * svc)
{
    while (axiom_children_qname_iterator_has_next(module_confs, env))
    {
        axiom_element_t *module_conf_element = NULL;
        axiom_node_t *module_conf_node = NULL;
        axiom_attribute_t *module_name_att = NULL;
        axutil_qname_t *qattname = NULL;

        module_conf_node =
            axiom_children_qname_iterator_next(module_confs, env);
        module_conf_element =
            axiom_node_get_data_element(module_conf_node, env);
        qattname = axutil_qname_create(env, AXIS2_ATTNAME, NULL, NULL);
        module_name_att = axiom_element_get_attribute(module_conf_element,
                                                      env, qattname);
        axutil_qname_free(qattname, env);
        qattname = NULL;
        if (!module_name_att)
        {
            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_INVALID_MODULE_CONF,
                            AXIS2_FAILURE);
            AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, 
                "Module name attribute not found for module node");
            return AXIS2_FAILURE;
        }
    }
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_svc_builder_process_module_refs(
    axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env,
    axiom_children_qname_iterator_t * module_refs)
{
    AXIS2_PARAM_CHECK(env->error, module_refs, AXIS2_FAILURE);

    while (axiom_children_qname_iterator_has_next(module_refs, env))
    {
        axiom_element_t *module_ref_element = NULL;
        axiom_node_t *module_ref_node = NULL;
        axiom_attribute_t *module_ref_att = NULL;
        axutil_qname_t *qref = NULL;

        module_ref_node = axiom_children_qname_iterator_next(module_refs, env);
        module_ref_element = axiom_node_get_data_element(module_ref_node, env);
        qref = axutil_qname_create(env, AXIS2_REF, NULL, NULL);
        module_ref_att = axiom_element_get_attribute(module_ref_element,
                                                     env, qref);
        axutil_qname_free(qref, env);
        if (module_ref_att)
        {
            axis2_char_t *ref_name = NULL;
            axutil_qname_t *qrefname = NULL;

            ref_name = axiom_attribute_get_value(module_ref_att, env);
            qrefname = axutil_qname_create(env, ref_name, NULL, NULL);
            if (!axis2_dep_engine_get_module
                (axis2_desc_builder_get_dep_engine
                 (svc_builder->desc_builder, env), env, qrefname))
            {
                AXIS2_ERROR_SET(env->error, AXIS2_ERROR_MODULE_NOT_FOUND,
                                AXIS2_FAILURE);
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Unable to find "\
                    "Module %s, in Service %s", ref_name, 
                    axis2_svc_get_name(svc_builder->svc, env));
                return AXIS2_FAILURE;
            }
            else
            {
                axis2_svc_add_module_qname(svc_builder->svc, env, qrefname);
            }
            axutil_qname_free(qrefname, env);
        }
    }
    return AXIS2_SUCCESS;
}

AXIS2_EXTERN struct axis2_desc_builder *AXIS2_CALL
axis2_svc_builder_get_desc_builder(
    const axis2_svc_builder_t * svc_builder,
    const axutil_env_t * env)
{
    return svc_builder->desc_builder;
}

