Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

Objects persisted via JPA are generally referred to as Managed Objects. In uPortal all domain objects are first defined by a public interface and then a concrete implementation with the JPA annotations is created. An example interface and implementation are included at the bottom of this section.

These guidelines should must be used when creating Managed Objects in uPortal

  1. Define the domain object methods in an Interface
  2. The domain object should be data focused, it must not also encapsulate buisness logic.
  3. The implementation should be package private and exist in the same package as the DAO implementation and the DAO implementation should be the only class ever creating new instances of the managed object.
  4. A surrogate key must be defined as the primary @Id for the object, business keys must never be used as the primary @Id.
  5. An immutable natural key shouldbe defined. This is one or more fields that make up a unique business identity for the object.
    • These fields should be annotated with @NaturalId to gain significant performance improvements when querying using the natural id fields.
    • These fields should be marked as final and passed in via the constructor
  6. All nullable=false fields must be passed in via the constructor to prevent invalid object creation .and should be marked as final
  7. A private no-arg constructor is required to allow Hibernate to create the object using reflection. This constructor is private to protect against invalid object creation.
  8. Both @TableGenerator and @SequenceGenerator annotations should be used to define the generator for the @GeneratedValue annotation. This allows for the maximum flexibility and consistency across databases.
  9. equals and hashCode must be implemented but must only ever include the fields that make up the unique business identity of the object.
    • For objects defined by an interface all efforts should be made to allow two different implementations of the same object interface to be equal to each other
  10. toString should be implemented and should as much information as is needed to easily identify the object but not too much that it clutters log files.
  11. Objects should define a version field annotated with @Version to support optimistic locking and data-integrity checks

...

Expand
PortletTypeImpl.java
PortletTypeImpl.java
Code Block
java
java
@Entity
@Table(name = "UP_PORTLET_TYPE")
@SequenceGenerator(
        name="UP_PORTLET_TYPE_GEN",
        sequenceName="UP_PORTLET_TYPE_SEQ",
        allocationSize=1
    )
@TableGenerator(
        name="UP_PORTLET_TYPE_GEN",
        pkColumnValue="UP_PORTLET_TYPE",
        allocationSize=1
    )
@NaturalIdCache
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class PortletTypeImpl implements Serializable, IPortletType {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator = "UP_PORTLET_TYPE_GEN")
    @Column(name = "TYPE_ID")
    private final int internalId;
    
    @Version
    @Column(name = "ENTITY_VERSION")
    private final long entityVersion;
    
@NaturalId     @Column(name = "TYPE_NAME", length = 70, nullable = false)
    private final String name;

    @Column(name = "TYPE_DESCR", length = 2000)
    private String descr;

    @Column(name = "TYPE_DEF_URI", length = 255, nullable = false)
    private String cpdUri;
    
    /**
     * Default constructor used by hibernate
     */
    @SuppressWarnings("unused")
    private PortletTypeImpl() {
        this.internalId = -1;
        this.name = null;
    }
 //Hidden reference to the child portlet definitions, used to allow cascading deletes where when a portlet type is deleted all associated definitions are also deleted
    //MUST BE LAZY FETCH, this set should never actually be populated at runtime or performance will be TERRIBLE
    @OneToMany(mappedBy = "portletType", targetEntity = PortletDefinitionImpl.class, cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, orphanRemoval = true)
    private transient Set<IPortletDefinition> portletDefinitions = null;

    @NaturalId
    @Column(name = "TYPE_NAME", length = 70)
    private final String name;
    @Column(name = "TYPE_DESCR", length = 2000)
    private String descr;
    @Column(name = "TYPE_DEF_URI", length = 255, nullable = false)
    private String cpdUri;
    
  PortletTypeImpl(String name, String cpdUri  /**
     * Default constructor used by hibernate
     */
    @SuppressWarnings("unused")
    private PortletTypeImpl() {
        this.internalId = -1;
        this.nameentityVersion = name-1;
        this.cpdUriname = cpdUrinull;
    }

    @Override
    public int getId(PortletTypeImpl(String name, String cpdUri) {

       return this.internalId = -1;
      }  this.entityVersion = -1;
   @Override     publicthis.name String getName() {= name;
        this.cpdUri return= namecpdUri;
    }

    @Override
    public Stringint getDescriptiongetId() {
        return descrthis.internalId;
    }

    @Override
    public String getCpdUrigetName() {
        return cpdUriname;
    }

    @Override
    public voidString setDescriptiongetDescription(String) descr) {
        this.descr =return descr;
    }
     @Override
    public voidString setCpdUrigetCpdUri(String cpdUri) {
        this.cpdUri =return cpdUri;
    }

    @Override
    public booleanvoid equalssetDescription(ObjectString objectdescr) {
        if (object =this.descr = this)descr;
{    }
    @Override
   return true;public void setCpdUri(String cpdUri) {
    }    this.cpdUri = cpdUri;
  if (!(object instanceof IPortletType)  }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
 return false;         } return true;
      IPortletType rhs =if (!(obj instanceof IPortletType))
object;         return new EqualsBuilder() return false;
        IPortletType  .append(this.name, rhs.getName())
other = (IPortletType) obj;
        if (this.name == .isEquals(null); {
   }      @Override     public int hashCodeif (other.getName() {!= null)
       return new HashCodeBuilder(-1497407419, 1799845985)      return false;
     .append(this.name)   }
        else .toHashCode();if (!this.name.equals(other.getName()))
    }      @Override  return false;
 public String toString() {    return true;
   return new}
ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)   @Override
    public int    .append("name", this.namehashCode() {
        final int  .append("cpdUri", this.cpdUri)
            .toString();prime = 31;
        int result = 1;
        result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
     } }
  return result;
    }
    @Override
    public String toString() {
        return "PortletTypeImpl [internalId=" + this.internalId + ", name=" + this.name + ", descr=" + this.descr
                + ", cpdUri=" + this.cpdUri + "]";
    }

    @Override
    public String getDataId() {
        return Integer.toString(getId());
    }

    @Override
    public String getDataTitle() {
        return name;
    }

    @Override
    public String getDataDescription() {
        return descr;
    }
}

JPA DAO Design

JPA DAOs are generally not that complex CRUD style data access objects. There a few design patterns that must be followed for all uPortal JPA DAOs.

  1. All JPA DAO must extend from BasePortalJpaDao. This class provides common functionality for building and executing queries that should be used by all JPA DAOs.
  2. The DAO must have a create method that takes in as parameters all the data required to create an persist the entity. This method will call the package-private constructor of the managed object and then must call entityManager.persist the entity. This method will call the package-private constructor of the managed object and then must call entityManager.persist() before returning the managed object. Unattached JPA Managed Objects should never exist in uPortal.
  3. Wherever possible the DAO should use the CriteriaBuilder API and the JPA MetaModel. These tools all for 100% type safe and re-factoring safe queries.
JPA DAO Examples

...

  1. () before returning the managed object. Unattached JPA Managed Objects should never exist in uPortal.
  2. Wherever possible the DAO should use the CriteriaBuilder API and the JPA MetaModel. This ensures that later refactoring doesn't break queries.
JPA DAO Examples
Expand
IPortletTypeDao.java
IPortletTypeDao.java
Code Block
java
java
public interface IPortletTypeDao {
    /**
     * Creates, initializes and persists a new {@link IPortletType} based on the specified parameters
     * 
     * @param name The name of the channel type
     * @param cpdUri The URI to the CPD file used when publishing channels of this type
     * 
     * Creates@return A newly created, initializesinitialized and persists apersisted new {@link IPortletType} based on the specified parameters
     * 
     * @throws org.springframework.dao.DataIntegrityViolationException If a IChannelType already exists for the provide arguments
     * @param@throws nameIllegalArgumentException TheIf nameany of the parameters channelare typenull
     * @param/
cpdUri The URI to thepublic CPDIPortletType file used when publishing channels of this typecreatePortletType(String name, String cpdUri);
    
    /** 
  
  * @return A newly* created,Persists initializedchanges andto persisteda {@link IPortletType}.
     * @throws org.springframework.dao.DataIntegrityViolationException If a IChannelType already exists for the provide arguments 
     * @param type The channel type to store the changes for
     * @throws IllegalArgumentException Ifif any of the parameters aretype is null.
     */
    public IPortletType createPortletType(String name, String cpdUriupdatePortletType(IPortletType type);
    
    /**
     * PersistsRemoves changesthe tospecified a {@link IPortletType} from the persistent store.
     * 
     * @param type The channel type to store the changes forremove.
     * @throws IllegalArgumentException if type is null.
     */
    public IPortletTypevoid updatePortletTypedeletePortletType(IPortletType type);
    
    /**
     * RemovesGet thea specified {@link IPortletType} fromfor the persistentspecified storeid.
     * 
     * @param typeid The id to get the type for.
    to remove.* @return The channel type for *the @throwsid, IllegalArgumentExceptionnull if no type exists isfor the nullid.
     */
    public voidIPortletType deletePortletTypegetPortletType(IPortletTypeint typeid);
    
    /**
     * Get a {@link IPortletType} for the specified id.name
     * 
     * @param idname The idname to get the type for.
     * @return The channel type for the idname, null if no type exists for the idfname.
     * @throws IllegalArgumentException if name is null.
     */
    public IPortletType getPortletType(intString idname);
    
    /**
     * Get@return aA {@link IPortletTypeList} of forall thepersisted specified name{@link IPortletType}s
     */
    public List<IPortletType> getPortletTypes();

* @param name The name to get the type for.}
Expand
JpaPortletTypeDao.java
JpaPortletTypeDao.java
Code Block
java
java
@Repository
public class JpaPortletTypeDao extends BasePortalJpaDao implements IPortletTypeDao {
    private *CriteriaQuery<PortletTypeImpl> @returnfindAllTypesQuery;
The channel type for the@Override
name, null if no typepublic existsvoid forafterPropertiesSet() thethrows fname.Exception {
    * @throws IllegalArgumentException if namethis.findAllTypesQuery is= nullthis.createCriteriaQuery(new Function<CriteriaBuilder, CriteriaQuery<PortletTypeImpl>>() {
  */     public IPortletType getPortletType(String name);  @Override
       /**     public *CriteriaQuery<PortletTypeImpl> @return Aapply(CriteriaBuilder cb) {@link
  List} of all persisted {@link IPortletType}s      */   final CriteriaQuery<PortletTypeImpl> publiccriteriaQuery List<IPortletType>= getPortletTypes(cb.createQuery(PortletTypeImpl.class);
 }
Expand
JpaPortletTypeDao.javaJpaPortletTypeDao.java
Code Block
javajava
@Repository
public class JpaPortletTypeDao extends BaseJpaDao implements IPortletTypeDao {
 private CriteriaQuery<PortletTypeImpl> findAllTypesQuery;
 private CriteriaQuery<PortletTypeImpl> findTypeByNameQuery;
 private ParameterExpression<String> nameParameter;
 private EntityManager entityManager;
 @PersistenceContext(unitName = "uPortalPersistence")
 public final void setEntityManager(EntityManager entityManager) {
 this.entityManager = entityManager;
 }
 
 @Override
 protected EntityManager getEntityManager() {
 return this.entityManager;
 }
 @Override
 public void afterPropertiesSet() throws Exception {
 this.nameParameter = this.createParameterExpression(String.class, "name");
 
 this.findAllTypesQuery = this.createCriteriaQuery(new Function<CriteriaBuilder, CriteriaQuery<PortletTypeImpl>>() {
 @Override
 public CriteriaQuery<PortletTypeImpl> apply(CriteriaBuilder cb) {
 final CriteriaQuery<PortletTypeImpl> criteriaQuery = cb.createQuery(PortletTypeImpl.class);
 criteriaQuery.from(PortletTypeImpl.class);
 return criteriaQuery;
 }
 }               criteriaQuery.from(PortletTypeImpl.class);
                return criteriaQuery;
            }
        });
    }
    
    
    @Override
    @PortalTransactional
    public void deletePortletType(IPortletType type) {
        Validate.notNull(type, "definition can not be null");
     this.findTypeByNameQuery = this.createCriteriaQuery(new Function<CriteriaBuilder,
CriteriaQuery<PortletTypeImpl>>() {  @Override  public CriteriaQuery<PortletTypeImpl> apply(CriteriaBuilder cb)final {IPortletType persistentChanneltype;
final CriteriaQuery<PortletTypeImpl> criteriaQuery = cb.createQuery(PortletTypeImpl.class);     final Root<PortletTypeImpl>EntityManager typeRootentityManager = criteriaQuerythis.fromgetEntityManager(PortletTypeImpl.class);
 criteriaQuery.select(typeRoot);      criteriaQuery.where( if cb.equal(typeRootentityManager.get(PortletTypeImpl_.name), nameParameter)
 );
 
 return criteriaQuery;
 }
 });contains(type)) {
            persistentChanneltype = type;
        }
   @Override  @Transactional  public void deletePortletType(IPortletType type) else {
 Validate.notNull(type, "definition can not be null");    final IPortletType persistentChanneltype; = if (this.entityManager.containsmerge(type));
{  persistentChanneltype = type;  }  else {
}
persistentChanneltype = this.entityManager.merge(type);     }  this.entityManager.remove(persistentChanneltype);
    }
    @Override
   @Transactional @PortalTransactional
    public IPortletType createPortletType(String name, String cpdUri) {
        Validate.notEmpty(name, "name can not be null");
        Validate.notEmpty(cpdUri, "cpdUri can not be null");
        
        final PortletTypeImpl channelType = new PortletTypeImpl(name, cpdUri););
        
        this.entityManagergetEntityManager().persist(channelType);
        
        return channelType;
    }
    @Override
    public IPortletType getPortletType(int id) {
        return this.entityManagergetEntityManager().find(PortletTypeImpl.class, id);
    }
    @OpenEntityManager(unitName = PERSISTENCE_UNIT_NAME)
    @Override
    public IPortletType getPortletType(String name) {
        final TypedQuery<PortletTypeImpl>NaturalIdQuery<PortletTypeImpl> query = this.createCachedQuerycreateNaturalIdQuery(thisPortletTypeImpl.findTypeByNameQueryclass);
        query.setParameterusing(thisPortletTypeImpl_.nameParametername, name);
     final List<PortletTypeImpl> channelTypes =return query.getResultListload();
 return DataAccessUtils.uniqueResult(channelTypes);  }
    @Override
    public List<IPortletType> getPortletTypes() {
        final TypedQuery<PortletTypeImpl> query = this.createCachedQuery(this.findAllTypesQuery);
        final List<PortletTypeImpl> portletTypes = query.getResultList();
        return new ArrayList<IPortletType>(portletTypes);
    }
    @Override
    @Transactional@PortalTransactional
    public IPortletType updatePortletType(IPortletType type) {
        Validate.notNull(type, "type can not be null");
        
        this.entityManagergetEntityManager().persist(type);
        
        return type;
    }
}