Skip to content
Snippets Groups Projects
Verified Commit b9ed3d14 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

DOC: more code docs

parent 8c69cf83
No related branches found
No related tags found
3 merge requests!21Release v0.4.0,!7F fsm,!6Draft: F acm permissions2
......@@ -35,17 +35,17 @@ public class CheckStateTransition extends EntityStateJob {
@Override
protected void run() {
try {
State nextState = getState();
if (nextState != null) {
checkStateValid(nextState);
State newState = getState();
if (newState != null) {
checkStateValid(newState);
}
if (getEntity() instanceof UpdateEntity) {
State fromState = getState(((UpdateEntity) getEntity()).getOriginal());
checkStateTransition(fromState, nextState);
State oldState = getState(((UpdateEntity) getEntity()).getOriginal());
checkStateTransition(oldState, newState);
} else if (getEntity() instanceof DeleteEntity) {
if (nextState != null) checkFinalState(nextState);
if (newState != null) checkFinalState(newState);
} else {
if (nextState != null) checkInitialState(nextState);
if (newState != null) checkInitialState(newState);
}
} catch (Message m) {
getEntity().addError(m);
......@@ -68,31 +68,31 @@ public class CheckStateTransition extends EntityStateJob {
/**
* Check if state is valid and transition is allowed.
*
* @param fromState
* @param toState
* @param oldState
* @param newState
* @throws Message if not
*/
private void checkStateTransition(State fromState, State toState) throws Message {
if (fromState == null && toState == null) {
private void checkStateTransition(State oldState, State newState) throws Message {
if (oldState == null && newState == null) {
return;
} else if (fromState == null && toState != null) {
checkInitialState(toState);
} else if (oldState == null && newState != null) {
checkInitialState(newState);
return;
} else if (toState == null && fromState != null) {
checkFinalState(fromState);
} else if (newState == null && oldState != null) {
checkFinalState(oldState);
return;
}
StateModel stateModel = findMatchingStateModel(fromState, toState);
StateModel stateModel = findMatchingStateModel(oldState, newState);
if (stateModel == null) {
// change from one stateModel to another
checkInitialState(toState);
checkFinalState(fromState);
checkInitialState(newState);
checkFinalState(oldState);
return;
}
for (Transition t : stateModel.getTransitions()) {
if (t.fromStatesInclude(fromState) && t.toStatesInclude(toState)) {
if (t.isFromState(oldState) && t.isToState(newState)) {
// TODO permissions
return;
}
......@@ -101,14 +101,14 @@ public class CheckStateTransition extends EntityStateJob {
}
/**
* @param fromState
* @param toState
* @param oldState
* @param newState
* @return the state model which contains both of the states.
* @throws Message if the state model of one of the states cannot be constructed.
*/
private StateModel findMatchingStateModel(State fromState, State toState) throws Message {
if (fromState.getStateModel().equals(toState.getStateModel())) {
return fromState.getStateModel();
private StateModel findMatchingStateModel(State oldState, State newState) throws Message {
if (oldState.getStateModel().equals(newState.getStateModel())) {
return oldState.getStateModel();
}
return null;
}
......@@ -116,11 +116,11 @@ public class CheckStateTransition extends EntityStateJob {
/**
* Check if the old state is final or if the {@link FORCE_FINAL_STATE} flag is true.
*
* @param fromState
* @param oldState
* @throws Message if the state is not final.
*/
private void checkFinalState(State fromState) throws Message {
if (!fromState.isFinal()) {
private void checkFinalState(State oldState) throws Message {
if (!oldState.isFinal()) {
if ("true".equalsIgnoreCase(getTransaction().getContainer().getFlags().get(FORCE_FINAL_STATE))
|| "true".equalsIgnoreCase(getEntity().getFlag(FORCE_FINAL_STATE))) {
// TODO permissions
......@@ -134,11 +134,11 @@ public class CheckStateTransition extends EntityStateJob {
/**
* Check if the new state is an initial state.
*
* @param toState
* @param newState
* @throws Message if not
*/
private void checkInitialState(State toState) throws Message {
if (!toState.isInitial()) {
private void checkInitialState(State newState) throws Message {
if (!newState.isInitial()) {
throw INITIAL_STATE_NOT_ALLOWED;
}
// TODO permissions
......
......@@ -22,6 +22,7 @@ import org.caosdb.server.entity.wrapper.Property;
import org.caosdb.server.entity.xml.ToElementable;
import org.caosdb.server.jobs.EntityJob;
import org.caosdb.server.query.Query;
import org.caosdb.server.utils.EntityStatus;
import org.jdom2.Element;
/**
......@@ -111,11 +112,19 @@ public abstract class EntityStateJob extends EntityJob {
return null;
}
public boolean fromStatesInclude(State previousState) {
/**
* @param previousState
* @return true iff the previous state is a fromState of this transition.
*/
public boolean isFromState(State previousState) {
return this.fromState.equals(previousState);
}
public boolean toStatesInclude(State nextState) {
/**
* @param nextState
* @return true iff the next state is a toState of this transition.
*/
public boolean isToState(State nextState) {
return this.toState.equals(nextState);
}
......@@ -168,6 +177,9 @@ public abstract class EntityStateJob extends EntityJob {
* <p>Furthermore, States are the start or end point of Transitions which belong to the same
* StateModel. Each State can be part of several transitions at the same time.
*
* <p>Note: The purpose of this should not be confused with {@link EntityStatus} which is purely
* for internal use.
*
* @author Timm Fitschen (t.fitschen@indiscale.com)
*/
public class State implements ToElementable {
......@@ -205,6 +217,7 @@ public abstract class EntityStateJob extends EntityJob {
return 21364234 + this.getStateName().hashCode() + this.getStateModelName().hashCode();
}
/** Serialize this State into XML. */
@Override
public void addToElement(Element ret) {
Element e = new Element(STATE_XML_TAG);
......@@ -232,10 +245,18 @@ public abstract class EntityStateJob extends EntityJob {
return this.stateModel;
}
/**
* @return true iff this state is an initial state of its StateModel.
* @throws Message
*/
public boolean isInitial() throws Message {
return Objects.equals(this, getStateModel().initialState);
}
/**
* @return true iff this state is a final state of its StateModel.
* @throws Message
*/
public boolean isFinal() throws Message {
return Objects.equals(this, getStateModel().finalState);
}
......@@ -337,6 +358,13 @@ public abstract class EntityStateJob extends EntityJob {
return null;
}
/**
* Read out the "Transition" property and create Transition instances.
*
* @param p the transition property
* @return a set of transitions
* @throws Message if the transitions could ne be created.
*/
private Set<Transition> createTransitions(Property p) throws Message {
Set<Transition> result = new HashSet<>();
try {
......@@ -358,6 +386,17 @@ public abstract class EntityStateJob extends EntityJob {
return result;
}
/**
* Collect all possible states from the set of transitions.
*
* <p>This function does not perform any consistency checks. It only add all toStates and
* fromStates of the transitions to the result.
*
* @param transitions
* @param stateModel
* @return set of states.
* @throws Message
*/
private Set<State> getStates(Set<Transition> transitions, StateModel stateModel)
throws Message {
Iterator<Transition> it = transitions.iterator();
......@@ -434,7 +473,6 @@ public abstract class EntityStateJob extends EntityJob {
}
protected EntityInterface getStateRecordType() throws Message {
// TODO this should be cached
return retrieveValidSparseEntityByName(STATE_RECORD_TYPE_NAME);
}
......@@ -517,6 +555,15 @@ public abstract class EntityStateJob extends EntityJob {
return new State(stateName, stateModel);
}
/**
* Create a State instance from the value of the state property.
*
* <p>This method also retrieves the state entity from the back-end.
*
* @param p the entity's state property
* @return The state of the entity
* @throws Message
*/
protected State createState(Property p) throws Message {
try {
p.parseValue();
......@@ -525,6 +572,8 @@ public abstract class EntityStateJob extends EntityJob {
EntityInterface stateModelEntity = findStateModel(stateEntity);
return new State(stateEntity, stateModelEntity);
} catch (Message e) {
throw e;
} catch (Exception e) {
throw COULD_NOT_CONSTRUCT_STATE_MESSAGE;
}
......
......@@ -17,25 +17,40 @@ import org.caosdb.server.utils.EntityStatus;
import org.caosdb.server.utils.Observable;
import org.caosdb.server.utils.Observer;
/**
* Initialize the other entity jobs by converting the client message with type "State" into {@link
* State} instances.
*
* <p>This job also needs to initialize the other jobs even if the current entity version does not
* have a state anymore but the previous version had, because it has to be checked if the stateModel
* allows to leave in this state.
*
* @author Timm Fitschen (t.fitschen@indiscale.com)
*/
@JobAnnotation(
loadAlways = true,
time = JobExecutionTime.INIT,
transaction = WriteTransaction.class)
public class InitEntityState extends EntityStateJob implements Observer {
public class InitEntityStateJobs extends EntityStateJob implements Observer {
@Override
protected void run() {
try {
State newState = null;
{
List<State> states = initStateMessage(getEntity());
if (states.size() > 1) {
throw new Message(
MessageType.Error, "Currently, each entity can only have one state at a time.");
} else if (states.size() == 1) {
newState = states.get(0);
}
State newState = handleNewState();
handleOldState(newState);
}
/**
* Converts the state property of the original entity into a state message (only needed for
* updates).
*
* <p>Also, this method adds an observer to the entity state which handles a corner case where the
* entity changes the state, but no other property changes. In this case Update.deriveUpdate
* cannot detect any changes and will mark this entity as "to-be-skipped". The observer waits for
* that to happen and changes the {@EntityStatus} back to normal.
*
* @param newState
*/
private void handleOldState(State newState) {
try {
if (getEntity() instanceof UpdateEntity) {
List<State> states = initStateMessage(((UpdateEntity) getEntity()).getOriginal());
......@@ -50,10 +65,27 @@ public class InitEntityState extends EntityStateJob implements Observer {
} catch (Message m) {
getEntity().addWarning(STATE_ERROR_IN_ORIGINAL_ENTITY(m));
}
}
/**
* Converts the state property of this entity into a state message.
*
* @return The new state.
*/
private State handleNewState() {
State newState = null;
try {
List<State> states = initStateMessage(getEntity());
if (states.size() > 1) {
throw new Message(
MessageType.Error, "Currently, each entity can only have one state at a time.");
} else if (states.size() == 1) {
newState = states.get(0);
}
} catch (Message m) {
getEntity().addError(m);
return;
}
return newState;
}
private static final Message STATE_ERROR_IN_ORIGINAL_ENTITY(Message m) {
......@@ -61,6 +93,13 @@ public class InitEntityState extends EntityStateJob implements Observer {
MessageType.Warning, "State error in previous entity version\n" + m.getDescription());
}
/**
* Returns a list of states as the are represented as properties or client messages in the entity.
*
* @param entity
* @return list of state instances for the entity.
* @throws Message
*/
private List<State> initStateMessage(EntityInterface entity) throws Message {
List<ClientMessage> stateClientMessages = getStateClientMessages(entity, true);
List<State> result = new ArrayList<>();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment