/** * Contains the entity classes that form the Screensaver domain model. The model is grouped into conceptual groups: * * <ul> * * <li>{@link edu.harvard.med.screensaver.model.users} * <li>{@link edu.harvard.med.screensaver.model.libraries} * <li>{@link edu.harvard.med.screensaver.model.screens} * <li>{@link edu.harvard.med.screensaver.model.screenresults} * <li>{@link edu.harvard.med.screensaver.model.cherrypicks} * <li>{@link edu.harvard.med.screensaver.model.activities.Activity} (activity entities are dispersed throughout multiple model packages) * * </ul> * * <h3>Hibernate Annotations and the Java Persistence API</h3> * * The domain model entity classes are mapped to a relational database schema using JPA * annotations and Hibernate annotations (for extended mapping functionality). Screensaver also provides * its own set of domain model annotations in the {@link * edu.harvard.med.screensaver.model.annotations} package. These annotations * are mainly used to implement a comprehensive test suite of the model, which * tests for model correctness as thoroughly as possible. * * <h3>Entity Identifiers</h3> * * Domain model entity classes must implement the {@link edu.harvard.med.screensaver.model.Entity} interface and may extend * {@link edu.harvard.med.screensaver.model.AbstractEntity}. Two different * methods are used for implementing entity ids for the entity classes: * * <ol> * * <li>Use a database sequence to generate entity id values. In this case, entities do not * get assigned an id until they are persisted to the database. Object methods * <code>equals(Object)</code> and <code>hashCode()</code> are not overridden by these * classes, so that * for the purpose of set containment, etc., object identity is used to compare objects. * For this reason, any two non-persisted entity objects are considered different. Also, any * two persisted entity objects are considered different, even if they have the same entity * id! However, note that Hibernate will assure that only one object is created for an * entity with a given type and entity id, <i>per session</i>. So care must be taken to * assure that the objects belong to the same session before comparing for identity in this * way. DAO methods {@link * edu.harvard.med.screensaver.db.GenericEntityDAO#reattachEntity(Entity)}, {@link * edu.harvard.med.screensaver.db.GenericEntityDAO#reloadEntity(Entity)}, and {@link * edu.harvard.med.screensaver.db.GenericEntityDAO#reloadEntity(Entity, boolean, edu.harvard.med.screensaver.model.meta.RelationshipPath)} may be found useful for * looking up a version of an entity that lives in the current session. * * <li>Use a <i>semantic id</i>, or <i>business key</i>, as an id for the entity. In this * case, the entity should get assigned a stable id, as returned by {@link * edu.harvard.med.screensaver.model.AbstractEntity#getEntityId()}, at object creation time (ie, in the * constructor). These kinds of entities should inherit from {@link * edu.harvard.med.screensaver.model.SemanticIDAbstractEntity}, * which has {@link * edu.harvard.med.screensaver.model.AbstractEntity} as a superclass. * <code>SemanticIDAbstractEntity</code> * overrides <code>equals</code> and <code>hashCode</code> methods based on the entity id. * Semantic ids are particularly useful if you need to be able to look up an existing entity * in an unflushed Hibernate session, since the only way to look up a newly created entity in * an unflushed session is by the entity id. In most cases, the decision to use a semantic * id is motivated by this consideration. * * </ol> * * <h3>Containment Relationships</h3> * * We use a set of conventions for modelling containment, or ownership, relationships. * First, the contained entity is annotated with {@link * edu.harvard.med.screensaver.model.annotations.ContainedEntity}, which indicates * the containing class that is responsible for providing create*() methods for the contained entity. * * <p> * * For every containment relationship, there are one or more methods that match the pattern * <code>public Contained Container.createContained(...)</code>. For example, see * {@link edu.harvard.med.screensaver.model.libraries.Library#createWell(edu.harvard.med.screensaver.model.libraries.WellKey, edu.harvard.med.screensaver.model.libraries.LibraryWellType)}, * This factory method is * responsible for adding the newly created entity into any bidirectional relationships, * almost always including the classes own * <code>public Set<Contained> Container.getContaineds()</code>. The factory methods are * also responsible for testing for duplicate entities. (These are responsibilities that * used to fall to the contained entity's constructor.) Besides the no-arg constructor * needed for Hibernate, all the contained entity's constructors are intended only for * these factory methods. Javadoc for the constructors always indicates this, and visibility * of the constructors is as restrictive as possible for the contained class to be able to * access it. (There are cases where the container and contained are in different packages, * so that the constructor has to be public.) * * <p> * * The <code>Contained.container</code> property is always * <code>@javax.persistence.Immutable</code>, and it is always set in the constructor. * * <h3>Conventions with Types</h3> * * We try to be as consistent as possible with types (both Java types and Hibernate types). * We use the following guidelines for choosing types: * * <dl> * * <dt>booleans * <dd>We assume booleans are non-nullable, and prefer to use primitive Java type * <code>boolean</code> over <code>java.lang.Boolean</code>. For boolean property * <code>foo</code>, we name the getter <code>isFoo</code>, the setter <code>setFoo</code>, * and the database column <code>is_foo</code>. We provide <code>javax.persistence</code> * annotation <code>@Column(nullable=false, name="isFoo")</code> to make the database * column <code>NOT NULL</code> and named <code>is_foo</code> instead of <code>foo</code>. * * <dt>strings * <dd>We use the PostgreSQL database type <code>TEXT</code> wherever possible, since there * is no performance penalty for doing so, and it avoids ugly problems of * <code>VARCHAR</code>s not being large enough. We annotate with * <code>@org.hibernate.annotations.Type(type="text")</code> to get this database type. * * <dt>integers * <dd>In general, we use the Java type <code>Integer</code> to represent integral * values, and the default Hibernate type for this Java type. This converts to PostgreSQL * type <code>integer</code>. This type is used for version fields as well as for entity id * values generated by a database sequence. * * <dt>floats * <dd>We use the Java type <code>BigDecimal</code> to represent rational values, and * explicitly set the Hibernate type to <code>big_decimal</code>. This converts to * PostgreSQL type <code>numeric(19,2)</code>. We always include the units of the value * in the property name for the sake of clarity. * * <dt>controlled vocabularies * <dd>All controller vocabularies in our model are enums that implement the interface * {@link edu.harvard.med.screensaver.model.VocabularyTerm}. These enums all provide a public * static inner class that implements the abstract class {@link * edu.harvard.med.screensaver.model.VocabularyUserType}; these inner classes become the * Hibernate type used for the controller vocabularies. More detail is provided in the class * documentation for {@link edu.harvard.med.screensaver.model.VocabularyUserType}. This rather * awkward system is forced upon us by a variety of * constraints: we want to use enumerations; the Java implementation of enumerations has * functional limitations (e.g., they can't <code>extend</code> an existing class or enum); * and the Hibernate requirements for user types are required to implement a somewhat * complex interface, <code>org.hibernate.usertype.UserType</code>. (In particular, the * restriction on Java enums, coupled with the Hibernate restrictions, prevent us from * using the same type as both the enumeration type and the Hibernate type, unless we provide * the boiler-plate code needed to implement <code>UserType</code> in every controlled * vocabulary type in our model.) * * </dl> * * <h3>Conventions for Relationships</h3> * * Our model contains one-to-one, one-to-many, and many-to-many relationships. Some are * unidirectional and some are bidirectional. Some one-to-one and one-to-many relationships * are distinguished as containment relationships by the presence of a {@link * edu.harvard.med.screensaver.model.annotations.ContainedEntity} annotation on the child * class. We use proxy relationships whenever possible, and lazy relationships liberally, * preferring to specify which relationships should be loaded via arguments to the {@link * edu.harvard.med.screensaver.db.GenericEntityDAO DAO} methods for loading entities. * * <h3>Miscellaneous Conventions</h3> * * Generally speaking, all the conventions we have adopted are meant to serve our needs, mostly * by making our lives easier by having consistency throughout the model. This is helpful for * reading and understanding the model code, as well as for generating new model code, since * a copy/paste/edit routine is generally a pretty safe bet. But these are only conventions, and * if they are hindering us from accomplishing what we want in our model, then we will freely * ignore, trash, or re-convene them. An incomplete list of further miscellaneous conventions follows: * * <dl> * * <dt>naming of foreign keys * <dd>We provide names for foreign keys and other database constraints whenever Hibernate allows * it. We name foreign key constraints as <code>"fk_" + from_table_name + "_to_" + to_table_name</code>. * In situations where there are multiple properties representing relationships between the same two * tables, we replace the table names with the relationship names (converting from camel-case to * underscore-delimited). * * </dl> */ package edu.harvard.med.screensaver.model;