package org.fluttercode.datavalve.entity; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import org.fluttercode.datavalve.EntityHome; public abstract class AbstractEntityHome<T> implements EntityHome<T> { private T entity; private Object id; private boolean managed; private Class<T> entityClass; public T getEntity() { if (entity == null) { entity = fetchEntity(); } return entity; } /** * Fetches the entity by loading a new one or creating one * * @return Fetched entity */ private T fetchEntity() { if (isIdSet()) { return internalLoadEntity(); } else { return internalCreateEntity(); } } public void setEntity(T entity) { this.entity = entity; } public Object getId() { return id; } public void setId(Object id) { this.id = id; } /** * Internal method used to create the entity. Do not override, override the * {@link AbstractEntityHome#doCreateEntity()} method to implement entity * creation. Override the <code>doPreCreateEntity</code> and * <code>doPostCreateEntity</code> methods to add additional processing when * creating an entity. * * @return The loaded entity */ protected T internalCreateEntity() { doPreCreateEntity(); T result = doCreateEntity(); managed = false; doPostCreateEntity(result); return result; } /** * Internal method used to load the entity. Do not override, override the * {@link AbstractEntityHome#doLoadEntity()} method to implement entity * loading. Override the <code>doPreLoadEntity</code> and * <code>doPostLoadEntity</code> methods to add additional processing when * loading an entity. * * @return The loaded entity */ protected T internalLoadEntity() { doPreLoadEntity(); T result = doLoadEntity(); managed = true; doPostLoadEntity(result); return result; } /** * Override this method to provide additional processing prior to creating * an entity. */ protected void doPreCreateEntity() { // do nothing } /** * Override this method to construct the object * * @return Newly created instance of T */ protected T doCreateEntity() { Class<T> type = getEntityClass(); T entity = null; try { entity = type.newInstance(); } catch (Exception e) { e.printStackTrace(); } return entity; } /** * Override this method to provide additional handling post to the newly * created entity * * @param entity * The newly created entity */ protected void doPostCreateEntity(T entity) { // do nothing } /** * Override to add additional processing prior to loading an entity */ protected void doPreLoadEntity() { // do nothing } /** * Override to implement entity loading for the specific data source * * @return The loaded entity */ protected abstract T doLoadEntity(); /** * Override this method to add additional handling to set up the loaded * entity. * * @param entity * The entity loaded */ protected void doPostLoadEntity(T entity) { // do nothing } public void insert() { doPreInsert(); doInsert(); managed = true; internalPostInsert(); doPostInsert(); } /** * Override to add addition handling once the entity has been inserted */ protected void doPostInsert() { // do nothing } /** * Used internally for post-insert processing, to add your own addition * handling, override the {@link AbstractEntityHome#doPostInsert()} method. */ protected void internalPostInsert() { // do nothing } /** * Perform the actual insert operation */ protected abstract void doInsert(); /** * Override this method to add additional pre insert handling on the entity. */ protected void doPreInsert() { // Do Nothing } public void cancel() { if (isManaged()) { doPreCancel(); doCancel(); internalPostCancel(); doPostCancel(); } else { // since this isn't managed, just create a new one setEntity(internalCreateEntity()); } } /** * Override to provide additional handling prior to cancelling changes to * the entity. */ protected void doPreCancel() { // do nothing } /** * Implements the actual entity change cancellation */ protected abstract void doCancel(); /** * Internal method to provide additional post cancellation handling. */ protected void internalPostCancel() { // do nothing } /** * Override this method to provide additional handling post cancellation */ protected void doPostCancel() { // do nothing } public void update() { doPreUpdate(); doUpdate(); internalPostUpdate(); doPostUpdate(); } /** * Override to provide additional handling prior to updating the entity. */ protected void doPreUpdate() { // do nothing } /** * Perform the actual update on the entity instance */ protected void doUpdate() { // do nothing } /** * Internal method to provide additional post update processing. Do not * override on the client, override the * {@link AbstractEntityHome#doPostUpdate()} method instead to add your own * post update handling. */ protected void internalPostUpdate() { // do nothing } /** * Override to provide additional handling after updating the entity. */ protected void doPostUpdate() { // do nothing } public boolean isIdSet() { return id != null; } public boolean isManaged() { return managed; } public Class<T> getEntityClass() { if (entityClass == null) { ParameterizedType parameterizedType = (ParameterizedType) getClass() .getGenericSuperclass(); Object value = parameterizedType.getActualTypeArguments()[0]; if (value instanceof Class) { return (Class<T>) value; } else { throw new IllegalArgumentException( "Unable to extract generic type information, please set manually using setEntityClass()"); } } return entityClass; } }