io.sirix.diff.DiffFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sirix-core Show documentation
Show all versions of sirix-core Show documentation
SirixDB is a hybrid on-disk and in-memory document oriented, versioned database system. It has a lightweight buffer manager, stores everything in a huge persistent and durable tree and allows efficient reconstruction of every revision. Furthermore, SirixDB implements change tracking, diffing and supports time travel queries.
/**
* Copyright (c) 2011, University of Konstanz, Distributed Systems Group All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met: * Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following disclaimer. * Redistributions
* in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* * Neither the name of the University of Konstanz nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.sirix.diff;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import java.util.Set;
import io.sirix.access.trx.node.HashType;
import io.sirix.api.NodeCursor;
import io.sirix.api.NodeReadOnlyTrx;
import io.sirix.api.NodeTrx;
import io.sirix.api.ResourceSession;
import io.sirix.api.json.JsonNodeReadOnlyTrx;
import io.sirix.api.json.JsonNodeTrx;
import io.sirix.api.xml.XmlNodeReadOnlyTrx;
import io.sirix.api.xml.XmlNodeTrx;
import io.sirix.api.xml.XmlResourceSession;
import io.sirix.exception.SirixException;
import org.checkerframework.checker.index.qual.NonNegative;
/**
* Factory method for public access.
*
* @author Johannes Lichtenberger, University of Konstanz
*
*/
public final class DiffFactory {
/**
* Possible kinds of differences between two nodes.
*/
public enum DiffType {
/** Nodes are the same. */
SAME,
/**
* Nodes are the same (including subtrees), internally used for optimizations.
*/
SAMEHASH,
/** Node has been inserted. */
INSERTED,
/** Node has been deleted. */
DELETED,
/** Node has been updated. */
UPDATED,
/** Node has been replaced. */
REPLACED,
/** Node has been replaced. */
REPLACEDNEW,
/** Node has been replaced. */
REPLACEDOLD,
/** Node has been moved from. */
MOVEDFROM,
/** Node has been moved to. */
MOVEDTO
}
/**
* Determines if an optimized diff calculation should be done, which is faster.
*/
public enum DiffOptimized {
/** Normal diff. */
NO,
/** Optimized diff. */
HASHED
}
/** Determines the kind of diff algorithm to invoke. */
private enum DiffAlgorithm {
/** Full diff. */
XML_FULL {
@Override
void invoke(
final Builder builder) {
@SuppressWarnings("unchecked")
final Builder xmlDiffBuilder =
(Builder) builder;
new XmlFullDiff(xmlDiffBuilder).diffMovement();
}
},
/**
* Structural diff (doesn't recognize differences in namespace and attribute nodes.
*/
XML_STRUCTURAL {
@Override
void invoke(
final Builder builder) {
@SuppressWarnings("unchecked")
final Builder xmlDiffBuilder =
(Builder) builder;
new XmlStructuralDiff(xmlDiffBuilder).diffMovement();
}
},
/**
* JSON diff.
*/
JSON {
@Override
void invoke(
final Builder builder) {
@SuppressWarnings("unchecked")
final Builder jsonDiffBuilder =
(Builder) builder;
new JsonDiff(jsonDiffBuilder).diffMovement();
}
};
/**
* Invoke diff.
*
* @param builder {@link Builder} reference
* @throws SirixException if anything while diffing goes wrong related to sirix
*/
abstract void invoke(
final Builder builder);
}
/**
* Create a new {@link Builder} instance.
*
* @param resourceManager the {@link ResourceSession} to use
* @param newRev new revision to compare
* @param oldRev old revision to compare
* @param diffKind kind of diff (optimized or not)
* @param observers {@link Set} of observers
* @return new {@link Builder} instance
*/
public static Builder builder(final XmlResourceSession resourceManager,
final @NonNegative int newRev, final @NonNegative int oldRev, final DiffOptimized diffKind,
final Set observers) {
return new Builder<>(resourceManager, newRev, oldRev, diffKind, observers);
}
/** Builder to simplify static methods. */
public static final class Builder {
/** {@link ResourceSession} reference. */
final ResourceSession resMgr;
/** Start key of new revision. */
transient long newStartKey;
/** Start key of old revision. */
transient long oldStartKey;
/** New revision. */
final int newRev;
/** Old revision. */
final int oldRev;
/** Depth of "root" node in new revision. */
transient int newDepth;
/** Depth of "root" node in old revision. */
transient int oldDepth;
/** Diff kind. */
final DiffOptimized kind;
/** {@link Set} of {@link DiffObserver}s. */
final Set observers;
/** Kind of diff to invoke. */
transient DiffAlgorithm mDiffKind;
/** Kind of hash. */
transient HashType hashKind = HashType.ROLLING;
/** Set if the GUI is used. */
transient boolean isGUI = true;
/** Determines if subtrees are skipped after detecting an insert/delete... */
transient boolean skipSubtrees = false;
/** The maximum depth. */
transient long oldMaxDepth;
/**
* Constructor.
*
* @param resMgr the {@link ResourceSession} to use
* @param newRev new revision to compare
* @param oldRev old revision to compare
* @param diffKind kind of diff (optimized or not)
* @param observers {@link Set} of observers
*/
public Builder(final ResourceSession resMgr, final @NonNegative int newRev, final @NonNegative int oldRev,
final DiffOptimized diffKind, final Set observers) {
this.resMgr = requireNonNull(resMgr);
checkArgument(newRev >= 0, "paramNewRev must be >= 0!");
this.newRev = newRev;
checkArgument(oldRev >= 0, "paramOldRev must be >= 0!");
this.oldRev = oldRev;
kind = requireNonNull(diffKind);
this.observers = requireNonNull(observers);
}
/**
* Set to true if the algorithm is used by the GUI, otherwise false.
*
* @param isGUI determines if the algorithm is used by the GUI or not
* @return this builder
*/
public Builder isGUI(final boolean isGUI) {
this.isGUI = isGUI;
return this;
}
/**
* Set start node key in old revision.
*
* @param oldKey start node key in old revision
* @return this builder
*/
public Builder oldStartKey(final @NonNegative long oldKey) {
checkArgument(oldKey >= 0, "oldKey must be >= 0!");
oldStartKey = oldKey;
return this;
}
/**
* Set old max depth.
*
* @param oldMaxDepth maximum depth of traversal
* @return this builder
*/
public Builder oldMaxDepth(final @NonNegative long oldMaxDepth) {
checkArgument(oldMaxDepth >= 0, "oldMaxDepth must be >= 0!");
this.oldMaxDepth = oldMaxDepth;
return this;
}
/**
* Set start node key in new revision.
*
* @param newKey start node key in new revision
* @return this builder
*/
public Builder newStartKey(final @NonNegative long newKey) {
checkArgument(newKey >= 0, "newKey must be >= 0!");
newStartKey = newKey;
return this;
}
/**
* Set new depth.
*
* @param newDepth depth of "root" node in new revision
* @return this builder
*/
public Builder newDepth(final @NonNegative int newDepth) {
checkArgument(newDepth >= 0, "newDepth must be >= 0!");
this.newDepth = newDepth;
return this;
}
/**
* Set old depth.
*
* @param oldDepth depth of "root" node in old revision
* @return this builder
*/
public Builder oldDepth(final int oldDepth) {
checkArgument(oldDepth >= 0, "oldDepth must be >= 0!");
this.oldDepth = oldDepth;
return this;
}
/**
* Set kind of diff-algorithm.
*
* @param diffAlgorithm {@link DiffAlgorithm} instance
*
* @return this builder
*/
public Builder diffAlgorithm(final DiffAlgorithm diffAlgorithm) {
mDiffKind = requireNonNull(diffAlgorithm);
return this;
}
/**
* Set kind of hash. Must be the same as used for the database creation.
*
* @param kind {@link HashType} instance
* @return this builder
*/
public Builder hashKind(final HashType kind) {
hashKind = requireNonNull(kind);
return this;
}
/**
* Set if subtrees after detecting an insert/delete/replace should be skipped..
*
* @param skipSubtrees {@code true}, if subtrees should be skipped, {@code false} if not
* @return this builder
*/
public Builder skipSubtrees(final boolean skipSubtrees) {
this.skipSubtrees = skipSubtrees;
return this;
}
}
/**
* Private constructor.
*/
private DiffFactory() {
// No instantiation allowed.
throw new AssertionError("No instantiation allowed!");
}
/**
* Do a full JSON diff.
*
* @param builder {@link Builder} reference
*/
public static synchronized void invokeJsonDiff(final Builder builder) {
DiffAlgorithm.JSON.invoke(builder);
}
/**
* Do a full diff.
*
* @param builder {@link Builder} reference
*/
public static synchronized void invokeFullXmlDiff(final Builder builder) {
DiffAlgorithm.XML_FULL.invoke(builder);
}
/**
* Do a structural diff.
*
* @param builder {@link Builder} reference
*/
public static synchronized void invokeStructuralXmlDiff(final Builder builder) {
DiffAlgorithm.XML_STRUCTURAL.invoke(builder);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy