All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dexcoder.dal.batis.xml.XMLIncludeTransformer Maven / Gradle / Ivy

package com.dexcoder.dal.batis.xml;

import java.util.Properties;

import com.dexcoder.dal.batis.build.Configuration;
import com.dexcoder.dal.batis.parser.PropertyParser;
import com.dexcoder.dal.batis.build.MapperBuilderAssistant;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.dexcoder.dal.exceptions.JdbcAssistantException;

/**
 * Created by liyd on 2015-11-24.
 */
public class XMLIncludeTransformer {

    private final Configuration configuration;
    private final MapperBuilderAssistant builderAssistant;

    public XMLIncludeTransformer(Configuration configuration, MapperBuilderAssistant builderAssistant) {
        this.configuration = configuration;
        this.builderAssistant = builderAssistant;
    }

    public void applyIncludes(Node source) {
        Properties variablesContext = new Properties();
        Properties configurationVariables = configuration.getVariables();
        if (configurationVariables != null) {
            variablesContext.putAll(configurationVariables);
        }
        applyIncludes(source, variablesContext);
    }

    /**
     * Recursively apply includes through all SQL fragments.
     *
     * @param source           Include node in DOM tree
     * @param variablesContext Current context for static variables with values
     */
    private void applyIncludes(Node source, final Properties variablesContext) {
        if (source.getNodeName().equals("include")) {
            // new full context for included SQL - contains inherited context and new variables from current include node
            Properties fullContext;

            String refId = getStringAttribute(source, "refid");
            // replace variables in include refid value
            refId = PropertyParser.parse(refId, variablesContext);
            Node toInclude = findSqlFragment(refId);
            Properties newVariablesContext = getVariablesContext(source, variablesContext);
            if (!newVariablesContext.isEmpty()) {
                // merge contexts
                fullContext = new Properties();
                fullContext.putAll(variablesContext);
                fullContext.putAll(newVariablesContext);
            } else {
                // no new context - use inherited fully
                fullContext = variablesContext;
            }
            applyIncludes(toInclude, fullContext);
            if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
                toInclude = source.getOwnerDocument().importNode(toInclude, true);
            }
            source.getParentNode().replaceChild(toInclude, source);
            while (toInclude.hasChildNodes()) {
                toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
            }
            toInclude.getParentNode().removeChild(toInclude);

            //           DocUtils.toStringFromDoc(source.getOwnerDocument()) ;
        } else if (source.getNodeType() == Node.ELEMENT_NODE) {
            NodeList children = source.getChildNodes();
            for (int i = 0; i < children.getLength(); i++) {
                applyIncludes(children.item(i), variablesContext);
            }
        } else if (source.getNodeType() == Node.ATTRIBUTE_NODE && !variablesContext.isEmpty()) {
            // replace variables in all attribute values
            source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
        } else if (source.getNodeType() == Node.TEXT_NODE && !variablesContext.isEmpty()) {
            // replace variables ins all text nodes
            source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
        }
    }

    private Node findSqlFragment(String refid) {
        refid = builderAssistant.applyCurrentNamespace(refid, true);
        try {
            XNode nodeToInclude = configuration.getSqlFragments().get(refid);
            return nodeToInclude.getNode().cloneNode(true);
        } catch (Exception e) {
            throw new JdbcAssistantException("Could not find SQL statement to include with refid '" + refid + "'", e);
        }
    }

    private String getStringAttribute(Node node, String name) {
        return node.getAttributes().getNamedItem(name).getNodeValue();
    }

    /**
     * Read placholders and their values from include node definition.
     *
     * @param node                      Include node instance
     * @param inheritedVariablesContext Current context used for replace variables in new variables values
     * @return variables context from include instance (no inherited values)
     */
    private Properties getVariablesContext(Node node, Properties inheritedVariablesContext) {
        Properties variablesContext = new Properties();
        NodeList children = node.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node n = children.item(i);
            if (n.getNodeType() == Node.ELEMENT_NODE) {
                String name = getStringAttribute(n, "name");
                String value = getStringAttribute(n, "value");
                // Replace variables inside
                value = PropertyParser.parse(value, inheritedVariablesContext);
                // Push new value
                Object originalValue = variablesContext.put(name, value);
                if (originalValue != null) {
                    throw new JdbcAssistantException("Variable " + name
                                                     + " defined twice in the same include definition");
                }
            }
        }
        return variablesContext;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy