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

org.apache.jackrabbit.oak.plugins.migration.FilteringNodeState Maven / Gradle / Ivy

There is a newer version: 1.66.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.migration;

import com.google.common.collect.ImmutableSet;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Set;
/**
 * NodeState implementation that decorates another node-state instance
 * in order to hide subtrees or partial subtrees from the consumer of
 * the API.
 * 
* The set of visible subtrees is defined by two parameters: include paths * and exclude paths, both of which are sets of absolute paths. *
* Any paths that are equal or are descendants of one of the * excluded paths are hidden by this implementation. *
* For all included paths, the direct ancestors, the node-state at * the path itself and all descendants are visible. Any siblings of the * defined path or its ancestors are implicitly hidden (unless made visible * by another include path). *
* The implementation delegates to the decorated node-state instance and * filters out hidden node-states in the following methods: *
    *
  • {@link #exists()}
  • *
  • {@link #hasChildNode(String)}
  • *
  • {@link #getChildNodeEntries()}
  • *
* Additionally, hidden node-state names are removed from the property * {@code :childOrder} in the following two methods: *
    *
  • {@link #getProperties()}
  • *
  • {@link #getProperty(String)}
  • *
*/ public class FilteringNodeState extends AbstractDecoratedNodeState { public static final Set ALL = ImmutableSet.of("/"); public static final Set NONE = ImmutableSet.of(); private final String path; private final Set includedPaths; private final Set excludedPaths; private final Set fragmentPaths; private final Set excludedFragments; /** * Factory method that conditionally decorates the given node-state * iff the node-state is (a) hidden itself or (b) has hidden descendants. * * @param path The path where the node-state should be assumed to be located. * @param delegate The node-state to decorate. * @param includePaths A Set of paths that should be visible. Defaults to ["/"] if {@code null}. * @param excludePaths A Set of paths that should be hidden. Empty if {@code null}. * @param fragmentPaths A Set of paths that should support the fragments (see below). Empty if {@code null}. * @param excludedFragments A Set of name fragments that should be hidden. Empty if {@code null}. * @return The decorated node-state if required, the original node-state if decoration is unnecessary. */ @NotNull public static NodeState wrap( @NotNull final String path, @NotNull final NodeState delegate, @Nullable final Set includePaths, @Nullable final Set excludePaths, @Nullable final Set fragmentPaths, @Nullable final Set excludedFragments ) { final Set includes = defaultIfEmpty(includePaths, ALL); final Set excludes = defaultIfEmpty(excludePaths, NONE); final Set safeFragmentPaths = defaultIfEmpty(fragmentPaths, NONE); final Set safeExcludedFragments = defaultIfEmpty(excludedFragments, NONE); if (hasHiddenDescendants(path, includes, excludes, safeFragmentPaths, safeExcludedFragments)) { return new FilteringNodeState(path, delegate, includes, excludes, fragmentPaths, safeExcludedFragments); } return delegate; } private FilteringNodeState( @NotNull final String path, @NotNull final NodeState delegate, @NotNull final Set includedPaths, @NotNull final Set excludedPaths, @NotNull final Set fragmentPaths, @NotNull final Set excludedFragments ) { super(delegate, false); this.path = path; this.includedPaths = includedPaths; this.excludedPaths = excludedPaths; this.fragmentPaths = fragmentPaths; this.excludedFragments = excludedFragments; } @NotNull @Override protected NodeState decorateChild(@NotNull final String name, @NotNull final NodeState child) { final String childPath = PathUtils.concat(path, name); return wrap(childPath, child, includedPaths, excludedPaths, fragmentPaths, excludedFragments); } @Override protected boolean hideChild(@NotNull final String name, @NotNull final NodeState delegateChild) { return isHidden(PathUtils.concat(path, name), includedPaths, excludedPaths, excludedFragments); } @Override protected PropertyState decorateProperty(@NotNull final PropertyState propertyState) { return fixChildOrderPropertyState(this, propertyState); } /** * Utility method to determine whether a given path should is hidden given the * include paths and exclude paths. * * @param path Path to be checked * @param includes Include paths * @param excludes Exclude paths * @param excludedFragments Exclude fragments * @return Whether the {@code path} is hidden or not. */ private static boolean isHidden( @NotNull final String path, @NotNull final Set includes, @NotNull final Set excludes, @NotNull final Set excludedFragments ) { return isExcluded(path, excludes, excludedFragments) || !isIncluded(path, includes); } /** * Utility method to determine whether the path itself or any of its descendants should * be hidden given the include paths and exclude paths. * * @param path Path to be checked * @param includePaths Include paths * @param excludePaths Exclude paths * @param excludedFragments Exclude fragments * @return Whether the {@code path} or any of its descendants are hidden or not. */ private static boolean hasHiddenDescendants( @NotNull final String path, @NotNull final Set includePaths, @NotNull final Set excludePaths, @NotNull final Set fragmentPaths, @NotNull final Set excludedFragments ) { return isHidden(path, includePaths, excludePaths, excludedFragments) || isAncestorOfAnyPath(path, fragmentPaths) || isDescendantOfAnyPath(path, fragmentPaths) || fragmentPaths.contains(path) || isAncestorOfAnyPath(path, excludePaths) || isAncestorOfAnyPath(path, includePaths); } /** * Utility method to check whether a given set of include paths cover the given * {@code path}. I.e. whether the path is visible or implicitly hidden due to the * lack of a matching include path. *
* Note: the ancestors of every include path are considered visible. * * @param path Path to be checked * @param includePaths Include paths * @return Whether the path is covered by the include paths or not. */ private static boolean isIncluded(@NotNull final String path, @NotNull final Set includePaths) { return isAncestorOfAnyPath(path, includePaths) || includePaths.contains(path) || isDescendantOfAnyPath(path, includePaths); } /** * Utility method to check whether a given set of exclude paths cover the given * {@code path}. I.e. whether the path is hidden due to the presence of a * matching exclude path. * * @param path Path to be checked * @param excludePaths Exclude paths * @param excludedFragments Exclude fragments * @return Whether the path is covered by the excldue paths or not. */ private static boolean isExcluded(@NotNull final String path, @NotNull final Set excludePaths, @NotNull final Set excludedFragments) { return excludePaths.contains(path) || isDescendantOfAnyPath(path, excludePaths) || containsAnyFragment(path, excludedFragments); } /** * Utility method to check whether any of the provided {@code paths} is a descendant * of the given ancestor path. * * @param ancestor Ancestor path * @param paths Paths that may be descendants of {@code ancestor}. * @return true if {@code paths} contains a descendant of {@code ancestor}, false otherwise. */ private static boolean isAncestorOfAnyPath(@NotNull final String ancestor, @NotNull final Set paths) { for (final String p : paths) { if (PathUtils.isAncestor(ancestor, p)) { return true; } } return false; } /** * Utility method to check whether any of the provided {@code paths} is an ancestor * of the given descendant path. * * @param descendant Descendant path * @param paths Paths that may be ancestors of {@code descendant}. * @return true if {@code paths} contains an ancestor of {@code descendant}, false otherwise. */ private static boolean isDescendantOfAnyPath(@NotNull final String descendant, @NotNull final Set paths) { for (final String p : paths) { if (PathUtils.isAncestor(p, descendant)) { return true; } } return false; } /** * Utility method to check whether the passed path contains any of the provided {@code fragments}. * * @param path Path * @param fragments Fragments, which the path may contain * @return true if {@code path} contains any of the {@code fragments}, false otherwise. */ private static boolean containsAnyFragment(@NotNull final String path, @NotNull final Set fragments) { for (final String f : fragments) { if (path.contains(f)) { return true; } } return false; } /** * Utility method to return the given {@code Set} if it is not empty and a default Set otherwise. * * @param value Value to check for emptiness * @param defaultValue Default value * @return return the given {@code Set} if it is not empty and a default Set otherwise */ @NotNull private static Set defaultIfEmpty(@Nullable Set value, @NotNull Set defaultValue) { return !isEmpty(value) ? value : defaultValue; } /** * Utility method to check whether a Set is empty, i.e. null or of size 0. * * @param set The Set to check. * @return true if empty, false otherwise */ private static boolean isEmpty(@Nullable final Set set) { return set == null || set.isEmpty(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy