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

org.apache.jackrabbit.oak.util.NodeUtil Maven / Gradle / Ivy

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

import java.util.Arrays;
import java.util.Calendar;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.AccessDeniedException;
import javax.jcr.RepositoryException;
import javax.jcr.Value;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.namepath.NameMapper;
import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.util.ISO8601;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.oak.api.Type.DATE;
import static org.apache.jackrabbit.oak.api.Type.LONG;
import static org.apache.jackrabbit.oak.api.Type.NAME;
import static org.apache.jackrabbit.oak.api.Type.NAMES;
import static org.apache.jackrabbit.oak.api.Type.STRING;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;

/**
 * Utility class for accessing and writing typed content of a tree.
 */
public class NodeUtil {

    private static final Logger log = LoggerFactory.getLogger(NodeUtil.class);

    private final NameMapper mapper;

    private final Tree tree;

    public NodeUtil(Tree tree, NameMapper mapper) {
        this.mapper = checkNotNull(mapper);
        this.tree = checkNotNull(tree);
    }

    public NodeUtil(Tree tree) {
        this(tree, NamePathMapper.DEFAULT);
    }

    @Nonnull
    public Tree getTree() {
        return tree;
    }

    @Nonnull
    public String getName() {
        return mapper.getJcrName(tree.getName());
    }

    @Nonnull
    public NodeUtil getParent() {
        return new NodeUtil(tree.getParent(), mapper);
    }

    public boolean hasChild(String name) {
        return tree.hasChild(name);
    }

    @CheckForNull
    public NodeUtil getChild(String name) {
        Tree child = tree.getChild(name);
        return child.exists() ? new NodeUtil(child, mapper) : null;
    }

    /**
     * Adds a new child tree with the given name and primary type name.
     * This method is a shortcut for calling {@link Tree#addChild(String)} and
     * {@link Tree#setProperty(String, Object, org.apache.jackrabbit.oak.api.Type)}
     * where the property name is {@link JcrConstants#JCR_PRIMARYTYPE}.
     * Note, that this method in addition verifies if the created tree exists
     * and is accessible in order to avoid {@link IllegalStateException} upon
     * subsequent modification of the new child.
     *
     * @param name            The name of the child item.
     * @param primaryTypeName The name of the primary node type.
     * @return The new child node with the specified name and primary type.
     * @throws AccessDeniedException If the child does not exist after creation.
     */
    @Nonnull
    public NodeUtil addChild(String name, String primaryTypeName) throws AccessDeniedException {
        Tree child = tree.addChild(name);
        if (!child.exists()) {
            throw new AccessDeniedException();
        }
        NodeUtil childUtil = new NodeUtil(child, mapper);
        childUtil.setName(JcrConstants.JCR_PRIMARYTYPE, primaryTypeName);
        return childUtil;
    }

    /**
     * Combination of {@link #getChild(String)} and {@link #addChild(String, String)}
     * in case no tree exists with the specified name.
     *
     * @param name            The name of the child item.
     * @param primaryTypeName The name of the primary node type.
     * @return The new child node with the specified name and primary type.
     * @throws AccessDeniedException If the child does not exist after creation.
     */
    @Nonnull
    public NodeUtil getOrAddChild(String name, String primaryTypeName) throws AccessDeniedException {
        NodeUtil child = getChild(name);
        return (child != null) ? child : addChild(name, primaryTypeName);
    }

    /**
     * TODO: clean up. workaround for OAK-426
     * 

* Create the tree at the specified relative path including all missing * intermediate trees using the specified {@code primaryTypeName}. This * method treats ".." parent element and "." as current element and * resolves them accordingly; in case of a relative path containing parent * elements this may lead to tree creating outside the tree structure * defined by this {@code NodeUtil}. * * @param relativePath A relative OAK path that may contain parent and * current elements. * @param primaryTypeName A oak name of a primary node type that is used * to create the missing trees. * @return The node util of the tree at the specified {@code relativePath}. * @throws AccessDeniedException If the any intermediate tree does not exist * and cannot be created. */ @Nonnull public NodeUtil getOrAddTree(String relativePath, String primaryTypeName) throws AccessDeniedException { if (PathUtils.denotesCurrent(relativePath)) { return this; } else if (PathUtils.denotesParent(relativePath)) { return getParent(); } else if (relativePath.indexOf('/') == -1) { return getOrAddChild(relativePath, primaryTypeName); } else { Tree t = TreeUtil.getTree(tree, relativePath); if (t == null || !t.exists()) { NodeUtil target = this; for (String segment : Text.explode(relativePath, '/')) { if (PathUtils.denotesParent(segment)) { target = target.getParent(); } else if (target.hasChild(segment)) { target = target.getChild(segment); } else if (!PathUtils.denotesCurrent(segment)) { target = target.addChild(segment, primaryTypeName); } } if (target == null) { throw new AccessDeniedException(); } return target; } else { return new NodeUtil(t); } } } public void removeProperty(String name) { tree.removeProperty(name); } public void setBoolean(String name, boolean value) { tree.setProperty(name, value); } @CheckForNull public String getString(String name, @Nullable String defaultValue) { String str = TreeUtil.getString(tree, name); return (str != null) ? str : defaultValue; } public void setString(String name, String value) { tree.setProperty(name, value); } public void setStrings(String name, String... values) { tree.setProperty(name, Arrays.asList(values), STRINGS); } @CheckForNull public String getName(String name, @Nullable String defaultValue) { PropertyState property = tree.getProperty(name); if (property != null && !property.isArray()) { return mapper.getJcrName(property.getValue(STRING)); } else { return defaultValue; } } public void setName(String propertyName, String value) { String oakName = getOakName(value); tree.setProperty(propertyName, oakName, NAME); } public void setNames(String propertyName, String... values) { tree.setProperty(propertyName, Lists.transform(Arrays.asList(values), new Function() { @Override public String apply(String jcrName) { return getOakName(jcrName); } }), NAMES); } public void setDate(String name, long time) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(time); tree.setProperty(name, ISO8601.format(calendar), DATE); } public long getLong(String name, long defaultValue) { PropertyState property = tree.getProperty(name); if (property != null && !property.isArray()) { return property.getValue(LONG); } else { return defaultValue; } } public void setLong(@Nonnull String name, long value) { tree.setProperty(name, value); } public void setValues(String name, Value[] values) { try { tree.setProperty(PropertyStates.createProperty(name, Arrays.asList(values))); } catch (RepositoryException e) { log.warn("Unable to convert values", e); } } @Nonnull private String getOakName(String jcrName) { String oakName = (jcrName == null) ? null : mapper.getOakNameOrNull(jcrName); if (oakName == null) { throw new IllegalArgumentException(new RepositoryException("Invalid name:" + jcrName)); } return oakName; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy