/******************************************************************************* * Copyright (c) 2015 Red Hat, Inc. Distributed under license by Red Hat, Inc. * All rights reserved. This program is 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: Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.openshift.internal.ui.validator; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.eclipse.core.databinding.validation.IValidator; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.runtime.IStatus; import org.eclipse.osgi.util.NLS; /** * Validate label values confirm to the format accepted * by OpenShift * * @author Jeff Cantrill */ public class LabelValueValidator implements IValidator { public static final int LABEL_MAXLENGTH = 63; private static final Pattern LABEL_REGEXP = Pattern.compile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$"); /** * This method must be in agreement with LABEL_REGEXP * @param c * @return */ protected static boolean isAlphaNumeric(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); } /** * This method must be in agreement with LABEL_REGEXP * @param c * @return */ protected static boolean isAlphaNumericOrValueSeparator(char c) { return isAlphaNumeric(c) || c == '.' || c == '-' || c == '_'; } public static final String valueDescription = "A valid {0} must be 63 characters or less\n" + "and must begin and end with an alphanumeric character ([a-z0-9A-Z]),\n" + "with dashes (-), underscores (_), dots (.), and alphanumerics between."; public static final String defaultType = "label value"; private final IStatus FAILED; protected String type; public LabelValueValidator() { this(defaultType); } public LabelValueValidator(String element) { type = element; FAILED = ValidationStatus.error(NLS.bind(valueDescription, type)); } @Override public IStatus validate(Object paramObject) { if(!(paramObject instanceof String)) { return ValidationStatus.cancel(getValueIsNotAStringMessage()); } String value = (String) paramObject; if(StringUtils.isBlank(value)) return ValidationStatus.cancel(NLS.bind("{0} is required.", type)); if(value.length() > LABEL_MAXLENGTH) { return getSizeConstraintError(); } if(!LABEL_REGEXP.matcher(value).matches()) { return getLabelRegexError(value, type); } return ValidationStatus.OK_STATUS; } protected String getValueIsNotAStringMessage() { return NLS.bind("{0} is not an instance of a string", type); } /** * Detailed status for the case LABEL_REGEXP.matcher(value).matches() = false * This method assumes that regexp match is failed! */ protected IStatus getLabelRegexError(String value, String type) { //1. Check the first character if(!isAlphaNumeric(value.charAt(0))) { return ValidationStatus.error(NLS.bind("A valid {0} must begin with an alphanumeric character", type)); } if(value.length() > 2) { //2. Check middle characters for (int i = 1; i < value.length() - 1; i++) { if(!isAlphaNumericOrValueSeparator(value.charAt(i))) { return ValidationStatus.error(NLS.bind("A character ''{0}'' is not allowed in {1}", value.substring(i, i + 1), type)); } } } if(value.length() > 1 && !isAlphaNumeric(value.charAt(value.length() - 1))) { //3. Check the last character return ValidationStatus.error(NLS.bind("A valid {0} must end with an alphanumeric character", type)); } //4. Should not happen. return ValidationStatus.error(NLS.bind("{0} is not valid.", type)); } protected boolean validateLabel(String value) { if (value.length() > LABEL_MAXLENGTH) { return false; } return LABEL_REGEXP.matcher(value).matches(); } protected IStatus getSizeConstraintError() { return ValidationStatus.error(NLS.bind("Maximum length allowed is {0} characters for {1}", LABEL_MAXLENGTH, type)); } protected IStatus getPatternConstraintError() { return getFailedStatus(); } protected IStatus getFailedStatus() { return FAILED; } }