| /* |
| * 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.apache.jackrabbit.oak.plugins.document; |
| |
| import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState; |
| import org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState; |
| import org.apache.jackrabbit.oak.spi.state.AbstractNodeState; |
| import org.apache.jackrabbit.oak.spi.state.EqualsDiff; |
| import org.apache.jackrabbit.oak.spi.state.NodeState; |
| import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; |
| import org.apache.jackrabbit.oak.commons.PerfLogger; |
| import org.jetbrains.annotations.NotNull; |
| import org.slf4j.LoggerFactory; |
| |
| import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE; |
| |
| public abstract class AbstractDocumentNodeState extends AbstractNodeState { |
| private static final PerfLogger perfLogger = new PerfLogger( |
| LoggerFactory.getLogger(AbstractDocumentNodeState.class.getName() |
| + ".perf")); |
| |
| public abstract String getPath(); |
| |
| public abstract RevisionVector getLastRevision(); |
| |
| public abstract RevisionVector getRootRevision(); |
| |
| public abstract boolean isFromExternalChange(); |
| |
| /** |
| * Creates a copy of this {@code DocumentNodeState} with the |
| * {@link #getRootRevision()} set to the given {@code root} revision. This method |
| * returns {@code this} instance if the given {@code root} revision is |
| * the same as the one in this instance and the {@link #isFromExternalChange()} |
| * flags are equal. |
| * |
| * @param root the root revision for the copy of this node state. |
| * @param externalChange if the {@link #isFromExternalChange()} flag must be |
| * set on the returned node state. |
| * @return a copy of this node state with the given root revision and |
| * external change flag. |
| */ |
| public abstract AbstractDocumentNodeState withRootRevision(@NotNull RevisionVector root, |
| boolean externalChange); |
| |
| public abstract boolean hasNoChildren(); |
| |
| protected abstract NodeStateDiffer getNodeStateDiffer(); |
| |
| //--------------------------< NodeState >----------------------------------- |
| |
| @Override |
| public boolean equals(Object that) { |
| if (this == that) { |
| return true; |
| } else if (that instanceof AbstractDocumentNodeState) { |
| AbstractDocumentNodeState other = (AbstractDocumentNodeState) that; |
| if (!getPath().equals(other.getPath())) { |
| // path does not match: not equals |
| // (even if the properties are equal) |
| return false; |
| } |
| if (revisionEquals(other)) { |
| return true; |
| } |
| // revision does not match: might still be equals |
| } else if (that instanceof ModifiedNodeState) { |
| ModifiedNodeState modified = (ModifiedNodeState) that; |
| if (modified.getBaseState() == this) { |
| return EqualsDiff.equals(this, modified); |
| } |
| } |
| if (that instanceof NodeState) { |
| return AbstractNodeState.equals(this, (NodeState) that); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean compareAgainstBaseState(NodeState base, NodeStateDiff diff) { |
| if (this == base) { |
| return true; |
| } else if (base == EMPTY_NODE || !base.exists()) { |
| // special case |
| return EmptyNodeState.compareAgainstEmptyState(this, diff); |
| } else if (base instanceof AbstractDocumentNodeState) { |
| AbstractDocumentNodeState mBase = (AbstractDocumentNodeState) base; |
| if (getPath().equals(mBase.getPath())){ |
| if (revisionEquals(mBase)) { |
| // no differences |
| return true; |
| } else { |
| // use DocumentNodeStore compare |
| final long start = perfLogger.start(); |
| try { |
| return getNodeStateDiffer().compare(this, mBase, diff); |
| } finally { |
| if (start > 0) { |
| perfLogger |
| .end(start, |
| 1, |
| "compareAgainstBaseState, path={}, lastRevision={}, base.path={}, base.lastRevision={}", |
| getPath(), getLastRevision(), |
| mBase.getPath(), mBase.getLastRevision()); |
| } |
| } |
| } |
| } |
| } |
| // fall back to the generic node state diff algorithm |
| return super.compareAgainstBaseState(base, diff); |
| } |
| |
| //------------------------------< internal >-------------------------------- |
| |
| /** |
| * Returns {@code true} if this state has the same last revision as the |
| * {@code other} state. |
| * |
| * @param other the other state to compare with. |
| * @return {@code true} if the last revisions are equal, {@code false} otherwise. |
| */ |
| private boolean revisionEquals(AbstractDocumentNodeState other) { |
| return this.getLastRevision() != null |
| && this.getLastRevision().equals(other.getLastRevision()); |
| } |
| } |