/* * (c) 2008- RANDI2 Core Development Team * * This file is part of RANDI2. * * RANDI2 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * RANDI2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along with * RANDI2. If not, see <http://www.gnu.org/licenses/>. */ package de.randi2.model; import java.io.Serializable; import java.lang.reflect.Field; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.Set; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; import javax.persistence.Transient; import javax.persistence.Version; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.validator.constraints.NotEmpty; import de.randi2.model.exceptions.ValidationException; /** * The super class for all persistent classes. * It contains all necessary field to save and check the objects. * * @author Daniel Schrimpf <ds@randi2.de> * */ @MappedSuperclass @Data @EqualsAndHashCode(of = { "id", "version" }) public abstract class AbstractDomainObject implements Serializable { private static final long serialVersionUID = -1394903092160914604L; public final static int NOT_YET_SAVED_ID = Integer.MIN_VALUE; public final static int MAX_VARCHAR_LENGTH = 255; @Transient private Map<String, Boolean> requiredFields = null; @Id @GeneratedValue(strategy = GenerationType.TABLE) private long id = NOT_YET_SAVED_ID; @Version private int version = Integer.MIN_VALUE; private GregorianCalendar createdAt = null; private GregorianCalendar updatedAt = null; private static final Random random = new Random(); public AbstractDomainObject() { //TODO ds: find out if the random initialization of the field version is necessary int v = random.nextInt(); this.version = (v < 0) ? v : -v; } /** * Checks if the value of the field is correct, if not a ValidationException is thrown. */ @SuppressWarnings("unchecked") public void checkValue(String fieldName, Object value) throws ValidationException { Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set<?> invalids = validator.validateValue(this.getClass(), fieldName, value); if (!invalids.isEmpty()) { throw new ValidationException((Set<ConstraintViolation<?>>) invalids); } } /** * Gets the required fields (a field with the annotation NotEmpty, NotNull * or Password). * * @return the required fields */ public Map<String, Boolean> getRequiredFields() { if (requiredFields == null) initializeRequiredFields(); return requiredFields; } private void initializeRequiredFields(){ requiredFields = new HashMap<String, Boolean>(); for (Field field : this.getClass().getDeclaredFields()) { requiredFields.put(field.getName(), this.isRequired(field)); } } private boolean isRequired(Field field) { return field.isAnnotationPresent(NotEmpty.class) || field.isAnnotationPresent(NotNull.class) || field.isAnnotationPresent(de.randi2.utility.validations.Password.class); } @PreUpdate public void beforeUpdate() { this.updatedAt = new GregorianCalendar(); } @PrePersist public void beforeCreate() { this.createdAt = new GregorianCalendar(); this.updatedAt = new GregorianCalendar(); } /** * This method provides a string object for the UI. * * @return the UI name */ @Transient public String getUIName() { // FIXME It would be better to have this method one level deeper return this.getClass().getCanonicalName(); } }