org.structr.common.ValidationHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.common.ValidationHelper.java

Source

/**
 * Copyright (C) 2010-2016 Structr GmbH
 *
 * This file is part of Structr <http://structr.org>.
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Structr.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.structr.common;

import java.util.Arrays;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.structr.common.error.ChronologicalOrderToken;
import org.structr.common.error.EmptyPropertyToken;
import org.structr.common.error.ErrorBuffer;
import org.structr.common.error.FrameworkException;
import org.structr.common.error.MatchToken;
import org.structr.common.error.RangeToken;
import org.structr.common.error.TooShortToken;
import org.structr.common.error.UniqueToken;
import org.structr.common.error.ValueToken;
import org.structr.core.GraphObject;
import org.structr.core.Result;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.graph.NodeInterface;
import org.structr.core.graph.RelationshipInterface;
import org.structr.core.property.GenericProperty;
import org.structr.core.property.PropertyKey;

/**
 * Defines helper methods for property validation.
 *
 *
 */
public class ValidationHelper {

    private static final PropertyKey UnknownType = new GenericProperty("unknown type");

    // ----- public static methods -----
    /**
     * Checks whether the value for the given property key of the given node
     * has at least the given length.
     *
     * @param node the node
     * @param key the property key whose value should be checked
     * @param minLength the min length
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkStringMinLength(final GraphObject node, final PropertyKey<String> key,
            final int minLength, final ErrorBuffer errorBuffer) {

        String value = node.getProperty(key);
        String type = node.getType();

        if (StringUtils.isNotBlank(value)) {

            if (value.length() >= minLength) {

                return false;

            }

            errorBuffer.add(new TooShortToken(type, key, minLength));

            return true;

        }

        errorBuffer.add(new EmptyPropertyToken(type, key));

        return true;
    }

    /**
     * Checks whether the value for the given property key of the given node
     * is a non-empty string.
     *
     * @param node the node
     * @param key the property key
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkStringNotBlank(final GraphObject node, final PropertyKey<String> key,
            final ErrorBuffer errorBuffer) {

        String type = node.getType();

        if (StringUtils.isNotBlank(node.getProperty(key))) {

            return false;

        }

        errorBuffer.add(new EmptyPropertyToken(type, key));

        return true;
    }

    /**
     * Checks whether the value for the given property key of the given node
     * is a non-empty string.
     *
     * @param node the node
     * @param key the property key
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkPropertyNotNull(final GraphObject node, final PropertyKey key,
            final ErrorBuffer errorBuffer) {

        String type = node.getType();

        if (key == null) {
            errorBuffer.add(new EmptyPropertyToken(type, UnknownType));
            return true;
        }

        Object value = node.getProperty(key);

        if (value != null) {

            if (value instanceof Iterable) {

                if (((Iterable) value).iterator().hasNext()) {

                    return false;

                }

            } else {

                return false;

            }

        }

        errorBuffer.add(new EmptyPropertyToken(type, key));

        return true;
    }

    /**
     * Checks whether the value for the given property key of the given node
     * is non null and of type Date.
     *
     * @param node the node
     * @param key the property key
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkDate(final GraphObject node, final PropertyKey<Date> key,
            final ErrorBuffer errorBuffer) {

        Date date = node.getProperty(key);
        String type = node.getType();
        boolean error = false;

        if ((date == null) || ((date != null) && (date.getTime() == 0))) {

            errorBuffer.add(new EmptyPropertyToken(type, key));
            error = true;

        }

        return error;
    }

    /**
     * Checks whether the Date values for the two given property keys are
     * in chronological order, i.e. the Date of key1 lies before the one of
     * key2.
     *
     * @param node the node
     * @param key1 the first Date key
     * @param key2 the second Date key
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkDatesChronological(final GraphObject node, final PropertyKey<Date> key1,
            final PropertyKey<Date> key2, final ErrorBuffer errorBuffer) {

        Date date1 = node.getProperty(key1);
        Date date2 = node.getProperty(key2);
        String type = node.getType();
        boolean error = false;

        error |= checkDate(node, key1, errorBuffer);
        error |= checkDate(node, key2, errorBuffer);

        if ((date1 != null) && (date2 != null) && !date1.before(date2)) {

            errorBuffer.add(new ChronologicalOrderToken(type, key1, key2));

            error = true;

        }

        return error;
    }

    /**
     * Checks whether the value for the given property key of the given node
     * is one of the values array.
     *
     * @param node the node
     * @param key the property key
     * @param values the values to check against
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkStringInArray(final GraphObject node, final PropertyKey<String> key,
            final String[] values, final ErrorBuffer errorBuffer) {

        String type = node.getType();

        if (StringUtils.isNotBlank(node.getProperty(key))) {

            if (Arrays.asList(values).contains(node.getProperty(key))) {

                return false;

            }

        }

        errorBuffer.add(new ValueToken(type, key, values));

        return true;
    }

    /**
     * Checks whether the value for the given property key of the given node
     * is a valid enum value of the given type.
     *
     * @param node the node
     * @param key the property key
     * @param enumType the enum type to check against
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkStringInEnum(final GraphObject node, final PropertyKey<? extends Enum> key,
            Class<? extends Enum> enumType, final ErrorBuffer errorBuffer) {

        return checkStringInEnum(node.getType(), node, key, enumType, errorBuffer);
    }

    /**
     * Checks whether the value of the given property key of the given node
     * if not null and matches the given regular expression.
     *
     * @param node
     * @param key
     * @param expression
     * @param errorBuffer
     * @return true if string matches expression
     */
    public static boolean checkStringMatchesRegex(final GraphObject node, final PropertyKey<String> key,
            final String expression, final ErrorBuffer errorBuffer) {

        String value = node.getProperty(key);
        boolean matches = value != null && value.matches(expression);

        if (!matches) {
            errorBuffer.add(new MatchToken(node.getType(), key, expression));
        }

        return matches;

    }

    /**
     * Checks whether the value for the given property key of the given node
     * is a valid enum value of the given type. In case of an error, the
     * type identifiery in typeString is used for the error message.
     *
     * @param typeString
     * @param node the node
     * @param key the property key
     * @param enumType the enum type to check against
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkStringInEnum(final String typeString, final GraphObject node,
            final PropertyKey<? extends Enum> key, Class<? extends Enum> enumType, final ErrorBuffer errorBuffer) {

        Enum value = node.getProperty(key);
        Enum[] values = enumType.getEnumConstants();

        for (Enum v : values) {

            if (v.equals(value)) {
                return false;
            }

        }

        errorBuffer.add(new ValueToken(typeString, key, values));

        return true;
    }

    /**
     * Checks whether the value for the given property key of the given node
     * is null OR one of the values given in the values array.
     *
     * @param node the node
     * @param key the property key
     * @param values the values array
     * @param errorBuffer the error buffer
     *
     * @return true if there is an error checking the given node
     */
    public static boolean checkNullOrStringInArray(final GraphObject node, final PropertyKey<String> key,
            String[] values, final ErrorBuffer errorBuffer) {

        String value = node.getProperty(key);
        String type = node.getType();

        if (value == null) {
            return false;
        }

        if (StringUtils.isNotBlank(node.getProperty(key))) {

            if (Arrays.asList(values).contains(node.getProperty(key))) {

                return false;

            }

        }

        errorBuffer.add(new ValueToken(type, key, values));

        return true;
    }

    public static boolean checkIntegerInRangeError(final GraphObject node, final PropertyKey<Integer> key,
            final String range, final ErrorBuffer errorBuffer) {

        // we expect expression to have the following format:
        // - "[" or "]" followed by a number (including negative values
        // - a comma (must exist)
        // - a number (including negative values followed by "[" or "]"

        final int length = range.length();
        final String leftBound = range.substring(0, 1);
        final String rightBound = range.substring(length - 1, length);
        final String[] parts = range.substring(1, length - 1).split(",+");
        final String type = node.getType();

        if (parts.length == 2) {

            final String leftPart = parts[0].trim();
            final String rightPart = parts[1].trim();
            final int left = Integer.parseInt(leftPart);
            final int right = Integer.parseInt(rightPart);
            final Integer value = node.getProperty(key);

            // do not check for non-null values, ignore (silently succeed)
            if (value != null) {

                // result
                boolean inRange = true;

                if ("[".equals(leftBound)) {
                    inRange &= (value >= left);
                } else {
                    inRange &= (value > left);
                }

                if ("]".equals(rightBound)) {
                    inRange &= (value <= right);
                } else {
                    inRange &= (value < right);
                }

                if (!inRange) {

                    errorBuffer.add(new RangeToken(type, key, range));
                }

                return !inRange;
            }

        }

        // no error
        return false;
    }

    public static boolean checkLongInRangeError(final GraphObject node, final PropertyKey<Long> key,
            final String range, final ErrorBuffer errorBuffer) {

        // we expect expression to have the following format:
        // - "[" or "]" followed by a number (including negative values
        // - a comma (must exist)
        // - a number (including negative values followed by "[" or "]"

        final int length = range.length();
        final String leftBound = range.substring(0, 1);
        final String rightBound = range.substring(length - 1, length);
        final String[] parts = range.substring(1, length - 1).split(",+");
        final String type = node.getType();

        if (parts.length == 2) {

            final String leftPart = parts[0].trim();
            final String rightPart = parts[1].trim();
            final long left = Long.parseLong(leftPart);
            final long right = Long.parseLong(rightPart);
            final Long value = node.getProperty(key);

            // do not check for non-null values, ignore (silently succeed)
            if (value != null) {

                // result
                boolean inRange = true;

                if ("[".equals(leftBound)) {
                    inRange &= (value >= left);
                } else {
                    inRange &= (value > left);
                }

                if ("]".equals(rightBound)) {
                    inRange &= (value <= right);
                } else {
                    inRange &= (value < right);
                }

                if (!inRange) {

                    errorBuffer.add(new RangeToken(type, key, range));
                }

                return !inRange;
            }

        }

        // no error
        return false;
    }

    public static boolean checkDoubleInRangeError(final GraphObject node, final PropertyKey<Double> key,
            final String range, final ErrorBuffer errorBuffer) {

        // we expect expression to have the following format:
        // - "[" or "]" followed by a number (including negative values
        // - a comma (must exist)
        // - a number (including negative values followed by "[" or "]"

        final int length = range.length();
        final String leftBound = range.substring(0, 1);
        final String rightBound = range.substring(length - 1, length);
        final String[] parts = range.substring(1, length - 1).split(",+");
        final String type = node.getType();

        if (parts.length == 2) {

            final String leftPart = parts[0].trim();
            final String rightPart = parts[1].trim();
            final double left = Double.parseDouble(leftPart);
            final double right = Double.parseDouble(rightPart);
            final Double value = node.getProperty(key);

            // do not check for non-null values, ignore (silently succeed)
            if (value != null) {

                // result
                boolean inRange = true;

                if ("[".equals(leftBound)) {
                    inRange &= (value >= left);
                } else {
                    inRange &= (value > left);
                }

                if ("]".equals(rightBound)) {
                    inRange &= (value <= right);
                } else {
                    inRange &= (value < right);
                }

                if (!inRange) {

                    errorBuffer.add(new RangeToken(type, key, range));
                }

                return !inRange;
            }

        }

        // no error
        return false;
    }

    public static synchronized boolean checkPropertyUniquenessError(final GraphObject object, final PropertyKey key,
            final ErrorBuffer errorBuffer) {

        if (key != null) {

            final Object value = object.getProperty(key);
            Result<GraphObject> result = null;
            boolean exists = false;
            String id = null;

            try {

                if (object instanceof NodeInterface) {

                    result = StructrApp.getInstance().nodeQuery(((NodeInterface) object).getClass()).and(key, value)
                            .getResult();

                } else {

                    result = StructrApp.getInstance().relationshipQuery(((RelationshipInterface) object).getClass())
                            .and(key, value).getResult();

                }

                exists = !result.isEmpty();

            } catch (FrameworkException fex) {

                fex.printStackTrace();

            }

            if (exists) {

                GraphObject foundNode = result.get(0);

                if (foundNode.getId() != object.getId()) {

                    id = ((AbstractNode) result.get(0)).getUuid();

                    errorBuffer.add(new UniqueToken(object.getType(), key, id));

                    return true;
                }
            }
        }

        // no error
        return false;
    }
}