Here are full listings of the entity interface and implementation example used in this chapter:
package curam.mypackage; import com.google.inject.ImplementedBy; import curam.mypackage.codetable.impl.MYLIFECYCLEENTITYSTATEEntry; import curam.util.exception.InformationalException; import curam.util.persistence.Insertable; import curam.util.persistence.OptimisticLockModifiable; import curam.util.persistence.StandardEntity; import curam.util.persistence.helper.Lifecycle; import curam.util.type.Date; import curam.util.type.DateRanged; /** * Description of my state-machine entity. */ @ImplementedBy(MyLifecycleEntityImpl.class) public interface MyLifecycleEntity extends StandardEntity, DateRanged, Lifecycle<MYLIFECYCLEENTITYSTATEEntry>, Insertable, OptimisticLockModifiable { /** * Suspends business pending investigation. * * Transitions the state to * {@linkplain MYLIFECYCLEENTITYSTATEEntry#SUSPENDED}, if it is * valid to suspend. * * @param reason * the reason for suspension * * @param versionNo * the version number as previously retrieved * * @throws InformationalException * if the entity is not in a valid state to transition * to * {@linkplain MYLIFECYCLEENTITYSTATEEntry#SUSPENDED}, * or if any other validation errors are found */ public void suspend(final String reason, final int versionNo) throws InformationalException; /** * Resumes business following a suspension investigation resulting * in acquittal. * * Transitions the state to * {@linkplain MYLIFECYCLEENTITYSTATEEntry#OPEN}, if it is valid * to resume business. * * @param versionNo * the version number as previously retrieved * * @throws InformationalException * if the entity is not in a valid state to transition * to {@linkplain MYLIFECYCLEENTITYSTATEEntry#OPEN}, or * if any other validation errors are found */ public void resume(final int versionNo) throws InformationalException; /** * Ceases business with the agency. * * Transitions the state to * {@linkplain MYLIFECYCLEENTITYSTATEEntry#CLOSED}, if it is * valid to cease conducting business. * * @param endDate * the date on which business with the agency was ceased * * @param versionNo * the version number as previously retrieved * * @throws InformationalException * if the entity is not in a valid state to transition * to {@linkplain MYLIFECYCLEENTITYSTATEEntry#CLOSED}, * or if any other validation errors are found */ public void close(final Date endDate, final int versionNo) throws InformationalException; }
package curam.mypackage; import java.util.HashMap; import java.util.Map; import curam.mypackage.codetable.MYLIFECYCLEENTITYSTATEEntry; import curam.mypackage.struct.MyLifecycleEntityDtls; import curam.util.exception.InformationalException; import curam.util.exception.UnimplementedException; import curam.util.persistence.ValidationHelper; import curam.util.persistence.helper.CodetableState; import curam.util.persistence.helper.SingleTableEntityImpl; import curam.util.persistence.helper.State; import curam.util.persistence.helper.Transition; import curam.util.type.Date; import curam.util.type.DateRange; /** * Standard implementation of {@linkplain MyLifecycleEntity}. */ public class MyLifecycleEntityImpl extends SingleTableEntityImpl<MyLifecycleEntityDtls> implements MyLifecycleEntity { protected MyLifecycleEntityImpl() { /* * Protected no-arg constructor for use only by Guice */ } /* * Persistence methods */ /** * {@inheritDoc} */ @Override public void modify(Integer versionNo) throws InformationalException { if (!getState().isModifyAllowed()) { ValidationHelper .addValidationError( "You are not allowed to modify this record when it is in this state" ); } super.modify(versionNo); } /* * Getters */ /** * {@inheritDoc} */ public MYLIFECYCLEENTITYSTATEEntry getLifecycleState() { return MYLIFECYCLEENTITYSTATEEntry.get(getDtls().state); } public DateRange getDateRange() { throw new UnimplementedException(); } /* * Setters */ private void setEndDate(final Date value) { throw new UnimplementedException(); } private void setSuspensionReason(final String value) { throw new UnimplementedException(); } void sendClosureEmail() { throw new UnimplementedException(); } /* * State transitions */ /** * {@inheritDoc} */ public void close(Date endDate, int versionNo) throws InformationalException { // store the date of closure setEndDate(endDate); // transition to "closed" transitionTo(CLOSED, versionNo); } /** * {@inheritDoc} */ public void resume(int versionNo) throws InformationalException { // blank the suspension reason setSuspensionReason(null); // transition to "open" transitionTo(OPEN, versionNo); } /** * {@inheritDoc} */ public void suspend(String reason, int versionNo) throws InformationalException { // store the suspension reason setSuspensionReason(reason); // transition to "suspended" transitionTo(SUSPENDED, versionNo); } /* * State Transitions */ /** * A map of the states for this entity */ private final Map<MYLIFECYCLEENTITYSTATEEntry, State<MYLIFECYCLEENTITYSTATEEntry>> states = new HashMap<MYLIFECYCLEENTITYSTATEEntry, State<MYLIFECYCLEENTITYSTATEEntry>>(); /** * @return The State object representing the current state of this * entity */ private State<MYLIFECYCLEENTITYSTATEEntry> getState() { return states.get(getLifecycleState()); } /** * Sets the state codetable code field from the State object * supplied. * * @param value * the State supplied */ private void setState( final State<MYLIFECYCLEENTITYSTATEEntry> state) { getDtls().state = state.getValue().getCode(); } /** * Transitions this entity to the new state specified. * * @param newState * the state to transition to * @param versionNo * the version number of this entity as previously * retrieved * @throws InformationalException * if validation errors occur during the transition */ private void transitionTo( final State<MYLIFECYCLEENTITYSTATEEntry> newState, final Integer versionNo) throws InformationalException { // get the current state of this entity final State<MYLIFECYCLEENTITYSTATEEntry> oldState = getState(); // set the field which stores the state value setState(newState); // validate the state transition oldState.transitionTo(newState); // update the database, bypassing any pre-modify validation in // this class super.modify(versionNo); } /** * Actively conducting business with the agency. */ private final State<MYLIFECYCLEENTITYSTATEEntry> OPEN = new CodetableState<MYLIFECYCLEENTITYSTATEEntry>(states, MYLIFECYCLEENTITYSTATEEntry.OPEN, true, true) { }; /** * Business has been suspended pending investigation. */ private final State<MYLIFECYCLEENTITYSTATEEntry> SUSPENDED = new CodetableState<MYLIFECYCLEENTITYSTATEEntry>(states, MYLIFECYCLEENTITYSTATEEntry.SUSPENDED, true, false) { }; /** * No longer conducting business with the agency. */ private final State<MYLIFECYCLEENTITYSTATEEntry> CLOSED = new CodetableState<MYLIFECYCLEENTITYSTATEEntry>(states, MYLIFECYCLEENTITYSTATEEntry.CLOSED, false, false) { @Override protected void onEnter() { // whenever the entity is closed, send an email sendClosureEmail(); } }; private final Transition<MYLIFECYCLEENTITYSTATEEntry> OPEN2CLOSED = new Transition<MYLIFECYCLEENTITYSTATEEntry>(OPEN, CLOSED) { }; private final Transition<MYLIFECYCLEENTITYSTATEEntry> OPEN2SUSPENDED = new Transition<MYLIFECYCLEENTITYSTATEEntry>(OPEN, SUSPENDED) { }; private final Transition<MYLIFECYCLEENTITYSTATEEntry> SUSPENDED2OPEN = new Transition<MYLIFECYCLEENTITYSTATEEntry>(SUSPENDED, OPEN) { }; private final Transition<MYLIFECYCLEENTITYSTATEEntry> SUSPENDED2CLOSED = new Transition<MYLIFECYCLEENTITYSTATEEntry>(SUSPENDED, CLOSED) { }; /* * Validation */ public void mandatoryFieldValidation() { throw new UnimplementedException(); } public void crossFieldValidation() { throw new UnimplementedException(); } public void crossEntityValidation() { throw new UnimplementedException(); } /** * Defaults the state to * {@linkplain MYLIFECYCLEENTITYSTATEEntry#OPEN}. */ public void setNewInstanceDefaults() { setState(OPEN); } }