Package org.apache.jackrabbit.oak.plugins.commit

Source Code of org.apache.jackrabbit.oak.plugins.commit.ConflictValidator

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

import com.google.common.base.Joiner;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.spi.commit.DefaultValidator;
import org.apache.jackrabbit.oak.spi.commit.Validator;
import org.apache.jackrabbit.oak.spi.state.ConflictType;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.collect.Iterables.transform;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.MIX_REP_MERGE_CONFLICT;

/**
* {@link Validator} which checks the presence of conflict markers
* in the tree in fails the commit if any are found.
*
* @see AnnotatingConflictHandler
*/
public class ConflictValidator extends DefaultValidator {
    private static Logger log = LoggerFactory.getLogger(ConflictValidator.class);

    private final Tree parentAfter;

    public ConflictValidator(Tree parentAfter) {
        this.parentAfter = parentAfter;
    }

    @Override
    public void propertyAdded(PropertyState after) throws CommitFailedException {
        failOnMergeConflict(after);
    }

    @Override
    public void propertyChanged(PropertyState before, PropertyState after)
            throws CommitFailedException {
        failOnMergeConflict(after);
    }

    @Override
    public Validator childNodeAdded(String name, NodeState after) {
        return new ConflictValidator(parentAfter.getChild(name));
    }

    @Override
    public Validator childNodeChanged(String name, NodeState before, NodeState after) {
        return new ConflictValidator(parentAfter.getChild(name));
    }

    @Override
    public Validator childNodeDeleted(String name, NodeState before) {
        return null;
    }

    private void failOnMergeConflict(PropertyState property) throws CommitFailedException {
        if (JcrConstants.JCR_MIXINTYPES.equals(property.getName())) {
            assert property.isArray();
            for (String v : property.getValue(STRINGS)) {
                if (MIX_REP_MERGE_CONFLICT.equals(v)) {

                    CommitFailedException ex = new CommitFailedException(
                            CommitFailedException.STATE, 1, "Unresolved conflicts in " + parentAfter.getPath());

                    //Conflict details are not made part of ExceptionMessage instead they are
                    //logged. This to avoid exposing property details to the caller as it might not have
                    //permission to access it
                    if (log.isDebugEnabled()) {
                        log.debug(getConflictMessage(), ex);
                    }
                    throw ex;
                }
            }
        }
    }

    private String getConflictMessage() {
        StringBuilder sb = new StringBuilder("Commit failed due to unresolved conflicts in ");
        sb.append(parentAfter.getPath());
        sb.append(" = {");
        for (Tree conflict : parentAfter.getChild(NodeTypeConstants.REP_OURS).getChildren()) {
            ConflictType ct = ConflictType.fromName(conflict.getName());

            sb.append(ct.getName()).append(" = {");
            if (ct.effectsNode()) {
                sb.append(getChildNodeNamesAsString(conflict));
            } else {
                for (PropertyState ps : conflict.getProperties()) {
                    PropertyState ours = null, theirs = null;
                    switch (ct) {
                        case DELETE_CHANGED_PROPERTY:
                            ours = null;
                            theirs = ps;
                            break;
                        case ADD_EXISTING_PROPERTY:
                        case CHANGE_CHANGED_PROPERTY:
                            ours = ps;
                            theirs = parentAfter.getProperty(ps.getName());
                            break;
                        case CHANGE_DELETED_PROPERTY:
                            ours = ps;
                            theirs = null;
                            break;
                    }

                    sb.append(ps.getName())
                            .append(" = {")
                            .append(toString(ours))
                            .append(',')
                            .append(toString(theirs))
                            .append('}');

                    sb.append(',');
                }
                sb.deleteCharAt(sb.length() - 1);
            }

            sb.append("},");
        }

        sb.deleteCharAt(sb.length() - 1);
        sb.append('}');
        return sb.toString();
    }

    private static String getChildNodeNamesAsString(Tree t) {
        return Joiner.on(',').join(transform(t.getChildren(), Tree.GET_NAME));
    }

    private static String toString(PropertyState ps) {
        if (ps == null) {
            return "<N/A>";
        }

        final Type type = ps.getType();
        if (type.isArray()) {
            return "<ARRAY>";
        }
        if (Type.BINARY == type) {
            return "<BINARY>";
        }

        String value = ps.getValue(Type.STRING);

        //Trim the value so as to not blowup diff message
        if (Type.STRING == type && value.length() > 10) {
            value = value.substring(0, 10) + "...";
        }

        return value;
    }

}
TOP

Related Classes of org.apache.jackrabbit.oak.plugins.commit.ConflictValidator

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.