com.izforge.izpack.util.xmlmerge.action.OrderedMergeAction Maven / Gradle / Ivy
/*
* 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 parallelly both element contents. Works when contents are in the
* same order in both elements.
*
* @author Laurent Bovet (LBO)
* @author Alex Mathey (AMA)
*/
public class OrderedMergeAction 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 parentIn1 The first source element
* @param parentIn2 The second source element
* @throws AbstractXmlMergeException If an error occurred during the merge
*/
private void doIt(Element parentOut, Element parentIn1, Element parentIn2)
throws AbstractXmlMergeException
{
addAttributes(parentOut, parentIn2);
Content[] list1 = (Content[]) parentIn1.getContent().toArray(new Content[] {});
Content[] list2 = (Content[]) parentIn2.getContent().toArray(new Content[] {});
int offsetTreated1 = 0;
int offsetTreated2 = 0;
for (Content content1 : list1)
{
Debug.log("List 1: " + content1);
if (content1 instanceof Comment || content1 instanceof Text)
{
parentOut.addContent((Content) content1.clone());
offsetTreated1++;
}
else if (!(content1 instanceof Element))
{
throw new DocumentException(content1.getDocument(), "Contents of type "
+ content1.getClass().getName() + " not supported");
}
else
{
Element e1 = (Element) content1;
// does e1 exist on list2 and has not yet been treated
int posInList2 = -1;
for (int j = offsetTreated2; j < list2.length; j++)
{
Debug.log("List 2: " + list2[j]);
if (list2[j] instanceof Element)
{
if (((Matcher) m_matcherFactory.getOperation(e1, (Element) list2[j]))
.matches(e1, (Element) list2[j]))
{
Debug.log("Match found: " + e1 + " and " + list2[j]);
posInList2 = j;
break;
}
}
else if (list2[j] instanceof Comment || list2[j] instanceof Text)
{
// skip
}
else
{
throw new DocumentException(list2[j].getDocument(), "Contents of type "
+ list2[j].getClass().getName() + " not supported");
}
}
// element found in second list, but there is some elements to
// be treated before in second list
while (posInList2 != -1 && offsetTreated2 < posInList2)
{
Content contentToAdd;
if (list2[offsetTreated2] instanceof Element)
{
applyAction(parentOut, null, (Element) list2[offsetTreated2]);
}
else
{
// FIXME prevent double comments in output by enhancing applyAction() to
// Content type instead of Element
// Workaround: Add only comments from original document (List1)
if (!(list2[offsetTreated2] instanceof Comment))
{
contentToAdd = (Content) list2[offsetTreated2].clone();
parentOut.addContent(contentToAdd);
}
}
offsetTreated2++;
}
// element found in all lists
if (posInList2 != -1)
{
applyAction(parentOut, (Element) list1[offsetTreated1],
(Element) list2[offsetTreated2]);
offsetTreated1++;
offsetTreated2++;
}
else
{
// element not found in second list
applyAction(parentOut, (Element) list1[offsetTreated1], null);
offsetTreated1++;
}
}
}
// at the end of list1, are there some elements in list2 which must be still treated?
while (offsetTreated2 < list2.length)
{
Content contentToAdd;
if (list2[offsetTreated2] instanceof Element)
{
applyAction(parentOut, null, (Element) list2[offsetTreated2]);
}
else
{
// FIXME prevent double comments in output by enhancing applyAction() to Content
// type instead of Element
// Workaround: Add only comments from original document (List1)
if (!(list2[offsetTreated2] instanceof Comment))
{
contentToAdd = (Content) list2[offsetTreated2].clone();
parentOut.addContent(contentToAdd);
}
}
offsetTreated2++;
}
}
/**
* 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