blob: aed3151eb2c56224b9a84f307efda01fe7f445d2 [file] [log] [blame]
/*
* 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.version;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.jetbrains.annotations.NotNull;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONLABELS;
import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
import static org.apache.jackrabbit.oak.commons.PathUtils.getDepth;
import static org.apache.jackrabbit.oak.commons.PathUtils.relativize;
import static org.apache.jackrabbit.oak.spi.state.AbstractNodeState.comparePropertiesAgainstBaseState;
import static org.apache.jackrabbit.oak.spi.version.VersionConstants.VERSION_NODE_TYPE_NAMES;
import static org.apache.jackrabbit.oak.spi.version.VersionConstants.VERSION_STORE_INIT;
import static org.apache.jackrabbit.oak.spi.version.VersionConstants.VERSION_STORE_NT_NAMES;
import static org.apache.jackrabbit.oak.spi.version.VersionConstants.VERSION_STORE_PATH;
/**
* Validates changes on the version store.
*/
class VersionStorageEditor extends DefaultEditor {
private static final int VERSION_HISTORY_DEPTH = 6;
private final NodeBuilder versionStorageNode;
private final NodeBuilder workspaceRoot;
private final NodeBuilder builder;
private final String path;
private boolean initPhase;
private ReadWriteVersionManager vMgr;
VersionStorageEditor(@NotNull NodeBuilder versionStorageNode,
@NotNull NodeBuilder workspaceRoot) {
this(versionStorageNode, workspaceRoot, versionStorageNode,
VERSION_STORE_PATH, false);
}
private VersionStorageEditor(@NotNull NodeBuilder versionStorageNode,
@NotNull NodeBuilder workspaceRoot,
@NotNull NodeBuilder builder,
@NotNull String path,
boolean initPhase) {
this.versionStorageNode = checkNotNull(versionStorageNode);
this.workspaceRoot = checkNotNull(workspaceRoot);
this.builder = checkNotNull(builder);
this.path = checkNotNull(path);
this.initPhase = initPhase;
}
@Override
public void enter(NodeState before, NodeState after) {
if (VERSION_STORE_PATH.equals(path)) {
initPhase = isInitializationPhase(before, after);
}
}
@Override
public Editor childNodeChanged(String name,
NodeState before,
NodeState after)
throws CommitFailedException {
int d = getDepth(path);
String p = concat(path, name);
if (d == VERSION_HISTORY_DEPTH
&& name.equals(JCR_VERSIONLABELS)) {
return new VersionLabelsEditor(p, getVersionManager());
}
if (d < VERSION_HISTORY_DEPTH && !isVersionStorageNode(after)) {
return null;
}
return new VersionStorageEditor(versionStorageNode, workspaceRoot, builder.child(name), p, initPhase);
}
@Override
public Editor childNodeAdded(String name, NodeState after)
throws CommitFailedException {
int d = getDepth(path);
// allow child nodes under version storage node, unless an attempt
// is made to create rep:versionStorage nodes manually.
if (d == getDepth(VERSION_STORE_PATH) &&
!isVersionStorageNode(after)) {
return null;
}
// allow node addition during initialization phase
if (initPhase) {
return null;
}
return throwProtected(name);
}
@Override
public Editor childNodeDeleted(String name, NodeState before)
throws CommitFailedException {
int d = getDepth(path);
if (d == VERSION_HISTORY_DEPTH) {
// restore version on builder
builder.setChildNode(name, before);
String relPath = relativize(VERSION_STORE_PATH, concat(path, name));
// let version manager remove it properly
getVersionManager().removeVersion(relPath);
return null;
} else if (isVersionStorageNode(before) || d > VERSION_HISTORY_DEPTH) {
throwProtected(name);
}
return null;
}
@Override
public void propertyAdded(PropertyState after)
throws CommitFailedException {
if (getDepth(path) < VERSION_HISTORY_DEPTH) {
return;
}
throwProtected(after.getName());
}
@Override
public void propertyChanged(PropertyState before, PropertyState after)
throws CommitFailedException {
if (getDepth(path) < VERSION_HISTORY_DEPTH) {
return;
}
throwProtected(before.getName());
}
@Override
public void propertyDeleted(PropertyState before)
throws CommitFailedException {
if (getDepth(path) < VERSION_HISTORY_DEPTH) {
return;
}
throwProtected(before.getName());
}
//-------------------------< internal >-------------------------------------
private static boolean isVersionStorageNode(NodeState state) {
String ntName = state.getName(JCR_PRIMARYTYPE);
return VERSION_STORE_NT_NAMES.contains(ntName)
|| VERSION_NODE_TYPE_NAMES.contains(ntName);
}
private ReadWriteVersionManager getVersionManager() {
if (vMgr == null) {
vMgr = new ReadWriteVersionManager(versionStorageNode, workspaceRoot);
}
return vMgr;
}
private Editor throwProtected(String name) throws CommitFailedException {
return Utils.throwProtected(concat(path, name));
}
private static boolean isInitializationPhase(NodeState before, NodeState after) {
return !comparePropertiesAgainstBaseState(after, before, new DefaultNodeStateDiff() {
@Override
public boolean propertyAdded(PropertyState after) {
return !after.getName().equals(VERSION_STORE_INIT);
}
});
}
}