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 { ...@@ -35,17 +35,17 @@ public class CheckStateTransition extends EntityStateJob {
@Override @Override
protected void run() { protected void run() {
try { try {
State nextState = getState(); State newState = getState();
if (nextState != null) { if (newState != null) {
checkStateValid(nextState); checkStateValid(newState);
} }
if (getEntity() instanceof UpdateEntity) { if (getEntity() instanceof UpdateEntity) {
State fromState = getState(((UpdateEntity) getEntity()).getOriginal()); State oldState = getState(((UpdateEntity) getEntity()).getOriginal());
checkStateTransition(fromState, nextState); checkStateTransition(oldState, newState);
} else if (getEntity() instanceof DeleteEntity) { } else if (getEntity() instanceof DeleteEntity) {
if (nextState != null) checkFinalState(nextState); if (newState != null) checkFinalState(newState);
} else { } else {
if (nextState != null) checkInitialState(nextState); if (newState != null) checkInitialState(newState);
} }
} catch (Message m) { } catch (Message m) {
getEntity().addError(m); getEntity().addError(m);
...@@ -68,31 +68,31 @@ public class CheckStateTransition extends EntityStateJob { ...@@ -68,31 +68,31 @@ public class CheckStateTransition extends EntityStateJob {
/** /**
* Check if state is valid and transition is allowed. * Check if state is valid and transition is allowed.
* *
* @param fromState * @param oldState
* @param toState * @param newState
* @throws Message if not * @throws Message if not
*/ */
private void checkStateTransition(State fromState, State toState) throws Message { private void checkStateTransition(State oldState, State newState) throws Message {
if (fromState == null && toState == null) { if (oldState == null && newState == null) {
return; return;
} else if (fromState == null && toState != null) { } else if (oldState == null && newState != null) {
checkInitialState(toState); checkInitialState(newState);
return; return;
} else if (toState == null && fromState != null) { } else if (newState == null && oldState != null) {
checkFinalState(fromState); checkFinalState(oldState);
return; return;
} }
StateModel stateModel = findMatchingStateModel(fromState, toState); StateModel stateModel = findMatchingStateModel(oldState, newState);
if (stateModel == null) { if (stateModel == null) {
// change from one stateModel to another // change from one stateModel to another
checkInitialState(toState); checkInitialState(newState);
checkFinalState(fromState); checkFinalState(oldState);
return; return;
} }
for (Transition t : stateModel.getTransitions()) { for (Transition t : stateModel.getTransitions()) {
if (t.fromStatesInclude(fromState) && t.toStatesInclude(toState)) { if (t.isFromState(oldState) && t.isToState(newState)) {
// TODO permissions // TODO permissions
return; return;
} }
...@@ -101,14 +101,14 @@ public class CheckStateTransition extends EntityStateJob { ...@@ -101,14 +101,14 @@ public class CheckStateTransition extends EntityStateJob {
} }
/** /**
* @param fromState * @param oldState
* @param toState * @param newState
* @return the state model which contains both of the states. * @return the state model which contains both of the states.
* @throws Message if the state model of one of the states cannot be constructed. * @throws Message if the state model of one of the states cannot be constructed.
*/ */
private StateModel findMatchingStateModel(State fromState, State toState) throws Message { private StateModel findMatchingStateModel(State oldState, State newState) throws Message {
if (fromState.getStateModel().equals(toState.getStateModel())) { if (oldState.getStateModel().equals(newState.getStateModel())) {
return fromState.getStateModel(); return oldState.getStateModel();
} }
return null; return null;
} }
...@@ -116,11 +116,11 @@ public class CheckStateTransition extends EntityStateJob { ...@@ -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. * 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. * @throws Message if the state is not final.
*/ */
private void checkFinalState(State fromState) throws Message { private void checkFinalState(State oldState) throws Message {
if (!fromState.isFinal()) { if (!oldState.isFinal()) {
if ("true".equalsIgnoreCase(getTransaction().getContainer().getFlags().get(FORCE_FINAL_STATE)) if ("true".equalsIgnoreCase(getTransaction().getContainer().getFlags().get(FORCE_FINAL_STATE))
|| "true".equalsIgnoreCase(getEntity().getFlag(FORCE_FINAL_STATE))) { || "true".equalsIgnoreCase(getEntity().getFlag(FORCE_FINAL_STATE))) {
// TODO permissions // TODO permissions
...@@ -134,11 +134,11 @@ public class CheckStateTransition extends EntityStateJob { ...@@ -134,11 +134,11 @@ public class CheckStateTransition extends EntityStateJob {
/** /**
* Check if the new state is an initial state. * Check if the new state is an initial state.
* *
* @param toState * @param newState
* @throws Message if not * @throws Message if not
*/ */
private void checkInitialState(State toState) throws Message { private void checkInitialState(State newState) throws Message {
if (!toState.isInitial()) { if (!newState.isInitial()) {
throw INITIAL_STATE_NOT_ALLOWED; throw INITIAL_STATE_NOT_ALLOWED;
} }
// TODO permissions // TODO permissions
......
...@@ -22,6 +22,7 @@ import org.caosdb.server.entity.wrapper.Property; ...@@ -22,6 +22,7 @@ import org.caosdb.server.entity.wrapper.Property;
import org.caosdb.server.entity.xml.ToElementable; import org.caosdb.server.entity.xml.ToElementable;
import org.caosdb.server.jobs.EntityJob; import org.caosdb.server.jobs.EntityJob;
import org.caosdb.server.query.Query; import org.caosdb.server.query.Query;
import org.caosdb.server.utils.EntityStatus;
import org.jdom2.Element; import org.jdom2.Element;
/** /**
...@@ -111,11 +112,19 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -111,11 +112,19 @@ public abstract class EntityStateJob extends EntityJob {
return null; 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); 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); return this.toState.equals(nextState);
} }
...@@ -168,6 +177,9 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -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 * <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. * 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) * @author Timm Fitschen (t.fitschen@indiscale.com)
*/ */
public class State implements ToElementable { public class State implements ToElementable {
...@@ -205,6 +217,7 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -205,6 +217,7 @@ public abstract class EntityStateJob extends EntityJob {
return 21364234 + this.getStateName().hashCode() + this.getStateModelName().hashCode(); return 21364234 + this.getStateName().hashCode() + this.getStateModelName().hashCode();
} }
/** Serialize this State into XML. */
@Override @Override
public void addToElement(Element ret) { public void addToElement(Element ret) {
Element e = new Element(STATE_XML_TAG); Element e = new Element(STATE_XML_TAG);
...@@ -232,10 +245,18 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -232,10 +245,18 @@ public abstract class EntityStateJob extends EntityJob {
return this.stateModel; return this.stateModel;
} }
/**
* @return true iff this state is an initial state of its StateModel.
* @throws Message
*/
public boolean isInitial() throws Message { public boolean isInitial() throws Message {
return Objects.equals(this, getStateModel().initialState); 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 { public boolean isFinal() throws Message {
return Objects.equals(this, getStateModel().finalState); return Objects.equals(this, getStateModel().finalState);
} }
...@@ -337,6 +358,13 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -337,6 +358,13 @@ public abstract class EntityStateJob extends EntityJob {
return null; 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 { private Set<Transition> createTransitions(Property p) throws Message {
Set<Transition> result = new HashSet<>(); Set<Transition> result = new HashSet<>();
try { try {
...@@ -358,6 +386,17 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -358,6 +386,17 @@ public abstract class EntityStateJob extends EntityJob {
return result; 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) private Set<State> getStates(Set<Transition> transitions, StateModel stateModel)
throws Message { throws Message {
Iterator<Transition> it = transitions.iterator(); Iterator<Transition> it = transitions.iterator();
...@@ -434,7 +473,6 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -434,7 +473,6 @@ public abstract class EntityStateJob extends EntityJob {
} }
protected EntityInterface getStateRecordType() throws Message { protected EntityInterface getStateRecordType() throws Message {
// TODO this should be cached
return retrieveValidSparseEntityByName(STATE_RECORD_TYPE_NAME); return retrieveValidSparseEntityByName(STATE_RECORD_TYPE_NAME);
} }
...@@ -517,6 +555,15 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -517,6 +555,15 @@ public abstract class EntityStateJob extends EntityJob {
return new State(stateName, stateModel); 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 { protected State createState(Property p) throws Message {
try { try {
p.parseValue(); p.parseValue();
...@@ -525,6 +572,8 @@ public abstract class EntityStateJob extends EntityJob { ...@@ -525,6 +572,8 @@ public abstract class EntityStateJob extends EntityJob {
EntityInterface stateModelEntity = findStateModel(stateEntity); EntityInterface stateModelEntity = findStateModel(stateEntity);
return new State(stateEntity, stateModelEntity); return new State(stateEntity, stateModelEntity);
} catch (Message e) {
throw e;
} catch (Exception e) { } catch (Exception e) {
throw COULD_NOT_CONSTRUCT_STATE_MESSAGE; throw COULD_NOT_CONSTRUCT_STATE_MESSAGE;
} }
......
...@@ -17,43 +17,75 @@ import org.caosdb.server.utils.EntityStatus; ...@@ -17,43 +17,75 @@ import org.caosdb.server.utils.EntityStatus;
import org.caosdb.server.utils.Observable; import org.caosdb.server.utils.Observable;
import org.caosdb.server.utils.Observer; 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( @JobAnnotation(
loadAlways = true, loadAlways = true,
time = JobExecutionTime.INIT, time = JobExecutionTime.INIT,
transaction = WriteTransaction.class) transaction = WriteTransaction.class)
public class InitEntityState extends EntityStateJob implements Observer { public class InitEntityStateJobs extends EntityStateJob implements Observer {
@Override @Override
protected void run() { protected void run() {
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 { try {
State newState = null; if (getEntity() instanceof UpdateEntity) {
{ List<State> states = initStateMessage(((UpdateEntity) getEntity()).getOriginal());
List<State> states = initStateMessage(getEntity()); State oldState = null;
if (states.size() > 1) { if (states.size() == 1) {
throw new Message( oldState = states.get(0);
MessageType.Error, "Currently, each entity can only have one state at a time.");
} else if (states.size() == 1) {
newState = states.get(0);
} }
} if (!Objects.equals(newState, oldState)) {
try { getEntity().acceptObserver(this);
if (getEntity() instanceof UpdateEntity) {
List<State> states = initStateMessage(((UpdateEntity) getEntity()).getOriginal());
State oldState = null;
if (states.size() == 1) {
oldState = states.get(0);
}
if (!Objects.equals(newState, oldState)) {
getEntity().acceptObserver(this);
}
} }
} catch (Message m) { }
getEntity().addWarning(STATE_ERROR_IN_ORIGINAL_ENTITY(m)); } 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) { } catch (Message m) {
getEntity().addError(m); getEntity().addError(m);
return;
} }
return newState;
} }
private static final Message STATE_ERROR_IN_ORIGINAL_ENTITY(Message m) { private static final Message STATE_ERROR_IN_ORIGINAL_ENTITY(Message m) {
...@@ -61,6 +93,13 @@ public class InitEntityState extends EntityStateJob implements Observer { ...@@ -61,6 +93,13 @@ public class InitEntityState extends EntityStateJob implements Observer {
MessageType.Warning, "State error in previous entity version\n" + m.getDescription()); 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 { private List<State> initStateMessage(EntityInterface entity) throws Message {
List<ClientMessage> stateClientMessages = getStateClientMessages(entity, true); List<ClientMessage> stateClientMessages = getStateClientMessages(entity, true);
List<State> result = new ArrayList<>(); 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