All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.oak.plugins.version.VersionStorageEditor Maven / Gradle / Ivy

There is a newer version: 1.64.0
Show newest version
/*
 * 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 java.util.Arrays;
import java.util.List;
import java.util.SortedMap;

import javax.annotation.Nonnull;

import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONLABELS;
import static org.apache.jackrabbit.JcrConstants.JCR_VERSIONSTORAGE;
import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.REP_ADD_VERSION_LABELS;
import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.REP_REMOVE_VERSION_LABELS;

/**
 * Implements an editor watching for well known properties on the
 * /jcr:system/jcr:versionStorage node to trigger version operations (like
 * adding/removing labels or removing versions) on the protected version storage
 * tree.
 * 

* This editor supports the following operations: *

    *
  • {@link VersionConstants#REP_ADD_VERSION_LABELS}: adds version labels to * existing version histories. The property is multi-valued and each value is a * PATH, which looks like this: * <version-history-path>/jcr:versionLabels/<version-label>/<version-name>. * The version-history-path is a relative path to the version * history node starting at the /jcr:system/jcr:versionStorage node. * An attempt to add a version label that already exists will result in a * {@link CommitFailedException}.
  • *
  • {@link VersionConstants#REP_REMOVE_VERSION_LABELS}: removes version labels from * existing version histories. The property is multi-valued and each value is a * PATH, which looks like this: * <version-history-path>/jcr:versionLabels/<version-label>/<version-name>. * The version-history-path is a relative path to the version * history node starting at the /jcr:system/jcr:versionStorage node. The * <version-name> part is ignored when labels are removed and * can be anything, though it must be a valid JCR/Oak name. * An attempt to remove a version label, which does not exist, will result in a * {@link CommitFailedException}.
  • *
*/ class VersionStorageEditor extends DefaultEditor { private final NodeBuilder versionStorageNode; private final NodeBuilder workspaceRoot; private ReadWriteVersionManager vMgr; private final List pathRemainder; private final SortedMap operations = Maps.newTreeMap(); VersionStorageEditor(@Nonnull NodeBuilder versionStorageNode, @Nonnull NodeBuilder workspaceRoot) { this(versionStorageNode, workspaceRoot, Arrays.asList(JCR_SYSTEM, JCR_VERSIONSTORAGE)); } private VersionStorageEditor(@Nonnull NodeBuilder versionStorageNode, @Nonnull NodeBuilder workspaceRoot, @Nonnull List pathRemainder) { this.versionStorageNode = versionStorageNode; this.workspaceRoot = workspaceRoot; this.pathRemainder = checkNotNull(pathRemainder); } @Override public Editor childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException { if (pathRemainder.isEmpty()) { return null; } if (pathRemainder.get(0).equals(name)) { return new VersionStorageEditor(versionStorageNode, workspaceRoot, pathRemainder.subList(1, pathRemainder.size())); } else { return null; } } @Override public void propertyAdded(PropertyState after) throws CommitFailedException { if (after.getName().equals(REP_REMOVE_VERSION_LABELS)) { operations.put(1, new RemoveVersionLabels(after.getValue(Type.PATHS))); versionStorageNode.removeProperty(after.getName()); } else if (after.getName().equals(REP_ADD_VERSION_LABELS)) { operations.put(2, new AddVersionLabels(after.getValue(Type.PATHS))); versionStorageNode.removeProperty(after.getName()); } } @Override public void leave(NodeState before, NodeState after) throws CommitFailedException { for (Operation op : operations.values()) { op.perform(); } } //-------------------------< internal >------------------------------------- private ReadWriteVersionManager getVersionManager() { if (vMgr == null) { vMgr = new ReadWriteVersionManager(versionStorageNode, workspaceRoot); } return vMgr; } interface Operation { void perform() throws CommitFailedException; } private class AddVersionLabels implements Operation { private Iterable labelPaths; public AddVersionLabels(Iterable labelPaths) { this.labelPaths = labelPaths; } @Override public void perform() throws CommitFailedException { for (String s : labelPaths) { VersionLabel label = new VersionLabel(s); getVersionManager().addVersionLabel(label.versionHistoryPath, label.label, label.versionName); } } } private class RemoveVersionLabels implements Operation { private Iterable labelPaths; public RemoveVersionLabels(Iterable labelPaths) { this.labelPaths = labelPaths; } @Override public void perform() throws CommitFailedException { for (String s : labelPaths) { VersionLabel label = new VersionLabel(s); getVersionManager().removeVersionLabel(label.versionHistoryPath, label.label); } } } private static class VersionLabel { private final String versionHistoryPath; private final String label; private final String versionName; /** * @param path a label path as defined in the constructor of * {@link VersionStorageEditor}. * @throws IllegalArgumentException if the path is malformed */ VersionLabel(@Nonnull String path) throws IllegalArgumentException { checkArgument(!PathUtils.isAbsolute(checkNotNull(path)), "Version label path must be relative"); List elements = Lists.newArrayList(PathUtils.elements(path)); // length of the path must be 7: // intermediate versionstorage nodes : 3 // version history node : 1 // jcr:versionLabels : 1 // version label : 1 // version name : 1 if (elements.size() != 7) { throw new IllegalArgumentException( "Invalid version label path: " + path); } StringBuilder builder = new StringBuilder(); String slash = ""; for (String element : elements.subList(0, 4)) { builder.append(slash); builder.append(element); slash = "/"; } versionHistoryPath = builder.toString(); checkArgument(elements.get(4).equals(JCR_VERSIONLABELS), "Invalid version label path: " + path); label = elements.get(5); versionName = elements.get(6); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy