com.mpe.common.validation.BeanValidationEventListener.java Source code

Java tutorial

Introduction

Here is the source code for com.mpe.common.validation.BeanValidationEventListener.java

Source

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package com.mpe.common.validation;

import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.TraversableResolver;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.hibernate.EntityMode;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.beanvalidation.GroupsPerOperation;
import org.hibernate.cfg.beanvalidation.HibernateTraversableResolver;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
import org.jboss.logging.Logger;

/**
 * Event listener used to enable Bean Validation for insert/update/delete events.
 *
 * @author Emmanuel Bernard
 * @author Hardy Ferentschik
 */
//FIXME review exception model
public class BeanValidationEventListener
        implements PreInsertEventListener, PreUpdateEventListener, PreDeleteEventListener {

    //private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, BeanValidationEventListener.class.getName());

    Logger logger = Logger.getLogger(this.getClass());

    private ValidatorFactory factory;
    private ConcurrentHashMap<EntityPersister, Set<String>> associationsPerEntityPersister = new ConcurrentHashMap<EntityPersister, Set<String>>();
    private GroupsPerOperation groupsPerOperation;
    boolean initialized;

    /**
     * No-arg constructor used when listener is configured via configuration file
     */
    public BeanValidationEventListener() {
    }

    /**
     * Constructor used in an environment where validator factory is injected (JPA2).
     *
     * @param factory The {@code ValidatorFactory} to use to create {@code Validator} instance(s)
     * @param properties Configued properties
     */
    public BeanValidationEventListener(ValidatorFactory factory, Properties properties) {
        init(factory, properties);
    }

    public void initialize(Configuration cfg) {
        if (!initialized) {
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            Properties props = cfg.getProperties();
            init(factory, props);
        }
    }

    public boolean onPreInsert(PreInsertEvent event) {
        validate(event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(),
                event.getSession().getFactory(), GroupsPerOperation.Operation.INSERT);
        return false;
    }

    public boolean onPreUpdate(PreUpdateEvent event) {
        validate(event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(),
                event.getSession().getFactory(), GroupsPerOperation.Operation.UPDATE);
        return false;
    }

    public boolean onPreDelete(PreDeleteEvent event) {
        validate(event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(),
                event.getSession().getFactory(), GroupsPerOperation.Operation.DELETE);
        return false;
    }

    private void init(ValidatorFactory factory, Properties properties) {
        this.factory = factory;
        groupsPerOperation = new GroupsPerOperation(properties);
        initialized = true;
    }

    private <T> void validate(T object, EntityMode mode, EntityPersister persister,
            SessionFactoryImplementor sessionFactory, GroupsPerOperation.Operation operation) {
        if (object == null || mode != EntityMode.POJO) {
            return;
        }
        TraversableResolver tr = new HibernateTraversableResolver(persister, associationsPerEntityPersister,
                sessionFactory);
        Validator validator = factory.usingContext()
                .messageInterpolator(
                        new ResourceBundleMessageInterpolator(new PlatformResourceBundleLocator("globalMessages")))
                .traversableResolver(tr).getValidator();
        final Class<?>[] groups = groupsPerOperation.get(operation);
        if (groups.length > 0) {
            final Set<ConstraintViolation<T>> constraintViolations = validator.validate(object, groups);
            if (constraintViolations.size() > 0) {
                /*Set<ConstraintViolation<?>> propagatedViolations =
                      new HashSet<ConstraintViolation<?>>( constraintViolations.size() );
                Set<String> classNames = new HashSet<String>();
                for ( ConstraintViolation<?> violation : constraintViolations ) {
                   LOG.trace( violation );
                   propagatedViolations.add( violation );
                   classNames.add( violation.getLeafBean().getClass().getName() );
                }
                StringBuilder builder = new StringBuilder();
                builder.append( "Validation failed for classes " );
                builder.append( classNames );
                builder.append( " during " );
                builder.append( operation.getName() );
                builder.append( " time for groups " );
                builder.append( toString( groups ) );
                builder.append( "\nList of constraint violations:[\n" );
                for (ConstraintViolation<?> violation : constraintViolations) {
                   builder.append( "\t" ).append( violation.toString() ).append("\n");
                }
                builder.append( "]" );
                    
                throw new ConstraintViolationException(
                      builder.toString(), propagatedViolations
                );*/
                Set<ConstraintViolation<?>> propagatedViolations = new HashSet<ConstraintViolation<?>>(
                        constraintViolations.size());
                StringBuilder builder = new StringBuilder();
                for (ConstraintViolation<?> violation : constraintViolations) {
                    builder.append(violation.getMessage()).append("\n");
                }

                logger.info("CCC >> " + builder.toString());

                throw new ConstraintViolationException(builder.toString(), propagatedViolations);

            }
        }
    }

    private String toString(Class<?>[] groups) {
        StringBuilder toString = new StringBuilder("[");
        for (Class<?> group : groups) {
            toString.append(group.getName()).append(", ");
        }
        toString.append("]");
        return toString.toString();
    }
}