edu.harvard.med.screensaver.model.AuditedAbstractEntity.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.med.screensaver.model.AuditedAbstractEntity.java

Source

// $HeadURL$
// $Id$
//
// Copyright  2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
// 
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.

package edu.harvard.med.screensaver.model;

import java.io.Serializable;
import java.util.Comparator;
import java.util.SortedSet;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;

import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;

import edu.harvard.med.screensaver.model.activities.Activity;
import edu.harvard.med.screensaver.model.activities.AdministrativeActivity;
import edu.harvard.med.screensaver.model.activities.AdministrativeActivityType;
import edu.harvard.med.screensaver.model.meta.Cardinality;
import edu.harvard.med.screensaver.model.meta.RelationshipPath;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.model.users.ScreensaverUser;

/**
 * Parent class of entity types that require auditing of their creation and
 * update events. Creation information (who, when) is stored directly as
 * properties in the class. Update information (who, when, what) is stored as a
 * set of associated AdministrativeActivity objects of type
 * {@link AdministrativeActivityType#ENTITY_UPDATE}. (Note that
 * AdministrativeActivity is itself an {@link AuditedAbstractEntity}, but entity
 * update activities should not themselves every be updated, so we don't have a
 * recursion problem!)
 * <p/>
 * Every subclass will store its entity update activities in it own database
 * table. To make this work within Hibernate, the subclass must override the
 * {@link #getUpdateActivities()} method for the sole purpose of defining the
 * Hibernate mapping annotations there. See existing subclasses for examples of
 * the requisite annotations.
 * <p/>
 * Subclass constructors <i>must</i> call
 * {@link #AuditedAbstractEntity(AdministratorUser)} to ensure that a creation
 * timestamp is recorded (the {@link #AuditedAbstractEntity()} constructor is
 * for Hibernate's use only).
 */
@MappedSuperclass
public abstract class AuditedAbstractEntity<K extends Serializable> extends AbstractEntity<K> {
    private static final long serialVersionUID = 1L;

    public static final RelationshipPath<AuditedAbstractEntity> createdBy = RelationshipPath
            .from(AuditedAbstractEntity.class).to("createdBy", Cardinality.TO_ONE);
    public static final RelationshipPath<AuditedAbstractEntity> updateActivities = RelationshipPath
            .from(AuditedAbstractEntity.class).to("updateActivities");

    protected SortedSet<AdministrativeActivity> _updateActivities = Sets.newTreeSet();

    private ScreensaverUser _createdBy;
    private DateTime _createdTimestamp;
    private DateTime _loadedTimestamp;
    private DateTime _publiclyAvailableTimestamp;

    /**
     * @motivation for Hibernate ONLY
     */
    protected AuditedAbstractEntity() {
    }

    protected AuditedAbstractEntity(AdministratorUser createdBy) {
        _createdBy = createdBy;
        _createdTimestamp = new DateTime();
        _loadedTimestamp = new DateTime();
        _publiclyAvailableTimestamp = new DateTime();
    }

    protected AuditedAbstractEntity(AdministratorUser createdBy, DateTime loaded, DateTime publiclyAvailable) {
        _createdBy = createdBy;
        _createdTimestamp = new DateTime();
        _loadedTimestamp = loaded;
        _publiclyAvailableTimestamp = publiclyAvailable;
    }

    //@Immutable
    @Column(nullable = false, updatable = false)
    @Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
    public DateTime getDateCreated() {
        return _createdTimestamp;
    }

    private void setDateCreated(DateTime createdTimeStamp) {
        _createdTimestamp = createdTimeStamp;
    }

    /**
     * The date that data is loaded into the database (used by LINCS)
     */
    @Column(nullable = true, updatable = false)
    @Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
    public DateTime getDateLoaded() {
        return _loadedTimestamp;
    }

    private void setDateLoaded(DateTime value) {
        _loadedTimestamp = value;
    }

    /**
     * The date that data has been made publicly available (used by LINCS)
     */
    @Column(nullable = true, updatable = false)
    @Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
    public DateTime getDatePubliclyAvailable() {
        return _publiclyAvailableTimestamp;
    }

    private void setDatePubliclyAvailable(DateTime value) {
        _publiclyAvailableTimestamp = value;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "createdById", updatable = false)
    @org.hibernate.annotations.LazyToOne(value = org.hibernate.annotations.LazyToOneOption.PROXY)
    @org.hibernate.annotations.Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE })
    @edu.harvard.med.screensaver.model.annotations.ToOne(unidirectional = true, hasNonconventionalSetterMethod = true /* nullable, immutable, to-one relationships not supported by domain model testing framework */)
    public ScreensaverUser getCreatedBy() {
        return _createdBy;
    }

    private void setCreatedBy(ScreensaverUser createdBy) {
        _createdBy = createdBy;
    }

    /**
     * To make update persistent, override in subclasses and add necessary Hibernate annotations on the overriding method.
     */
    @Transient
    public SortedSet<AdministrativeActivity> getUpdateActivities() {
        return _updateActivities;
    }

    @Transient
    public SortedSet<AdministrativeActivity> getUpdateActivitiesOfType(AdministrativeActivityType activityType) {
        return Sets.newTreeSet(Sets.filter(_updateActivities, AdministrativeActivity.IsOfType(activityType)));
    }

    /**
     * @param activityType
     * @return the most recently performed {@link AdministrativeActivity} of the specified type; if no activity of the
     *         specified type exists, returns a {@link AdministrativeActivity} with all properties set to
     *         </code>null</code>
     */
    @Transient
    public AdministrativeActivity getLastUpdateActivityOfType(AdministrativeActivityType activityType) {
        SortedSet<AdministrativeActivity> activities = getUpdateActivitiesOfType(activityType);
        return activities.isEmpty() ? AdministrativeActivity.Null : activities.last();
    }

    private static Ordering<Activity> ActivityRecordedOrdering = Ordering.from(new Comparator<Activity>() {
        @Override
        public int compare(Activity a1, Activity a2) {
            return a1.getDateCreated().compareTo(a2.getDateCreated());
        }
    });

    @Transient
    public AdministrativeActivity getLastRecordedUpdateActivityOfType(AdministrativeActivityType activityType) {
        SortedSet<AdministrativeActivity> activities = getUpdateActivitiesOfType(activityType);
        return activities.isEmpty() ? AdministrativeActivity.Null : ActivityRecordedOrdering.max(activities);
    }

    private void setUpdateActivities(SortedSet<AdministrativeActivity> updateActivities) {
        _updateActivities = updateActivities;
    }

    public AdministrativeActivity createUpdateActivity(AdministratorUser recordedBy, String comments) {
        return createUpdateActivity(AdministrativeActivityType.ENTITY_UPDATE, recordedBy, comments);
    }

    public AdministrativeActivity createUpdateActivity(AdministrativeActivityType activityType,
            AdministratorUser recordedBy, String comments) {
        AdministrativeActivity updateActivity = new AdministrativeActivity(recordedBy, new DateTime().toLocalDate(),
                activityType);
        updateActivity.setComments(comments);
        _updateActivities.add(updateActivity);
        return updateActivity;
    }

    public AdministrativeActivity createComment(AdministratorUser recordedBy, String comment) {
        return createUpdateActivity(AdministrativeActivityType.COMMENT, recordedBy, comment);
    }

}