/*
 *  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.
 */

package org.apache.synapse.config.xml;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.Mediator;
import org.apache.synapse.Startup;
import org.apache.synapse.SynapseConstants;
import org.apache.synapse.endpoints.Template;
import org.apache.synapse.inbound.InboundEndpoint;
import org.apache.synapse.libraries.imports.SynapseImport;
import org.apache.synapse.mediators.template.TemplateMediator;
import org.apache.synapse.SynapseException;
import org.apache.synapse.message.processor.MessageProcessor;
import org.apache.synapse.message.store.MessageStore;
import org.apache.synapse.commons.executors.PriorityExecutor;
import org.apache.synapse.config.Entry;
import org.apache.synapse.config.SynapseConfigUtils;
import org.apache.synapse.config.SynapseConfiguration;
import org.apache.synapse.core.axis2.ProxyService;
import org.apache.synapse.endpoints.Endpoint;
import org.apache.synapse.eventing.SynapseEventSource;
import org.apache.synapse.mediators.base.SequenceMediator;
import org.apache.synapse.api.API;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.*;
import java.util.Iterator;
import java.util.Properties;

/**
 * <p>
 * This optional configuration builder creates the Synapse configuration by processing
 * a specified file hierarchy. If the root of the specified file hierarchy is CONFIG_HOME,
 * then the following directories are expected to be in CONFIG_HOME.
 * <ul>
 *  <li>CONFIG_HOME/proxy-services</li>
 *  <li>CONFIG_HOME/sequences</li>
 *  <li>CONFIG_HOME/endpoints</li>
 *  <li>CONFIG_HOME/local-entries</li>
 *  <li>CONFIG_HOME/tasks</li>
 *  <li>CONFIG_HOME/event-sources</li>
 *  <li>CONFIG_HOME/priority-executors</li>
 * </ul>
 *
 * Each of these directories will house a set of XML files. Each file will define exactly
 * one configuration item (eg: a proxy service, an endpoint, a sequence).
 * </p>
 * <p>
 * In addition to the directories mentioned above one can have the following file in
 * CONFIG_HOME
 * <ul>
 *  <li>CONFIG_HOME/registry.xml</li>
 * </ul>
 * </p>
 *
 */
public class MultiXMLConfigurationBuilder {

    public static final String PROXY_SERVICES_DIR       = "proxy-services";
    public static final String SEQUENCES_DIR            = "sequences";
    public static final String TEMPLATES_DIR            = "templates";
    public static final String ENDPOINTS_DIR            = "endpoints";
    public static final String LOCAL_ENTRY_DIR          = "local-entries";
    public static final String TASKS_DIR                = "tasks";
    public static final String EVENTS_DIR               = "event-sources";
    public static final String EXECUTORS_DIR            = "priority-executors";
    public static final String MESSAGE_STORE_DIR        = "message-stores";
    public static final String MESSAGE_PROCESSOR_DIR    = "message-processors";
    public static final String REST_API_DIR             = "api";
    public static final String INBOUND_ENDPOINT_DIR     = "inbound-endpoints";
    public static final String SYNAPSE_IMPORTS_DIR   = "imports";

    public static final String REGISTRY_FILE       = "registry.xml";

    public static final String TASK_MANAGER_FILE       = "task-manager.xml";

    public static final String SEPARATE_REGISTRY_DEFINITION = "__separateRegDef";

    public static final String SEPARATE_TASK_MANAGER_DEFINITION = "__separateTaskManagerDef";

    private static final String[] extensions = { "xml" };

    private static Log log = LogFactory.getLog(MultiXMLConfigurationBuilder.class);

    public static SynapseConfiguration getConfiguration(String root, Properties properties) {

        log.info("Building synapse configuration from the synapse artifact repository at : " + root);

        // First try to load the configuration from synapse.xml
        SynapseConfiguration synapseConfig = createConfigurationFromSynapseXML(root, properties);
        if (synapseConfig == null) {
            synapseConfig = SynapseConfigUtils.newConfiguration();
            synapseConfig.setDefaultQName(XMLConfigConstants.DEFINITIONS_ELT);
        } else if (log.isDebugEnabled()) {
            log.debug("Found a synapse configuration in the " + SynapseConstants.SYNAPSE_XML
                    + " file at the artifact repository root, which gets precedence "
                    + "over other definitions");
        }

        if (synapseConfig.getRegistry() == null) {
            // If the synapse.xml does not define a registry look for a registry.xml
            createRegistry(synapseConfig, root, properties);
        } else if (log.isDebugEnabled()) {
            log.debug("Using the registry defined in the " + SynapseConstants.SYNAPSE_XML
                    + " as the registry, any definitions in the "+ REGISTRY_FILE +
                    " will be neglected");
        }

        if (synapseConfig.getTaskManager() == null) {
            // If the synapse.xml does not define a taskManager look for a task-manager.xml
            createTaskManager(synapseConfig, root, properties);
        } else if (log.isDebugEnabled()) {
            log.debug("Using the task manager defined in the " + SynapseConstants.SYNAPSE_XML
                    + " as the task manager, any definitions in the "+ TASK_MANAGER_FILE +
                    " will be neglected");
        }


        createSynapseImports(synapseConfig, root, properties);
        createLocalEntries(synapseConfig, root, properties);
        createEndpoints(synapseConfig, root, properties);
        createSequences(synapseConfig, root, properties);
        createTemplates(synapseConfig, root, properties);
        createProxyServices(synapseConfig, root, properties);
        createTasks(synapseConfig, root, properties);
        createEventSources(synapseConfig, root, properties);
        createExecutors(synapseConfig, root, properties);
        createMessageStores(synapseConfig, root, properties);
        createMessageProcessors(synapseConfig, root, properties);
        createAPIs(synapseConfig, root, properties);
        createInboundEndpoint(synapseConfig, root, properties);
        return synapseConfig;
    }

    private static SynapseConfiguration createConfigurationFromSynapseXML(
            String rootDirPath, Properties properties) {

        File synapseXML = new File(rootDirPath, SynapseConstants.SYNAPSE_XML);
        if (!synapseXML.exists() || !synapseXML.isFile()) {
            return null;
        }

        FileInputStream is;
        SynapseConfiguration config = null;
        try {
            is = FileUtils.openInputStream(synapseXML);
        } catch (IOException e) {
            handleException("Error while opening the file: " + synapseXML.getName(), e);
            return null;
        }

        try {
            config = XMLConfigurationBuilder.getConfiguration(is, properties);
            is.close();
        } catch (XMLStreamException e) {
            handleException("Error while loading the Synapse configuration from the " +
                    synapseXML.getName() + " file", e);
        } catch (IOException e) {
            log.warn("Error while closing the input stream from file: " + synapseXML.getName(), e);
        }

        return config;
    }

    private static void createRegistry(SynapseConfiguration synapseConfig, String rootDirPath,
                                       Properties properties) {

        File registryDef = new File(rootDirPath, REGISTRY_FILE);
        try {
            if (registryDef.exists() && registryDef.isFile()) {
                if (log.isDebugEnabled()) {
                    log.debug("Initializing Synapse registry from the configuration at : " +
                            registryDef.getPath());
                }
                OMElement document = getOMElement(registryDef);
                SynapseXMLConfigurationFactory.defineRegistry(synapseConfig, document, properties);
                synapseConfig.setProperty(SEPARATE_REGISTRY_DEFINITION,
                        String.valueOf(Boolean.TRUE));
            }
        } catch (Exception e) {
            String msg = "Registry configuration cannot be built from : " + registryDef.getName();
            handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_REGISTRY, msg, e);
        }
    }

    private static void createTaskManager(SynapseConfiguration synapseConfig, String rootDirPath,
                                       Properties properties) {

        File taskManagerDef = new File(rootDirPath, TASK_MANAGER_FILE);
        try {
            if (taskManagerDef.exists() && taskManagerDef.isFile()) {
                if (log.isDebugEnabled()) {
                    log.debug("Initializing Synapse taskManager from the configuration at : " +
                            taskManagerDef.getPath());
                }
                OMElement document = getOMElement(taskManagerDef);
                SynapseXMLConfigurationFactory.defineTaskManager(synapseConfig, document, properties);
                synapseConfig.setProperty(SEPARATE_TASK_MANAGER_DEFINITION,
                        String.valueOf(Boolean.TRUE));
            }
        } catch (Exception e) {
            String msg = "Task Manager configuration cannot be built from : " + taskManagerDef.getName();
            handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_TASK_MANAGER, msg, e);
        }
    }

    private static void createLocalEntries(SynapseConfiguration synapseConfig, String rootDirPath,
                                           Properties properties) {

        File localEntriesDir = new File(rootDirPath, LOCAL_ENTRY_DIR);
        if (localEntriesDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading local entry definitions from : " + localEntriesDir.getPath());
            }

            Iterator entryDefinitions = FileUtils.iterateFiles(localEntriesDir, extensions, false);
            while (entryDefinitions.hasNext()) {
                File file = (File) entryDefinitions.next();
                try {
                    OMElement document = getOMElement(file);
                    Entry entry = SynapseXMLConfigurationFactory.defineEntry(synapseConfig, document,
                            properties);
                    if (entry != null) {
                        entry.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(file.getAbsolutePath(),
                                entry.getKey());
                    }
                } catch (Exception e) {
                    String msg = "Local Entry configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_LOCALENTRIES, msg, e);
                }
             }
        }
    }

    private static void createProxyServices(SynapseConfiguration synapseConfig, String rootDirPath,
                                            Properties properties) {

        File proxyServicesDir = new File(rootDirPath, PROXY_SERVICES_DIR);
        if (proxyServicesDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading proxy services from : " + proxyServicesDir.getPath());
            }

            Iterator proxyDefinitions = FileUtils.iterateFiles(proxyServicesDir, extensions, false);

            while (proxyDefinitions.hasNext()) {
                File file = (File) proxyDefinitions.next();
                try {
                    OMElement document = getOMElement(file);
                    ProxyService proxy = SynapseXMLConfigurationFactory.defineProxy(synapseConfig,
                            document, properties);
                    if (proxy != null) {
                        proxy.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(
                                file.getAbsolutePath(), proxy.getName());
                    }
                } catch (Exception e) {
                    String msg = "Proxy configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_PROXY_SERVICES, msg, e);
                }
            }
        }
    }

    private static void createTasks(SynapseConfiguration synapseConfig, String rootDirPath,
                                    Properties properties) {

        File tasksDir = new File(rootDirPath, TASKS_DIR);
        if (tasksDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading tasks from : " + tasksDir.getPath());
            }

            Iterator taskDefinitions = FileUtils.iterateFiles(tasksDir, extensions, false);
            while (taskDefinitions.hasNext()) {
                File file = (File) taskDefinitions.next();
                try {
                    OMElement document = getOMElement(file);
                    Startup startup = SynapseXMLConfigurationFactory.defineStartup(synapseConfig,
                            document, properties);
                    startup.setFileName(file.getName());
                    synapseConfig.getArtifactDeploymentStore().addArtifact(
                            file.getAbsolutePath(), startup.getName());
                } catch (Exception e) {
                    String msg = "Task configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_TASKS, msg, e);
                }
            }
        }
    }

    private static void createSequences(SynapseConfiguration synapseConfig, String rootDirPath,
                                        Properties properties) {

        File sequencesDir = new File(rootDirPath, SEQUENCES_DIR);
        if (sequencesDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading sequences from : " + sequencesDir.getPath());
            }

            Iterator sequences = FileUtils.iterateFiles(sequencesDir, extensions, false);
            while (sequences.hasNext()) {
                File file = (File) sequences.next();
                try{
                    OMElement document = getOMElement(file);
                    Mediator seq = SynapseXMLConfigurationFactory.defineSequence(synapseConfig,
                            document, properties);
                    if (seq != null && seq instanceof SequenceMediator) {
                        SequenceMediator sequence = (SequenceMediator) seq;
                        sequence.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(
                                file.getAbsolutePath(), sequence.getName());
                    }
                } catch (Exception e) {
                    String msg = "Sequence configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_SEQUENCES, msg, e);
                }

             }
        }
    }

    private static void createTemplates(SynapseConfiguration synapseConfig, String rootDirPath,
                                        Properties properties) {

        File templatesDir = new File(rootDirPath, TEMPLATES_DIR);
        if (templatesDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading template from : " + templatesDir.getPath());
            }
            Iterator templates = FileUtils.iterateFiles(templatesDir, extensions, false);
            while (templates.hasNext()) {
                File file = (File) templates.next();
                try {
                    OMElement document = getOMElement(file);
                    OMElement element = document.getFirstChildWithName(
                            new QName(SynapseConstants.SYNAPSE_NAMESPACE, "sequence"));
                    if (element != null) {
                        TemplateMediator mediator =
                                (TemplateMediator) SynapseXMLConfigurationFactory.defineMediatorTemplate(
                                        synapseConfig, document, properties);
                        if (mediator != null) {
                            mediator.setFileName(file.getName());
                            synapseConfig.getArtifactDeploymentStore().addArtifact(
                                    file.getAbsolutePath(), mediator.getName());
                        }
                    } else {
                        element = document.getFirstChildWithName(
                                new QName(SynapseConstants.SYNAPSE_NAMESPACE, "endpoint"));
                        if (element != null) {
                            Template endpointTemplate =
                                    SynapseXMLConfigurationFactory.defineEndpointTemplate(
                                            synapseConfig, document, properties);
                            if (endpointTemplate != null) {
                                endpointTemplate.setFileName(file.getName());
                                synapseConfig.getArtifactDeploymentStore().addArtifact(
                                        file.getAbsolutePath(), endpointTemplate.getName());
                            }
                        }
                    }
                } catch (Exception e) {
                    String msg = "Template configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_TEMPLATES, msg, e);
                }
            }
        }
    }

    private static void createEndpoints(SynapseConfiguration synapseConfig, String rootDirPath,
                                        Properties properties) {

        File endpointsDir = new File(rootDirPath, ENDPOINTS_DIR);
        if (endpointsDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading endpoints from : " + endpointsDir.getPath());
            }

            Iterator endpoints = FileUtils.iterateFiles(endpointsDir, extensions, false);
            while (endpoints.hasNext()) {
                File file = (File) endpoints.next();
                try {
                    OMElement document = getOMElement(file);
                    Endpoint endpoint = SynapseXMLConfigurationFactory.defineEndpoint(
                            synapseConfig, document, properties);
                    if (endpoint != null) {
                        endpoint.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(
                                file.getAbsolutePath(), endpoint.getName());
                    }
                } catch (Exception e) {
                    String msg = "Endpoint configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_EP, msg, e);
                }
            }
        }
    }

    private static void createEventSources(SynapseConfiguration synapseConfig, String rootDirPath,
                                           Properties properties) {

        File eventsDir = new File(rootDirPath, EVENTS_DIR);
        if (eventsDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading event sources from : " + eventsDir.getPath());
            }

            Iterator events = FileUtils.iterateFiles(eventsDir, extensions, false);
            while (events.hasNext()) {
                File file = (File) events.next();
                try {
                    OMElement document = getOMElement(file);
                    SynapseEventSource eventSource = SynapseXMLConfigurationFactory.
                            defineEventSource(synapseConfig, document, properties);
                    if (eventSource != null) {
                        eventSource.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(
                                file.getAbsolutePath(), eventSource.getName());
                    }
                } catch (Exception e) {
                    String msg = "Event source configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_EVENT_SOURCE, msg, e);
                }
            }
        }
    }

    private static void createExecutors(SynapseConfiguration synapseConfig, String rootDirPath,
                                        Properties properties) {

        File executorsDir = new File(rootDirPath, EXECUTORS_DIR);
        if (executorsDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading event sources from : " + executorsDir.getPath());
            }

            Iterator executors = FileUtils.iterateFiles(executorsDir, extensions, false);
            while (executors.hasNext()) {
                File file = (File) executors.next();
                try {
                    OMElement document = getOMElement(file);
                    PriorityExecutor executor = SynapseXMLConfigurationFactory.
                            defineExecutor(synapseConfig, document, properties);
                    if (executor != null) {
                        executor.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(
                                file.getAbsolutePath(), executor.getName());
                    }
                } catch (Exception e) {
                    String msg = "Executor configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_EXECUTORS, msg, e);
                }
            }
        }
    }

    private static void createMessageStores(SynapseConfiguration synapseConfig ,
                                            String rootDirPath, Properties properties) {

        File messageStoresDir = new File(rootDirPath, MESSAGE_STORE_DIR);
        if (messageStoresDir.exists() ) {
            if (log.isDebugEnabled()) {
                log.debug("Loading Message Stores from :" + messageStoresDir.getPath());
            }

            Iterator messageStores = FileUtils.iterateFiles(messageStoresDir, extensions, false);
            while (messageStores.hasNext()) {
                File file = (File) messageStores.next();
                try {
                    OMElement document = getOMElement(file);
                    MessageStore messageStore = SynapseXMLConfigurationFactory.defineMessageStore(
                            synapseConfig, document, properties);
                    if (messageStore != null) {
                        messageStore.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(file.getAbsolutePath(),
                                messageStore.getName());
                    }
                } catch (Exception e) {
                    String msg = "Message store configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_MESSAGE_STORES, msg, e);
                }
            }
        }
    }


    private static void createMessageProcessors(SynapseConfiguration synapseConfig,
                                            String rootDirPath, Properties properties) {

        File messageProcessorDir = new File(rootDirPath, MESSAGE_PROCESSOR_DIR);
        if (messageProcessorDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading Message Processors from :" + messageProcessorDir.getPath());
            }

            Iterator messageProcessors = FileUtils.iterateFiles(messageProcessorDir, extensions, false);
            while (messageProcessors.hasNext()) {
                File file = (File) messageProcessors.next();
                try {
                    OMElement document = getOMElement(file);
                    MessageProcessor messageProcessor = SynapseXMLConfigurationFactory.defineMessageProcessor(
                            synapseConfig, document, properties);
                    if (messageProcessor != null) {
                        messageProcessor.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(file.getAbsolutePath(),
                                messageProcessor.getName());
                    }
                } catch (Exception e) {
                    String msg = "Message processor configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_MESSAGE_PROCESSORS, msg, e);
                }
            }
        }
    }

    private static void createSynapseImports(SynapseConfiguration synapseConfig, String root, Properties properties) {
        File synImportsDir = new File(root, SYNAPSE_IMPORTS_DIR);
        if (synImportsDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading Synapse Imports from :" + synImportsDir.getPath());
            }
            Iterator synImports = FileUtils.iterateFiles(synImportsDir, extensions, false);
            while (synImports.hasNext()) {
                File file = (File) synImports.next();
                try {
                    OMElement document = getOMElement(file);
                    SynapseImport synImp = SynapseXMLConfigurationFactory.defineImport(
                            synapseConfig, document, properties);
                    if (synImp != null) {
                        synImp.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(file.getAbsolutePath(),
                                synImp.getName());
                    }
                } catch (Exception e) {
                    String msg = "Import configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_IMPORTS, msg, e);
                }
            }
        }

    }


    private static void createAPIs(SynapseConfiguration synapseConfig,
                                   String rootDirPath, Properties properties) {

        try {
            File apiDir = new File(rootDirPath, REST_API_DIR);
            if (apiDir.exists()) {
                if (log.isDebugEnabled()) {
                    log.debug("Loading APIs from :" + apiDir.getPath());
                }
                String[] apiFileDirectories = apiDir.list((dir, name) -> {
                    for (String extension : extensions) {
                        if (name.endsWith(extension)) {
                            return true;
                        }
                    }
                    return false;
                });
                if (apiFileDirectories != null) {
                    for (String fileName : apiFileDirectories) {
                        try {
                            File file = new File(apiDir, fileName);
                            OMElement document = getOMElement(file);
                            API api = SynapseXMLConfigurationFactory.defineAPI(synapseConfig, document, properties,
                                    false);
                            if (api != null) {
                                api.setFileName(file.getName());
                                synapseConfig.getArtifactDeploymentStore()
                                        .addArtifact(file.getAbsolutePath(), api.getName());
                            }
                        } catch (Exception e) {
                            String msg = "API configuration cannot be built from: " + fileName;
                            handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_API, msg, e);
                        }
                    }
                }
                // order the apis based on context descending order
                try {
                    SynapseXMLConfigurationFactory.reOrderAPIs(synapseConfig);
                } catch (Exception e) {
                    String msg = "Error while re-ordering apis";
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_API, msg, e);
                }
            }
        } catch (Exception e) {
            String msg = "Error loading APIs";
            handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_API, msg, e);
        }
    }


    private static void createInboundEndpoint(SynapseConfiguration synapseConfig,
                                              String rootDirPath, Properties properties) {
        File inboundEndpointDir = new File(rootDirPath, INBOUND_ENDPOINT_DIR);
        if (inboundEndpointDir.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Loading APIs from :" + inboundEndpointDir.getPath());
            }

            Iterator inboundEndpointIterator = FileUtils.iterateFiles(inboundEndpointDir, extensions, false);
            while (inboundEndpointIterator.hasNext()) {
                File file = (File) inboundEndpointIterator.next();
                try {
                    OMElement document = getOMElement(file);
                    InboundEndpoint inboundEndpoint = SynapseXMLConfigurationFactory.defineInboundEndpoint(synapseConfig, document, properties);
                    if (inboundEndpoint != null) {
                        inboundEndpoint.setFileName(file.getName());
                        synapseConfig.getArtifactDeploymentStore().addArtifact(file.getAbsolutePath(),
                                inboundEndpoint.getName());
                    }
                } catch (Exception e) {
                    String msg = "Inbound Endpoint configuration cannot be built from : " + file.getName();
                    handleConfigurationError(SynapseConstants.FAIL_SAFE_MODE_INBOUND_ENDPOINT, msg, e);
                }
            }
        }
    }



    private static OMElement getOMElement(File file) {
        FileInputStream is;
        OMElement document = null;

        try {
            is = FileUtils.openInputStream(file);
        } catch (IOException e) {
            handleException("Error while opening the file: " + file.getName() + " for reading", e);
            return null;
        }

        try {
            document = new StAXOMBuilder(is).getDocumentElement();
            document.build();
            is.close();
        } catch (XMLStreamException e) {
            handleException("Error while parsing the content of the file: " + file.getName(), e);
        } catch (IOException e) {
            log.warn("Error while closing the input stream from the file: " + file.getName(), e);
        }

        return document;
    }

    private static void handleConfigurationError(String componentType, String msg, Exception e) {
        if (SynapseConfigUtils.isFailSafeEnabled(componentType)) {
            log.warn(msg + " - Continue in fail-safe mode", e);
        } else {
            log.error(msg, e);
            throw new SynapseException(msg, e);
        }
    }

    private static void handleException(String msg, Exception e) {
        log.error(msg, e);
        throw new SynapseException(msg, e);
    }
}
