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

com.izforge.izpack.util.xmlmerge.action.FullMergeAction Maven / Gradle / Ivy

There is a newer version: 5.2.3
Show newest version
/*
 * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
 *
 * http://izpack.org/
 * http://izpack.codehaus.org/
 *
 * Copyright 2009 Laurent Bovet, Alex Mathey
 * Copyright 2010 Rene Krell
 *
 * Licensed 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 com.izforge.izpack.util.xmlmerge.action;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Content;
import org.jdom.Element;
import org.jdom.Text;

import com.izforge.izpack.util.*;
import com.izforge.izpack.util.xmlmerge.*;

/**
 * Merge implementation traversing element contents undependend of their order.
 */
public class FullMergeAction extends AbstractMergeAction
{

    /**
     * {@inheritDoc}
     */
    public void perform(Element originalElement, Element patchElement, Element outputParentElement)
            throws AbstractXmlMergeException
    {

        Debug.log("Merging: " + originalElement + "(List 1) and " + patchElement + "(List 2)");

        Mapper mapper = (Mapper) m_mapperFactory.getOperation(originalElement, patchElement);

        if (originalElement == null)
        {
            outputParentElement.addContent(mapper.map(patchElement));
        }
        else if (patchElement == null)
        {
            outputParentElement.addContent((Content) originalElement.clone());
        }
        else
        {

            Element workingElement = new Element(originalElement.getName(), originalElement
                    .getNamespacePrefix(), originalElement.getNamespaceURI());
            addAttributes(workingElement, originalElement);

            Debug.log("Adding " + workingElement);
            outputParentElement.addContent(workingElement);

            doIt(workingElement, originalElement, patchElement);
        }

    }

    /**
     * Performs the actual merge between two source elements.
     *
     * @param parentOut The merged element
     * @param origElement The first source element
     * @param patchElement The second source element
     * @throws AbstractXmlMergeException If an error occurred during the merge
     */
    private void doIt(Element parentOut, Element origElement, Element patchElement)
            throws AbstractXmlMergeException
    {
        addAttributes(parentOut, patchElement);

        List origContentList = origElement.getContent();
        List patchContentList = patchElement.getContent();
        List unmatchedPatchContentList = new ArrayList();
        List matchedPatchContentList = new ArrayList();

        for (Content origContent : origContentList)
        {
            Debug.log("Checking original content: " + origContent + " for matching patch contents");
            if (origContent instanceof Element)
            {
                boolean patchMatched = false;

                for (Content patchContent : patchContentList)
                {
                    Debug.log("Checking patch content: " + patchContent);

                    if (patchContent instanceof Comment || patchContent instanceof Text)
                    {
                        // skip and leave original comment or text
                        Debug.log("Skipped patch content: " + patchContent);
                    }
                    else if (!(patchContent instanceof Element))
                    {
                        throw new DocumentException(patchContent.getDocument(), "Contents of type "
                                + patchContent.getClass().getName() + " in patch document not supported");
                    }
                    else
                    {
                        if (((Matcher) m_matcherFactory.getOperation((Element) patchContent, (Element) origContent))
                                .matches((Element) patchContent, (Element) origContent))
                        {
                            Debug.log("Apply matching patch: " + patchContent + " -> " + origContent);
                            applyAction(parentOut, (Element) origContent, (Element) patchContent);
                            patchMatched = true;
                            if (!matchedPatchContentList.contains(patchContent))
                            {
                                matchedPatchContentList.add(patchContent);
                            }
                        }
                        else
                        {
                            if (!unmatchedPatchContentList.contains(patchContent))
                            {
                                unmatchedPatchContentList.add(patchContent);
                            }
                        }
                        // Continue searching here for finding multiple matches
                    }
                }

                if (!patchMatched)
                {
                    Debug.log("Apply original: "+ origContent);
                    applyAction(parentOut, (Element) origContent, null);
                }
            }
            else if (origContent instanceof Comment || origContent instanceof Text)
            {
                // leave original comment or text
                parentOut.addContent((Content) origContent.clone());
            }
            else
            {
                throw new DocumentException(origContent.getDocument(), "Contents of type "
                        + origContent.getClass().getName() + " in original document not supported");
            }
        }

        for (Content unmatchedPatchContent : unmatchedPatchContentList)
        {
            if (!matchedPatchContentList.contains(unmatchedPatchContent))
            {
                Debug.log("Apply unmatching patch: "+ unmatchedPatchContent);
                applyAction(parentOut, null, (Element) unmatchedPatchContent);
            }
        }
    }

    /**
     * Applies the action which performs the merge between two source elements.
     *
     * @param workingParent Output parent element
     * @param originalElement Original element
     * @param patchElement Patch element
     * @throws AbstractXmlMergeException if an error occurred during the merge
     */
    private void applyAction(Element workingParent, Element originalElement, Element patchElement)
            throws AbstractXmlMergeException
    {
        Action action = (Action) m_actionFactory.getOperation(originalElement, patchElement);
        Mapper mapper = (Mapper) m_mapperFactory.getOperation(originalElement, patchElement);

        // Propagate the factories to deeper merge actions
        // TODO: find a way to make it cleaner
        if (action instanceof MergeAction)
        {
            MergeAction mergeAction = (MergeAction) action;
            mergeAction.setActionFactory(m_actionFactory);
            mergeAction.setMapperFactory(m_mapperFactory);
            mergeAction.setMatcherFactory(m_matcherFactory);
        }

        action.perform(originalElement, mapper.map(patchElement), workingParent);
    }

    /**
     * Adds attributes from in element to out element.
     *
     * @param out out element
     * @param in in element
     */
    private void addAttributes(Element out, Element in)
    {

        LinkedHashMap allAttributes = new LinkedHashMap();

        List outAttributes = new ArrayList(out.getAttributes());
        List inAttributes = new ArrayList(in.getAttributes());

        for (Attribute attr : outAttributes)
        {
            attr.detach();
            allAttributes.put(attr.getQualifiedName(), attr);
            Debug.log("adding attr from out:" + attr);
        }

        for (Attribute attr : inAttributes)
        {
            attr.detach();
            allAttributes.put(attr.getQualifiedName(), attr);
            Debug.log("adding attr from in:" + attr);
        }

        out.setAttributes(new ArrayList(allAttributes.values()));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy