/*******************************************************************************
* Copyright (c) 2007, 2014 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 org.apache.oro.text.perl.Perl5Util;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.runtime.Assert;
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.nls.Messages;
/**
* Implementation for a regular expression check. If the rule fails it will
* prevent updating the ridget and model values. The rule will not block invalid
* input to the widget.
* <p>
* Note that the value <tt>null</tt> will be treated as an empty string. The
* option <tt>i</tt>, <tt>m</tt> and <tt>x</tt>, as featured in the Perl5 native
* format <quote>[m]/pattern/[i][m][s][x]</quote> are supported through the
* {@link Option} enumeration.
* <p>
* At the moment this class supports Perl5 regular expressions. It is however
* recommended to stick to common standards between
* {@linkplain java.util.regex.Pattern java.util.regex} and Perl5 regular
* expressions, if possible.
* <p>
* This validation rule does not support partial correctness checking.
* <p>
*
* @see org.apache.oro.text.perl.Perl5Util#match(String, String)
* @see java.util.regex.Pattern
*/
public class ValidExpression implements IValidator, IExecutableExtension {
/** <code>GERMAN_ZIP</code> */
public static final String GERMAN_ZIP = "^[0-9]{5}$"; //$NON-NLS-1$
/**
* @see http://de.wikipedia.org/wiki/SWIFT
*/
public static final String SWIFT_BIC = "^([a-zA-Z]{6}[a-zA-Z\\d]{2})([a-zA-Z\\d]{3})?$"; //$NON-NLS-1$
/**
* Option postfixes.
*
* @see org.apache.oro.text.perl.Perl5Util#match(String, String)
* @see java.util.regex.Pattern
*/
public static enum Option {
/** Enables case insensitive matching. */
CASE_INSENSITIVE('i'),
/** Treats input as it would consist of multiple lines. */
MULTIPLE_LINE('m'),
/** Enables the extended expression syntax with whitespace and comments. */
ENABLE_EXTENDED_SYNTAX('x');
private final char symbol;
private Option(final char symbol) {
this.symbol = symbol;
}
}
/*
* Concurrent access is okay as long as #getMatch() is not used.
*
* @see org.apache.oro.text.perl.Perl5Util
*/
private final Perl5Util matcher = new Perl5Util();
private String pattern;
private final String options;
/**
* Constructs a new ValidExpression rule with the given options.
*/
public ValidExpression() {
this("*"); //$NON-NLS-1$
}
/**
* Constructs a new ValidExpression rule with the given options.
*
* @param regex
* the regular expression to check against
* @see org.apache.oro.text.perl.Perl5Util#match(String, String)
* @see java.util.regex.Pattern#matches(String, CharSequence)
* @throws some_kind_of_runtime_exception
* if parameter is <tt>null</tt>, pattern is a String of length
* zero, or pattern is malformed.
*/
public ValidExpression(final String pattern, final Option... options) {
Assert.isNotNull(pattern, "pattern must not be null"); //$NON-NLS-1$
Assert.isLegal(pattern.length() > 0, "pattern must not be empty"); //$NON-NLS-1$
this.pattern = pattern;
final StringBuilder optionsBuilder = new StringBuilder(4);
for (final Option option : options) {
optionsBuilder.append(option.symbol);
}
this.options = optionsBuilder.toString();
}
/**
* Matches the given object against this rule's regular expression.
*
* @see org.eclipse.core.databinding.validation.IValidator#validate(java.lang.Object)
*/
public IStatus validate(final Object value) {
if (!(value == null || value instanceof String)) {
throw new ValidationFailure(getClass().getSimpleName() + " can only validate objects of type " //$NON-NLS-1$
+ String.class.getName());
}
final String string = value == null ? "" : (String) value; //$NON-NLS-1$
// validates if char is not either whitespace or ignored.
if (matcher.match("/" + pattern + "/" + options, string)) { //$NON-NLS-1$//$NON-NLS-2$
return ValidationRuleStatus.ok();
}
final String message = NLS.bind(Messages.ValidExpression_error_noMatch, string, pattern);
return ValidationRuleStatus.error(false, message);
}
/**
* This method is called on a newly constructed extension for validation.
* After creating a new instance of {@code ValidExpression} 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);
pattern = args[0];
}
}
}