org.eclipse.riena.ui.ridgets.validation.AbstractValidDate.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.riena.ui.ridgets.validation.AbstractValidDate.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2013 compeople AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    compeople AG - initial API and implementation
 *******************************************************************************/
package org.eclipse.riena.ui.ridgets.validation;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;

import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.osgi.util.NLS;

import org.eclipse.riena.core.util.PropertiesUtils;
import org.eclipse.riena.ui.ridgets.IDateTextRidget;
import org.eclipse.riena.ui.ridgets.nls.Messages;

/**
 * Validator checking that a String matches a given pattern for a Date.
 */
public abstract class AbstractValidDate implements IValidator, IExecutableExtension {

    private static final String DAY_COMPONENT_LETTER = "d"; //$NON-NLS-1$
    private static final String MONTH_COMPONENT_LETTER = "M"; //$NON-NLS-1$
    private static final String YEAR_COMPONENT_LETTER = "y"; //$NON-NLS-1$
    private static final String A_LEAP_YEAR = "2004"; //$NON-NLS-1$

    /**
     * the separator key used in the format for this date validation rule
     */
    private static final char SEPERATOR_KEY = '.'; // default is the dot-separator

    // placeholderValid to use in completion, if no input occurs between two
    // separators
    private static final String PLACEHOLDER_VALID = "1"; //$NON-NLS-1$
    // placeholderInvalid to use in completion to mark invalid input. May be
    // used, if input occurs for
    // some part of the format pattern, which should be marked as invalid.
    // Example: yyyy is the part of the format pattern to be validated and the
    // input is 0xx and should be
    // marked invalid, so 0xx is replaced by ?.
    private static final String PLACEHOLDER_INVALID = "?"; //$NON-NLS-1$

    private String pattern;

    private boolean checkValidIntermediate;

    /**
     * Creates a StringToDateValidator.
     */
    protected AbstractValidDate(final boolean checkValidIntermediate) {
        this("", checkValidIntermediate); //$NON-NLS-1$
    }

    /**
     * Creates a StringToDateValidator.
     * 
     * @param pattern
     *            The pattern to match e.g. MM/dd/yyyy.
     */
    public AbstractValidDate(final String pattern, final boolean checkValidIntermediate) {
        this.pattern = pattern;
        this.checkValidIntermediate = checkValidIntermediate;
    }

    /**
     * @see org.eclipse.core.databinding.validation.IValidator#validate(java.lang.Object)
     */
    public IStatus validate(final Object value) {
        if (value != null) {
            if (!(value instanceof String)) {
                throw new ValidationFailure("ValidCharacters can only validate objects of type String."); //$NON-NLS-1$
            }
            final String string = (String) value;

            // an empty String should not create an ErrorMarker
            if (Utils.isEmptyDate(string)) {
                return ValidationRuleStatus.ok();
            }

            if (string.length() > 0 && !isDateValid(string, pattern)) {
                final String message = NLS.bind(Messages.AbstractValidDate_error_invalidDate, pattern);
                return ValidationRuleStatus.error(false, message);
            }
        }
        return ValidationRuleStatus.ok();
    }

    private boolean isDateValid(String value, String datePattern) {
        // fix for problem report #651
        // workaround for org.apache.commons.validator.GenericValidator bug #221
        // https://issues.apache.org/jira/browse/VALIDATOR-221
        if (datePattern.contains(DAY_COMPONENT_LETTER) && datePattern.contains(MONTH_COMPONENT_LETTER)
                && !datePattern.contains(YEAR_COMPONENT_LETTER)) {
            datePattern += SEPERATOR_KEY + YEAR_COMPONENT_LETTER + YEAR_COMPONENT_LETTER + YEAR_COMPONENT_LETTER
                    + YEAR_COMPONENT_LETTER;
            value += SEPERATOR_KEY + A_LEAP_YEAR;
        }

        if (checkValidIntermediate) {
            return isDate(complete(value, datePattern), datePattern, false);
        }
        return isDate(value, datePattern, true);
        // if (checkValidIntermediate) {
        // return GenericValidator.isDate(complete(value, datePattern),
        // datePattern, false);
        // }
        // return GenericValidator.isDate(value, datePattern, true);
    }

    private boolean isDate(final String value, final String pattern, final boolean strict) {
        if (value == null || pattern == null || pattern.length() <= 0) {

            return false;
        }
        if (strict && value.length() != pattern.length()) {
            return false;
        }
        final SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        formatter.setLenient(false);

        final ParsePosition pos = new ParsePosition(0);
        formatter.parse(value, pos);
        if (pos.getErrorIndex() != -1) {
            return false;
        }
        if (strict) {
            if (pos.getIndex() < value.length()) {
                return false;
            }
        }
        return true;
    }

    private String complete(final String value, final String datePattern) {

        final StringBuilder completedValue = new StringBuilder();
        String valueToCheck = value;
        String datePatternToCheck = datePattern;
        int nextSeparatorIndex = nextSeparatorIndex(datePatternToCheck);
        while (nextSeparatorIndex != -1) {
            final int nextSeparatorIndexOfValueToCheck = valueToCheck
                    .indexOf(datePatternToCheck.charAt(nextSeparatorIndex));
            if (nextSeparatorIndexOfValueToCheck == -1) {
                break;
            }
            if (nextSeparatorIndexOfValueToCheck == 0 || isPlaceholderInvalidSubstitutionNeeded(
                    valueToCheck.substring(0, nextSeparatorIndexOfValueToCheck))) {
                completedValue.append(PLACEHOLDER_VALID);
                completedValue.append(valueToCheck.charAt(nextSeparatorIndexOfValueToCheck));
            } else if (isNoPossibleCompletionToAllowedYear(
                    valueToCheck.substring(0, nextSeparatorIndexOfValueToCheck), datePatternToCheck)) {
                completedValue.append(PLACEHOLDER_INVALID);
            } else {
                completedValue.append(valueToCheck.substring(0, nextSeparatorIndexOfValueToCheck + 1));
            }
            datePatternToCheck = datePatternToCheck.substring(nextSeparatorIndex + 1);
            valueToCheck = valueToCheck.substring(nextSeparatorIndexOfValueToCheck + 1);
            nextSeparatorIndex = nextSeparatorIndex(datePatternToCheck);
        }

        if (("".equals(valueToCheck) && !"".equals(datePatternToCheck)) //$NON-NLS-1$//$NON-NLS-2$
                || isPlaceholderInvalidSubstitutionNeeded(valueToCheck)) {
            completedValue.append(PLACEHOLDER_VALID);
        } else if (isNoPossibleCompletionToAllowedYear(valueToCheck, datePatternToCheck)) {
            completedValue.append(PLACEHOLDER_INVALID);
        } else {
            completedValue.append(valueToCheck);
        }

        // System.out.println("completed= " + completedValue.toString());
        return completedValue.toString();
    }

    private boolean isPlaceholderInvalidSubstitutionNeeded(final String value) {
        return "0".equals(value); //$NON-NLS-1$
    }

    private boolean isNoPossibleCompletionToAllowedYear(final String value, final String datePattern) {
        boolean result = false;
        if (datePattern.startsWith(IDateTextRidget.FORMAT_YYYY)) {
            final String trimedValue = value.trim();
            result = trimedValue.length() < 2 || (trimedValue.length() > 2 && trimedValue.startsWith("0")); //$NON-NLS-1$
            // System.out.println(String.format("%s '%s' %b", datePattern, trimedValue, result));
        }
        return result;
    }

    private int nextSeparatorIndex(final String value) {
        for (int i = 0; i < value.length(); i++) {
            if (!Character.isLetter(value.charAt(i))) {
                return i;
            }
        }
        return -1;
    }

    protected void setPattern(final String pattern) {
        this.pattern = pattern;
    }

    protected void setCheckValidIntermediate(final boolean checkValidIntermediate) {
        this.checkValidIntermediate = checkValidIntermediate;
    }

    /**
     * This method is called on a newly constructed extension for validation.
     * After creating a new instance of {@code AbstractValidDate} this method is
     * called to initialize the instance. The argument for initialization is in
     * the parameter {@code data}. Is the data a string the argument is the
     * initial value of {@code pattern}.
     * 
     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
     *      java.lang.String, java.lang.Object)
     */
    public void setInitializationData(final IConfigurationElement config, final String propertyName,
            final Object data) throws CoreException {

        if (data instanceof String) {
            final String[] args = PropertiesUtils.asArray(data);
            setPattern(args[0]);
        }

    }

}