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

org.openxma.hbmfilemerge.HbmFileMerge Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
package org.openxma.hbmfilemerge;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class HbmFileMerge {
    private static final String HIBERNATE_DOCTYPE_SYSTEM = "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd";
    private static final String HIBERNATE_DOCTYPE_PUBLIC = "-//Hibernate/Hibernate Mapping DTD//EN";

    private static final DocumentBuilderFactory DOC_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();

    private DocumentBuilder _builder;
    private HbmFileMergeInput _input;

    private HbmFileMerge(HbmFileMergeInput input) {
        if (null == input)
            throw new IllegalArgumentException("missing input");

        _input = input;
        initDocumentBuilder();
    }

    public static HbmFileMerge getInstance(File resourcesFolder, File resourcesGenFolder) {
        return new HbmFileMerge(HbmFileMergeInput.getInstance(resourcesFolder, resourcesGenFolder));
    }

    /**
     * @param fragmentHbm
     *            the custom hbm.xml to be merged with the generated hbm.xml
     * @throws SAXException
     * @throws IOException
     * @throws XPathExpressionException
     * @throws TransformerException
     */
    public String mergeGenHbmWith(File fragmentHbm) throws SAXException, IOException, XPathExpressionException,
            TransformerException {
        return merge(_input.getMergeInputByFragmentHbm(fragmentHbm));
    }

    /**
     * @param genHbm
     *            the generated hbm.xml to be merged with the fragment hbm xml
     * @throws SAXException
     * @throws IOException
     * @throws XPathExpressionException
     * @throws TransformerException
     */
    public String mergeFragmentHbmWith(File genHbm) throws SAXException, IOException, XPathExpressionException,
            TransformerException {
        return merge(_input.getMergeInputByGenHbm(genHbm));
    }

    private void initDocumentBuilder() {
        try {
            _builder = DOC_BUILDER_FACTORY.newDocumentBuilder();

            // skip resolving (external) DTDs
            _builder.setEntityResolver(new EntityResolver() {
                public InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId)
                        throws SAXException, java.io.IOException {
                    if (systemId.endsWith(".dtd"))
                        // this deactivates all DTDs by giving empty XML docs
                        return new InputSource(new ByteArrayInputStream(""
                                .getBytes()));
                    else
                        return null;
                }
            });
        } catch (ParserConfigurationException e) {
            throw new IllegalStateException("could not create DocumentBuilder", e);
        }
    }

    private String merge(HbmFilePair genFragmentPair) throws SAXException, IOException, XPathExpressionException,
            TransformerException {
        if (null == genFragmentPair)
            return null;
        Document mergedDoc = merge(genFragmentPair.getGenHbm(), genFragmentPair.getFragmentHbm());
        // then nothing was merged, because the fragment did not contain any
        // nodes
        if (null == mergedDoc)
            return createMergedHbmFileName(genFragmentPair.getGenHbm());

        return saveStateToHbmFile(genFragmentPair.getGenHbm(), mergedDoc);
    }

    private String saveStateToHbmFile(File genHbm, Document doc) throws IOException, TransformerException {
        String pathToHbmXml = createMergedHbmFileName(genHbm);
        createTransformer().transform(new DOMSource(doc),
                new StreamResult(new FileOutputStream(new File(pathToHbmXml))));
        return pathToHbmXml;
    }

    private Transformer createTransformer() throws TransformerConfigurationException {
        TransformerFactory transFactory = TransformerFactory.newInstance();
        Transformer transformer = transFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, HIBERNATE_DOCTYPE_PUBLIC);
        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, HIBERNATE_DOCTYPE_SYSTEM);
        return transformer;
    }

    private String createMergedHbmFileName(File genHbm) throws IOException {
        String path = genHbm.getCanonicalPath();
        return path.replace(new StringBuffer().append(HbmFileNameSuffix.GEN).append("."), "");
    }

    private Document merge(File genHbm, File fragment) throws SAXException, IOException, XPathExpressionException,
            TransformerException {
        if (null == fragment || null == genHbm)
            return null;

        Map fragmentNodeList = new HashMap();
        for (XmlElement xmlElement : XmlElement.values()) {
            NodeList nodes = getFragmentNodeListByXmlElement(fragment, xmlElement);
            if (nodes.getLength() > 0)
                fragmentNodeList.put(xmlElement, nodes);
        }

        return mergeFragmentIntoGenHbm(parseFile(genHbm), fragmentNodeList);
    }

    private Document mergeFragmentIntoGenHbm(Document genHbm, Map fragmentNodeList)
            throws XPathExpressionException, SAXException, IOException, TransformerException {
        if (fragmentNodeList.isEmpty())
            return null;

        for (Entry entry : fragmentNodeList.entrySet())
            replaceWithFragments(entry.getKey(), entry.getValue(), genHbm);

        return genHbm;
    }

    private void replaceWithFragments(XmlElement xmlElement, NodeList fragmentNodeList, Document genHbm)
            throws XPathExpressionException, SAXException, IOException, TransformerException {

        for (int i = 0; i < fragmentNodeList.getLength(); i++) {
            replaceWithFragment(xmlElement, fragmentNodeList.item(i), genHbm);
        }
    }

    private void replaceWithFragment(XmlElement xmlElement, Node fragmentNode, Document genHbm)
            throws XPathExpressionException, DOMException, SAXException, IOException, TransformerException {
        Node relevantGenHbmNode = getRelevantGenHbmNode(xmlElement, fragmentNode, genHbm);
        if (null == relevantGenHbmNode) {
            //add this element
            xmlElement.getParentNode(genHbm).appendChild(genHbm.importNode(fragmentNode, true));
        } else if (XmlElement.CLASS.equals(xmlElement)) {
            //special merge mode for class element: only attributes will be merged
            mergeClassXmlElementAttributes(relevantGenHbmNode, fragmentNode, genHbm);
        } else {
            //merge this element
            xmlElement.getParentNode(genHbm).replaceChild(genHbm.importNode(fragmentNode, true), relevantGenHbmNode);
        }
    }

    private void mergeClassXmlElementAttributes(Node relevantGenHbmNode, Node fragmentNode, Document genHbm)
            throws XPathExpressionException, DOMException, SAXException, IOException, TransformerException {
        NamedNodeMap fragmentNodeAttrs = fragmentNode.getAttributes();
        for (int i = 0; i < fragmentNodeAttrs.getLength(); i++) {
            Node next = fragmentNodeAttrs.item(i);
            Node relAttr = relevantGenHbmNode.getAttributes().getNamedItem(next.getNodeName());

            if (null == relAttr) {
                ((Element) relevantGenHbmNode).setAttribute(next.getNodeName(), next.getNodeValue());
            } else {
                relAttr.setNodeValue(next.getNodeValue());
            }
        }
    }

    private Node getRelevantGenHbmNode(XmlElement xmlElement, Node fragmentNode, Document genHbm)
            throws XPathExpressionException, SAXException, IOException {
        if (xmlElement.isSelfIdentified()) {
            return (Node) xmlElement.getXpathExpr().evaluate(genHbm, XPathConstants.NODE);
        } else {
            XmlElementAttributeDto props = xmlElement.getIdAttrValueFromFragmentIdAttrNode(fragmentNode);
            return (Node) xmlElement.getRelevantGenHbmNodeXPathExpression(props).evaluate(genHbm, XPathConstants.NODE);
        }
    }

    private NodeList getFragmentNodeListByXmlElement(File fragment, XmlElement xmlElement) throws SAXException,
            IOException, XPathExpressionException {
        return (NodeList) xmlElement.getXpathExpr().evaluate(parseFile(fragment), XPathConstants.NODESET);
    }

    private Document parseFile(File toParse) throws SAXException, IOException {
        if (null == toParse || !toParse.isFile())
            throw new IllegalArgumentException("missing file or is no file");

        try {
            // we do this extensive error logging, in order localise encoding
            // problems in hbm xml files
            return _builder.parse(toParse);
        } catch (SAXParseException spe) {
            String err = spe.toString() + "\n  Line number: " + spe.getLineNumber() + "\nColumn number: "
                    + spe.getColumnNumber() + "\n Public ID: " + spe.getPublicId() + "\n System ID: "
                    + spe.getSystemId();
            System.out.println(err);
            throw new RuntimeException(err);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy