Package org.apache.jackrabbit.oak.jcr.state

Source Code of org.apache.jackrabbit.oak.jcr.state.TransientNodeState

/*
* 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.jcr.state;

import org.apache.jackrabbit.mk.model.ChildNodeEntry;
import org.apache.jackrabbit.mk.model.NodeState;
import org.apache.jackrabbit.mk.model.PropertyState;
import org.apache.jackrabbit.mk.model.Scalar;
import org.apache.jackrabbit.mk.model.ScalarImpl;
import org.apache.jackrabbit.oak.api.Connection;
import org.apache.jackrabbit.oak.jcr.SessionContext;
import org.apache.jackrabbit.oak.jcr.SessionImpl;
import org.apache.jackrabbit.oak.jcr.state.ChangeTree.NodeDelta;
import org.apache.jackrabbit.oak.jcr.util.Function1;
import org.apache.jackrabbit.oak.jcr.util.Iterators;
import org.apache.jackrabbit.oak.jcr.util.PagedIterator;
import org.apache.jackrabbit.oak.jcr.util.Path;
import org.apache.jackrabbit.oak.jcr.util.Predicate;
import org.apache.jackrabbit.oak.kernel.KernelPropertyState;

import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.PathNotFoundException;
import java.util.Iterator;
import java.util.List;

import static org.apache.jackrabbit.oak.jcr.util.Iterators.toIterable;


/**
* A {@code TransientNodeState} instance uses a {@code TransientSpace} to record changes
* to a {@code PersistedNodeState}.
*/
public class TransientNodeState {
    private static final int BATCH_SIZE = 256;

    private final SessionContext<SessionImpl> sessionContext;

    private NodeDelta nodeDelta;

    TransientNodeState(SessionContext<SessionImpl> sessionContext, NodeDelta nodeDelta) {
        this.sessionContext = sessionContext;
        this.nodeDelta = nodeDelta;
    }

    /**
     * @return {@code true} iff this is the root node
     */
    public boolean isRoot() {
        return getPath().isRoot();
    }

    /**
     * @return the path of this node
     */
    public Path getPath() {
        return getNodeDelta().getPath();
    }

    /**
     * @return the name of this node
     */
    public String getName() {
        return getPath().getName();
    }

    /**
     * @return {@code true} iff this node has been transiently added.
     */
    public boolean isNew() {
        NodeDelta delta = getNodeDelta();
        return delta.isTransient() && !delta.isRemoved();
    }

    /**
     * @return {@code true} iff this node has been transiently modified.
     */
    public boolean isModified() {
        return getNodeDelta().isTransient();
    }

    /**
     * Transiently add a node with the given {@code name}.
     *
     * @param name The name of the new node.
     * @return the added node
     * @throws javax.jcr.ItemExistsException if a node with that name exists already.
     */
    public TransientNodeState addNode(String name) throws ItemExistsException {
        NodeDelta child = getNodeDelta().addNode(name);
        return getNodeState(child);
    }

    /**
     * Transiently remove this node.
     * @throws javax.jcr.ItemNotFoundException if this node has been removed already
     */
    public void remove() throws ItemNotFoundException {
        getNodeStateProvider().release(getPath());
        getNodeDelta().getParent().removeNode(getName());
    }

    /**
     * Transiently move this node.
     *
     * @param name  name of this node at its {@code destination}
     * @param destination The destination of the move.
     * @throws javax.jcr.ItemExistsException  {@code name} exists at {@code destination}
     * @throws javax.jcr.PathNotFoundException  {@code destination} does not exist
     * @throws javax.jcr.ItemNotFoundException  {@code name} does not exist
     */
    public void move(String name, Path destination) throws ItemExistsException, PathNotFoundException,
            ItemNotFoundException {

        getNodeDelta().moveNode(name, destination);
        getNodeStateProvider().release(getPath().concat(name));
    }

    /**
     * Transiently set a property.
     * @param name  Name of the property.
     * @param value  Value of the property.
     *               to remove the property.
     */
    public void setProperty(String name, Scalar value) {
        getNodeDelta().setProperty(new KernelPropertyState(name, value));
    }

    /**
     * Transiently set a property.
     * @param name  Name of the property.
     * @param values  Values of the property.
     */
    public void setProperty(String name, List<Scalar> values) {
        getNodeDelta().setProperty(new KernelPropertyState(name, values));
    }

    /**
     * Transiently remove a property.
     * @param name  name of the property to remove.
     */
    public void removeProperty(String name) {
        getNodeDelta().removeProperty(name);
    }

    /**
     * @return {@code true} iff this instance has child nodes.
     */
    public boolean hasNodes() {
        return getNodes().hasNext();
    }

    /**
     * @return Iterator of all child node states of this instance.
     */
    public Iterator<TransientNodeState> getNodes() {
        Iterator<? extends ChildNodeEntry> persistedEntries = Iterators.flatten(
                new PagedIterator<ChildNodeEntry>(BATCH_SIZE) {
                    @Override
                    protected Iterator<? extends ChildNodeEntry> getPage(long pos, int size) {
                        return getPersistentNodeState().getChildNodeEntries(pos, size).iterator();
                    }
                });

        final NodeDelta delta = getNodeDelta();

        Iterator<ChildNodeEntry> unmodifiedEntries = Iterators.filter(persistedEntries,
            new Predicate<ChildNodeEntry>() {
                @Override
                public boolean evaluate(ChildNodeEntry entry) {
                    return !delta.isNodeModified(entry.getName());
                }
            });

        Iterator<TransientNodeState> unmodifiedStates = Iterators.map(unmodifiedEntries,
            new Function1<ChildNodeEntry, TransientNodeState>() {
                @Override
                public TransientNodeState apply(ChildNodeEntry entry) {
                    return getNodeState(delta.getNode(entry.getName()));
                }
            });

        Iterator<TransientNodeState> modifiedStates = Iterators.map(toIterable(delta.getNodes()).iterator(),
            new Function1<NodeDelta, TransientNodeState>() {
                @Override
                public TransientNodeState apply(NodeDelta delta) {
                    return getNodeState(delta);
                }
            });

        return Iterators.chain(unmodifiedStates, modifiedStates);
    }

    /**
     * @return {@code true} iff this instance has properties
     */
    public boolean hasProperties() {
        return getProperties().hasNext();
    }

    /**
     * @return Iterator of all property states of this instance.
     */
    public Iterator<PropertyState> getProperties() {
        Iterable<? extends PropertyState> propertyStates = getPersistentNodeState().getProperties();
        final NodeDelta delta = getNodeDelta();

        Iterator<PropertyState> propertyEntries =
            Iterators.filter(propertyStates.iterator(),
                new Predicate<PropertyState>() {
                    @Override
                    public boolean evaluate(PropertyState state) {
                        return !state.getName().startsWith(":") && !delta.hasProperty(state.getName());
                    }
                });

        Iterator<PropertyState> modifiedProperties = delta.getPropertyStates();
        return Iterators.chain(propertyEntries, Iterators.toIterable(modifiedProperties).iterator());
    }

    /**
     * @param name  name of the property
     * @return  state of the property named {@code name}.
     * @throws javax.jcr.ItemNotFoundException  if no such property exists.
     */
    public PropertyState getPropertyState(String name) throws ItemNotFoundException {
        PropertyState state = getPropertyStateOrNull(name);
        if (state == null) {
            throw new ItemNotFoundException(name);
        }

        return state;
    }

    /**
     * @param name name of the property
     * @return {@code true} iff this instance has a property name {@code name}.
     */
    public boolean hasProperty(String name) {
        return getPropertyStateOrNull(name) != null;
    }

    /**
     * @param name name of the property
     * @return {@code true} iff the property named {@code name} has been transiently added.
     */
    public boolean isPropertyNew(String name) {
        PropertyState state = getNodeDelta().getPropertyState(name);
        if (state == null) {
            return false;
        }

        if (state.isArray()) {
            return getPersistedPropertyState(name) == null;
        }
        else {
            Scalar value = state.getScalar();
            return !value.equals(ScalarImpl.nullScalar()) && getPersistedPropertyState(name) == null;
        }
    }

    /**
     * @param name name of the property
     * @return {@code true} iff the property named {@code name} has been transiently modified.
     */
    public boolean isPropertyModified(String name) {
        return getNodeDelta().hasProperty(name);
    }

    @Override
    public String toString() {
        return "TransientNodeState(" + getPath().toString() + ')';
    }

    //------------------------------------------< private >---

    private NodeStateProvider getNodeStateProvider() {
        return sessionContext.getNodeStateProvider();
    }
   
    private TransientNodeState getNodeState(NodeDelta nodeDelta) {
        return getNodeStateProvider().getNodeState(nodeDelta);
    }

    private PropertyState getPropertyStateOrNull(String name) {
        PropertyState state = getNodeDelta().getPropertyState(name);
        if (state == null) {
            return getPersistedPropertyState(name);
        }
        else {
            if (state.isArray()) {
                return state;
            }
            else {
                Scalar value = state.getScalar();
                return value.equals(ScalarImpl.nullScalar())
                    ? null
                    : state;
            }
        }
    }

    private PropertyState getPersistedPropertyState(String name) {
        return getPersistentNodeState().getProperty(name);
    }

    private synchronized NodeState getPersistentNodeState() {
        Path path = getNodeDelta().getPersistentPath();

        return path == null
            ? EmptyNodeState.INSTANCE
            : getPersistentNodeState(sessionContext.getConnection(), path);
    }

    private NodeDelta getNodeDelta() {
        return nodeDelta = getNodeStateProvider().getNodeDelta(nodeDelta.getPath());
    }

    private static NodeState getPersistentNodeState(Connection connection, Path path) {
        NodeState state = connection.getCurrentRoot();
        for (String name : path.getNames()) {
            state = state.getChildNode(name);
            if (state == null) {
                return null;
            }
        }

        return state;
    }

}
TOP

Related Classes of org.apache.jackrabbit.oak.jcr.state.TransientNodeState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.