com.fiveamsolutions.nci.commons.web.struts2.validator.HibernateValidator.java Source code

Java tutorial

Introduction

Here is the source code for com.fiveamsolutions.nci.commons.web.struts2.validator.HibernateValidator.java

Source

/**
 * The software subject to this notice and license includes both human readable
 * source code form and machine readable, binary, object code form. The caarray-war
 * Software was developed in conjunction with the National Cancer Institute
 * (NCI) by NCI employees and 5AM Solutions, Inc. (5AM). To the extent
 * government employees are authors, any rights in such works shall be subject
 * to Title 17 of the United States Code, section 105.
 *
 * This caarray-war Software License (the License) is between NCI and You. You (or
 * Your) shall mean a person or an entity, and all other entities that control,
 * are controlled by, or are under common control with the entity. Control for
 * purposes of this definition means (i) the direct or indirect power to cause
 * the direction or management of such entity, whether by contract or otherwise,
 * or (ii) ownership of fifty percent (50%) or more of the outstanding shares,
 * or (iii) beneficial ownership of such entity.
 *
 * This License is granted provided that You agree to the conditions described
 * below. NCI grants You a non-exclusive, worldwide, perpetual, fully-paid-up,
 * no-charge, irrevocable, transferable and royalty-free right and license in
 * its rights in the caarray-war Software to (i) use, install, access, operate,
 * execute, copy, modify, translate, market, publicly display, publicly perform,
 * and prepare derivative works of the caarray-war Software; (ii) distribute and
 * have distributed to and by third parties the caarray-war Software and any
 * modifications and derivative works thereof; and (iii) sublicense the
 * foregoing rights set out in (i) and (ii) to third parties, including the
 * right to license such rights to further third parties. For sake of clarity,
 * and not by way of limitation, NCI shall have no right of accounting or right
 * of payment from You or Your sub-licensees for the rights granted under this
 * License. This License is granted at no charge to You.
 *
 * Your redistributions of the source code for the Software must retain the
 * above copyright notice, this list of conditions and the disclaimer and
 * limitation of liability of Article 6, below. Your redistributions in object
 * code form must reproduce the above copyright notice, this list of conditions
 * and the disclaimer of Article 6 in the documentation and/or other materials
 * provided with the distribution, if any.
 *
 * Your end-user documentation included with the redistribution, if any, must
 * include the following acknowledgment: This product includes software
 * developed by 5AM and the National Cancer Institute. If You do not include
 * such end-user documentation, You shall include this acknowledgment in the
 * Software itself, wherever such third-party acknowledgments normally appear.
 *
 * You may not use the names "The National Cancer Institute", "NCI", or "5AM"
 * to endorse or promote products derived from this Software. This License does
 * not authorize You to use any trademarks, service marks, trade names, logos or
 * product names of either NCI or 5AM, except as required to comply with the
 * terms of this License.
 *
 * For sake of clarity, and not by way of limitation, You may incorporate this
 * Software into Your proprietary programs and into any third party proprietary
 * programs. However, if You incorporate the Software into third party
 * proprietary programs, You agree that You are solely responsible for obtaining
 * any permission from such third parties required to incorporate the Software
 * into such third party proprietary programs and for informing Your
 * sub-licensees, including without limitation Your end-users, of their
 * obligation to secure any required permissions from such third parties before
 * incorporating the Software into such third party proprietary software
 * programs. In the event that You fail to obtain such permissions, You agree
 * to indemnify NCI for any claims against NCI by such third parties, except to
 * the extent prohibited by law, resulting from Your failure to obtain such
 * permissions.
 *
 * For sake of clarity, and not by way of limitation, You may add Your own
 * copyright statement to Your modifications and to the derivative works, and
 * You may provide additional or different license terms and conditions in Your
 * sublicenses of modifications of the Software, or any derivative works of the
 * Software as a whole, provided Your use, reproduction, and distribution of the
 * Work otherwise complies with the conditions stated in this License.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS," AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 * (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED. IN NO
 * EVENT SHALL THE NATIONAL CANCER INSTITUTE, 5AM SOLUTIONS, INC. OR THEIR
 * AFFILIATES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.fiveamsolutions.nci.commons.web.struts2.validator;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;

import com.fiveamsolutions.nci.commons.util.HibernateHelper;
import com.fiveamsolutions.nci.commons.validator.MultipleCriteriaMessageInterpolator;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;

/**
 * Class to provide hibernate validator support in Struts 2.
 *
 * @author Scott Miller
 */
@SuppressWarnings("PMD.TooManyMethods")
public class HibernateValidator extends FieldValidatorSupport {
    private String resourceKeyBase;
    private String conditionalExpression;
    private String includes;
    private Set<String> parsedIncludes;
    private String excludes;
    private Set<String> parsedExcludes;

    /**
     * {@inheritDoc}
     */
    public void validate(Object object) throws ValidationException {
        ValueStack stack = ActionContext.getContext().getValueStack();
        if (StringUtils.isNotBlank(getConditionalExpression())
                && !(Boolean) stack.findValue(getConditionalExpression())) {
            return;
        }
        Object value = getFieldValue(getFieldName(), object);
        stack.push(object);
        if (value instanceof Collection<?>) {
            Collection<?> coll = (Collection<?>) value;
            Object[] array = coll.toArray();
            validateArrayElements(array, getFieldName());
        } else if (value instanceof Object[]) {
            Object[] array = (Object[]) value;
            validateArrayElements(array, getFieldName());
        } else {
            validateObject(getFieldName(), value);
        }
        stack.pop();
    }

    private static String simplifyFieldName(String name) {
        if (name == null) {
            return name;
        }
        int start = name.indexOf('[');
        if (start >= 0) {
            int end = name.indexOf(']', start);
            return name.substring(0, start) + simplifyFieldName(name.substring(end + 1));
        }
        return name;
    }

    private void addFieldError(String fieldName, InvalidValue message) {
        StringBuffer errorField = new StringBuffer(fieldName);
        StringBuffer errorFieldKey = new StringBuffer(fieldName);
        if (StringUtils.isNotBlank(getResourceKeyBase())) {
            errorFieldKey.setLength(0); // clear
            errorFieldKey.append(getResourceKeyBase());
        }
        errorField.append('.').append(message.getPropertyPath());
        errorFieldKey.append('.').append(message.getPropertyPath());
        String msg = StringUtils.replace(message.getMessage(), "(fieldName)",
                getValidatorContext().getText(errorFieldKey.toString(), message.getPropertyPath()));
        String errorFieldName = errorField.toString();
        getValidatorContext().addFieldError(errorFieldName, msg);

    }

    private void convertMessages(String fieldName, InvalidValue[] validationMessages) {
        for (InvalidValue message : validationMessages) {
            convertMessage(fieldName, message);
        }
    }

    private void convertMessage(String fieldName, InvalidValue message) {
        if (message.getMessage().startsWith(MultipleCriteriaMessageInterpolator.HEADER)) {
            convertMultipleCriteriaMessages(fieldName, message.getMessage());
        } else if (isFieldError(message)) {
            convertFieldError(fieldName, message);
        } else {
            getValidatorContext().addActionError(message.getMessage());
        }
    }

    private boolean isFieldError(InvalidValue message) {
        return StringUtils.isNotBlank(message.getPropertyName());
    }

    private void convertFieldError(String fieldName, InvalidValue message) {
        String path = message.getPropertyPath();
        String simpleName = simplifyFieldName(path);
        if ((parsedIncludes == null || parsedIncludes.contains(simpleName))
                && (parsedExcludes == null || !parsedExcludes.contains(simpleName))) {
            addFieldError(fieldName, message);
        }
    }

    private void convertMultipleCriteriaMessages(String fieldName, String combinedMessage) {
        String[] messages = StringUtils.splitByWholeSeparator(combinedMessage,
                MultipleCriteriaMessageInterpolator.MESSAGE_SEPARATOR);
        //start from 1, because the message at index 0 is actually the header
        for (int i = 1; i < messages.length; i++) {
            if (StringUtils.isNotBlank(messages[i])) {
                String[] messageParts = StringUtils.splitByWholeSeparator(messages[i],
                        MultipleCriteriaMessageInterpolator.FIELD_SEPARATOR);
                InvalidValue iv = new InvalidValue(messageParts[1], null, messageParts[0], null, null);
                addFieldError(fieldName, iv);
            }
        }
    }

    private void validateArrayElements(Object[] array, String fieldName) {
        for (int i = 0; i < array.length; i++) {
            Object o = array[i];
            validateObject(fieldName + "[" + i + "]", o);
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void validateObject(String fieldName, Object o) {
        if (o != null) {
            ClassValidator classValidator = HibernateHelper.getClassValidator(o);
            InvalidValue[] validationMessages = classValidator.getInvalidValues(o);
            if (validationMessages.length > 0) {
                convertMessages(fieldName, validationMessages);
            }
        }
    }

    /**
     * @return the resourceKeyBase
     */
    public String getResourceKeyBase() {
        return this.resourceKeyBase;
    }

    /**
     * @param resourceKeyBase the resourceKeyBase to set
     */
    public void setResourceKeyBase(String resourceKeyBase) {
        this.resourceKeyBase = resourceKeyBase;
    }

    /**
     * @return the conditionalExpression
     */
    public String getConditionalExpression() {
        return this.conditionalExpression;
    }

    /**
     * @param conditionalExpression the conditionalExpression to set
     */
    public void setConditionalExpression(String conditionalExpression) {
        this.conditionalExpression = conditionalExpression;
    }

    /**
     * @return the includes
     */
    public String getIncludes() {
        return includes;
    }

    /**
     * @param includes A comma seperated list of property names to validate.
     */
    public void setIncludes(String includes) {
        this.includes = includes;
        this.parsedIncludes = parseList(includes);
    }

    /**
     * @return the excludes list
     */
    public String getExcludes() {
        return excludes;
    }

    /**
     * @param excludes A comma seperated list of property names to exclude from validation.
     */
    public void setExcludes(String excludes) {
        this.excludes = excludes;
        this.parsedExcludes = parseList(excludes);
    }

    private static Set<String> parseList(String list) {
        if (StringUtils.isBlank(list)) {
            return null;
        }
        HashSet<String> names = new HashSet<String>();
        StringTokenizer st = new StringTokenizer(list, ",");
        while (st.hasMoreTokens()) {
            String n = st.nextToken().trim();
            if (StringUtils.isNotBlank(n)) {
                names.add(n);
            }
        }
        return !names.isEmpty() ? names : null;
    }

}