Package org.openoffice.xmerge.merger.merge

Source Code of org.openoffice.xmerge.merger.merge.DocumentMerge

/**************************************************************
*
* 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.openoffice.xmerge.merger.merge;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.openoffice.xmerge.ConverterCapabilities;
import org.openoffice.xmerge.MergeException;
import org.openoffice.xmerge.merger.MergeAlgorithm;
import org.openoffice.xmerge.merger.NodeMergeAlgorithm;
import org.openoffice.xmerge.merger.Iterator;
import org.openoffice.xmerge.merger.Difference;
import org.openoffice.xmerge.util.XmlUtil;

/**
* This is an implementation of the <code>MergeAlgorithm</code> interface.
* This class will merge two <code>Document</code> classes.  It utilizes the
* appropriate class which implements {@link
* org.openoffice.xmerge.merger.NodeMergeAlgorithm
* NodeMergeAlgorithm} to perform the merge.
*
* @author smak
*/
public class DocumentMerge implements MergeAlgorithm {

    private NodeMergeAlgorithm subDocumentMerge = null;

    /**  The capabilities of this converter. */
    protected ConverterCapabilities cc_;


    /**
     *  Constructor
     *
     *  @param  cc     The <code>ConverterCapabilities</code>.
     *  @param  merge  The <code>NodeMergeAlgorithm</code>.
     */
    public DocumentMerge(ConverterCapabilities cc, NodeMergeAlgorithm merge) {
        cc_ = cc;
        subDocumentMerge = merge;
    }


    public void applyDifference(Iterator orgSeq, Iterator modSeq,
                            Difference[] differences) throws MergeException {


        // a quick test whether the differences array is in ascending order
        int currentPosition = -1;
        boolean haveDeleteOperation = false;

        for (int i = 0; i < differences.length; i++) {
            if (differences[i].getOrgPosition() > currentPosition) {
                currentPosition = differences[i].getOrgPosition();
                if (differences[i].getOperation() == Difference.DELETE) {
                    haveDeleteOperation = true;
                } else  {
                    haveDeleteOperation = false;
                }
            } else if (differences[i].getOrgPosition() == currentPosition) {
                if (differences[i].getOperation() == Difference.DELETE) {
                    haveDeleteOperation = true;
                } else if (differences[i].getOperation() == Difference.ADD &&
                            haveDeleteOperation == true) {
                    throw new MergeException(
                         "Differences array is not sorted. Delete before Add");
                }
            } else {
               throw new MergeException("Differences array need to be sorted.");
            }
        }

        // reset sequence counters
        orgSeq.start();
        int orgSeqCounter = 0;

        modSeq.start();
        int modSeqCounter = 0;

        // check for each diff unit in the diff array to apply the diff
        for (int i = 0; i < differences.length; i++) {

            Difference currentDiff = differences[i];

            int operation = currentDiff.getOperation();

            Object currentElement;

            switch (operation) {

            case Difference.DELETE:
                // loop through the original sequence up to the expected
                // position. note that we use delta (see above comment)
                // also. we will just continue the counter without reset it.
                for (;
                     orgSeqCounter < currentDiff.getOrgPosition();
                     orgSeqCounter++, orgSeq.next()) {
                    // empty
                }

                // remove the Node. note that it will NOT affect the
                // iterator sequence as ParaNodeIterator is a static one.
                removeNode((Node)(orgSeq.currentElement()));

                break;

            // if it's an add operation, then get content from original seq
            case Difference.ADD:
                // loop through the modified sequence up to the expected
                // position to get the content. As we don't need to modify
                // the sequence. we don't need to use delta to do adjustment.
                for (;
                     modSeqCounter < currentDiff.getModPosition();
                     modSeqCounter++, modSeq.next()) {
                    // empty
                }

                currentElement = orgSeq.currentElement();

                for (;
                     orgSeqCounter < currentDiff.getOrgPosition();
                     orgSeqCounter++, currentElement = orgSeq.next()) {
                    // empty
                }

                if (orgSeqCounter > orgSeq.elementCount() - 1) {
                    // append the element to the end of the original sequence
                    appendNode((Node)(orgSeq.currentElement()),
                               (Node)(modSeq.currentElement()));
                } else {
                    // insert the element BEFORE the current element
                    insertNode((Node)(orgSeq.currentElement()),
                               (Node)(modSeq.currentElement()));
                }

                break;

            case Difference.CHANGE:
                for (;
                     modSeqCounter < currentDiff.getModPosition();
                     modSeqCounter++, modSeq.next()) {
                    // empty
                }

                currentElement = orgSeq.currentElement();

                for (;
                     orgSeqCounter < currentDiff.getOrgPosition();
                     orgSeqCounter++, currentElement = orgSeq.next()) {
                    // empty
                }

                if (subDocumentMerge == null) {
                    // use a simple replace if no row merge algorithm supply
                    replaceElement((Element)orgSeq.currentElement(),
                                   (Element)modSeq.currentElement());
                } else {
                    subDocumentMerge.merge((Element)orgSeq.currentElement(),
                                         (Element)modSeq.currentElement());

                }
                break;

            default:
                break;
            }
        }
    }


    /**
     *  Removes the specified <code>Node</code>.
     *
     *  @param  node  <code>Node</code> to remove.
     */
    protected void removeNode(Node node) {

        Node parent = node.getParentNode();
        parent.removeChild(node);
    }

    /**
     *  Appends <code>Node</code> after the specified <code>Node</code>.
     *
     *  @param  oldNode  <code>Node</code> to append after.
     *  @param  newNode  <code>Node</code> to append.
     */
    protected void appendNode(Node oldNode, Node newNode) {
        Node clonedNode = XmlUtil.deepClone(oldNode, newNode);
        Node parent = oldNode.getParentNode();
        parent.appendChild(clonedNode);
    }


    /**
     *  Insert <code>Node</code> before the specified <code>Node</code>.
     *
     *  @param  oldNode  <code>Node</code> to insert before.
     *  @param  newNode  <code>Node</code> to insert.
     */
    protected void insertNode(Node oldNode, Node newNode) {
        Node clonedNode = XmlUtil.deepClone(oldNode, newNode);
        Node parent = oldNode.getParentNode();
        parent.insertBefore(clonedNode, oldNode);
    }


    /**
     *  Replace <code>Element</code>.
     *
     *  @param  currElem  <code>Element</code> to be replaced.
     *  @param  newElem   <code>Element</code> to replace.
     */
    protected void replaceElement(Element currElem, Element newElem) {

        Node clonedNode = XmlUtil.deepClone(currElem, newElem);
        Node parent = currElem.getParentNode();
        parent.replaceChild(clonedNode, currElem);
    }
}
TOP

Related Classes of org.openoffice.xmerge.merger.merge.DocumentMerge

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.