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);
}
}