Package org.lilyproject.repository.impl

Source Code of org.lilyproject.repository.impl.MutationConditionVerifier

/*
* Copyright 2012 NGDATA nv
*
* Licensed 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.lilyproject.repository.impl;

import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.lilyproject.repository.api.CompareOp;
import org.lilyproject.repository.api.MutationCondition;
import org.lilyproject.repository.api.QName;
import org.lilyproject.repository.api.Record;
import org.lilyproject.repository.api.Repository;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.ResponseStatus;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.api.ValueType;
import org.lilyproject.util.repo.SystemFields;

public class MutationConditionVerifier {
    private MutationConditionVerifier() {
    }

    /**
     * Checks a set of conditions, if not satisfied it returns false and sets the response
     * status in the supplied record object to conflict, as well as reduces the fields to those
     * that were submitted.
     *
     * @param record the complete record state as currently stored in the repository
     * @param conditions the conditions that should be satisfied
     *
     * @return null if conditions are satisfied, a Record object if not.
     */
    public static Record checkConditions(Record record, List<MutationCondition> conditions, Repository repository,
            Record newRecord) throws RepositoryException, InterruptedException {

        if (conditions == null) {
            return null;
        }

        boolean allSatisfied = true;

        // TODO should we check with the typemanager that the supplied value types are
        // of the correct type? this is not necessary for us, but might be helpful to the
        // user. OTOH, since users most of the time will go through a remote itf, such checks
        // will likely already have happened as part of serialization/deserialization code.

        SystemFields systemFields = SystemFields.getInstance(repository.getTypeManager(), repository.getIdGenerator());

        for (MutationCondition condition : conditions) {
            Object value = systemFields.softEval(record, condition.getField(), repository.getTypeManager());

            // Compare with null value is special case, handle this first
            if (condition.getValue() == null) {
                if (condition.getOp() == CompareOp.EQUAL) {
                    if (value == null) {
                        continue;
                    } else {
                        allSatisfied = false;
                        break;
                    }
                } else if (condition.getOp() == CompareOp.NOT_EQUAL) {
                    if (value != null) {
                        continue;
                    } else {
                        allSatisfied = false;
                        break;
                    }
                } else {
                    throw new RepositoryException("When comparing to null, only (not-)equal operator is allowed. " +
                            "Operator: " + condition.getOp() + ", field: " + condition.getField());
                }
            }

            if (value == null && condition.getAllowMissing()) {
                continue;
            }

            if (value == null) {
                allSatisfied = false;
                break;
            }

            if (!checkValue(condition, value, repository.getTypeManager())) {
                allSatisfied = false;
                break;
            }
        }

        if (!allSatisfied) {
            Record responseRecord = record.cloneRecord();
            if (newRecord != null) {
                // reduce the fields to return to those that were submitted
                reduceFields(responseRecord, newRecord.getFields().keySet());
            } else {
                // reduce the fields to those on which conditions were put
                reduceFields(responseRecord, extractFields(conditions));
            }
            responseRecord.setResponseStatus(ResponseStatus.CONFLICT);
            return responseRecord;
        }

        return null;
    }

    private static Set<QName> extractFields(List<MutationCondition> conditions) {
        Set<QName> fields = new HashSet<QName>();
        for (MutationCondition condition : conditions) {
            fields.add(condition.getField());
        }
        return fields;
    }

    private static boolean checkValue(MutationCondition cond, Object currentValue, TypeManager typeManager)
            throws RepositoryException, InterruptedException {

        if (cond.getOp() == CompareOp.EQUAL) {
            return currentValue.equals(cond.getValue());
        } else if (cond.getOp() == CompareOp.NOT_EQUAL) {
            return !currentValue.equals(cond.getValue());
        }

        ValueType valueType = typeManager.getFieldTypeByName(cond.getField()).getValueType();
        Comparator comparator = valueType.getComparator();

        if (comparator == null) {
            throw new RepositoryException("Other than (not-)equals operator in mutation condition used for value type "
                    + "that does not support comparison: " + valueType.getName());
        }

        int result = comparator.compare(currentValue, cond.getValue());

        if (result == 0) {
            switch (cond.getOp()) {
                case EQUAL:
                case GREATER_OR_EQUAL:
                case LESS_OR_EQUAL:
                    return true;
                default:
                    return false;
            }
        } else if (result < 0) {
            switch (cond.getOp()) {
                case LESS:
                case LESS_OR_EQUAL:
                case NOT_EQUAL:
                    return true;
                default:
                    return false;
            }
        } else { // result > 0
            switch (cond.getOp()) {
                case GREATER:
                case GREATER_OR_EQUAL:
                case NOT_EQUAL:
                    return true;
                default:
                    return false;
            }
        }
    }

    private static void reduceFields(Record record, Set<QName> fieldsToInclude) {
        Iterator<QName> it = record.getFields().keySet().iterator();

        while (it.hasNext()) {
            QName name = it.next();
            if (!fieldsToInclude.contains(name)) {
                it.remove();
            }
        }
    }
}
TOP

Related Classes of org.lilyproject.repository.impl.MutationConditionVerifier

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.