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

WIP: FSM

parent e8a64dd5
No related branches found
No related tags found
3 merge requests!21Release v0.4.0,!7F fsm,!6Draft: F acm permissions2
...@@ -41,4 +41,14 @@ public class ClientMessage extends Message { ...@@ -41,4 +41,14 @@ public class ClientMessage extends Message {
public String getProperty(String key) { public String getProperty(String key) {
return properties.get(key); return properties.get(key);
} }
@Override
public String toString() {
return this.type + " - " + this.properties.toString();
}
@Override
public int hashCode() {
return type.hashCode() + this.properties.hashCode();
}
} }
...@@ -225,14 +225,6 @@ public abstract class Job { ...@@ -225,14 +225,6 @@ public abstract class Job {
} }
} }
// @Override
// public boolean notifyObserver(final String e, final Observable o) {
// if (getEntity().getEntityStatus() != EntityStatus.UNQUALIFIED) {
// getTransaction().getSchedule().runJob(this);
// }
// return true;
// }
static HashMap<String, Class<? extends Job>> allClasses = null; static HashMap<String, Class<? extends Job>> allClasses = null;
private static List<Class<? extends Job>> loadAlways; private static List<Class<? extends Job>> loadAlways;
......
...@@ -16,28 +16,41 @@ public class CheckStateTransition extends EntityStateJob { ...@@ -16,28 +16,41 @@ public class CheckStateTransition extends EntityStateJob {
private static final Message TRANSITION_NOT_ALLOWED = private static final Message TRANSITION_NOT_ALLOWED =
new Message(MessageType.Error, "Transition not allowed."); new Message(MessageType.Error, "Transition not allowed.");
private static final Message INITIAL_STATE_NOT_ALLOWED =
new Message(MessageType.Error, "Initial state not allowed.");
private static final Message FINAL_STATE_NOT_ALLOWED =
new Message(MessageType.Error, "Final state not allowed.");
private static final String FORCE_FINAL_STATE = "forceFinalState";
@Override @Override
protected void run() { protected void run() {
try { try {
State nextState = getState();
if (nextState != null) {
checkStateValid(nextState);
}
if (getEntity() instanceof UpdateEntity) { if (getEntity() instanceof UpdateEntity) {
StateMessage toState = getStateMessage(); State fromState = getState(((UpdateEntity) getEntity()).getOriginal());
StateMessage fromState = getStateMessage(((UpdateEntity) getEntity()).getOriginal()); checkStateTransition(fromState, nextState);
checkStateTransition(fromState, toState);
} else if (getEntity() instanceof DeleteEntity) { } else if (getEntity() instanceof DeleteEntity) {
StateMessage finalState = getStateMessage(); if (nextState != null) checkFinalState(nextState);
checkFinalState(finalState);
} else { } else {
StateMessage initialState = getStateMessage(); if (nextState != null) checkInitialState(nextState);
checkInitialState(initialState);
} }
} catch (Message m) { } catch (Message m) {
getEntity().addError(m); getEntity().addError(m);
} }
} }
private void checkStateValid(State state) throws Message {
if (state.isFinal() || state.isInitial() || state.getStateModel().getStates().contains(state)) {
return;
}
throw STATE_NOT_IN_STATE_MODEL;
}
/** Check if state is valid and transition is allowed */ /** Check if state is valid and transition is allowed */
private void checkStateTransition(StateMessage fromState, StateMessage toState) throws Message { private void checkStateTransition(State fromState, State toState) throws Message {
if (fromState == null && toState == null) { if (fromState == null && toState == null) {
return; return;
} else if (fromState == null && toState != null) { } else if (fromState == null && toState != null) {
...@@ -50,32 +63,44 @@ public class CheckStateTransition extends EntityStateJob { ...@@ -50,32 +63,44 @@ public class CheckStateTransition extends EntityStateJob {
StateModel stateModel = findMatchingStateModel(fromState, toState); StateModel stateModel = findMatchingStateModel(fromState, toState);
if (stateModel == null) { if (stateModel == null) {
// change from one stateModel to another
checkInitialState(toState); checkInitialState(toState);
checkFinalState(fromState); checkFinalState(fromState);
return; return;
} }
for (Transition t : stateModel.getTransitions()) { for (Transition t : stateModel.getTransitions()) {
if (t.fromStatesInclude(fromState.getState()) && t.toStatesInclude(toState.getState())) { if (t.fromStatesInclude(fromState) && t.toStatesInclude(toState)) {
// TODO permissions
return; return;
} }
} }
throw TRANSITION_NOT_ALLOWED; throw TRANSITION_NOT_ALLOWED;
} }
private StateModel findMatchingStateModel(StateMessage fromState, StateMessage toState) private StateModel findMatchingStateModel(State fromState, State toState) throws Message {
throws Message {
if (fromState.getStateModel().equals(toState.getStateModel())) { if (fromState.getStateModel().equals(toState.getStateModel())) {
return fromState.getStateModel(); return fromState.getStateModel();
} }
return null; return null;
} }
private void checkFinalState(StateMessage fromState) { private void checkFinalState(State fromState) throws Message {
// TODO Auto-generated method stub if (!fromState.isFinal()) {
if ("true"
.equalsIgnoreCase(getTransaction().getContainer().getFlags().get(FORCE_FINAL_STATE))) {
// TODO permissions
return;
}
throw FINAL_STATE_NOT_ALLOWED;
}
// TODO permissions
} }
private void checkInitialState(StateMessage toState) { private void checkInitialState(State toState) throws Message {
// TODO Auto-generated method stub if (!toState.isInitial()) {
throw INITIAL_STATE_NOT_ALLOWED;
}
// TODO permissions
} }
} }
package org.caosdb.server.jobs.core; package org.caosdb.server.jobs.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.caosdb.server.entity.ClientMessage; import org.caosdb.server.entity.ClientMessage;
import org.caosdb.server.entity.Entity; import org.caosdb.server.entity.Entity;
...@@ -24,10 +26,23 @@ public class InitEntityState extends EntityStateJob implements Observer { ...@@ -24,10 +26,23 @@ public class InitEntityState extends EntityStateJob implements Observer {
@Override @Override
protected void run() { protected void run() {
try { try {
State newState = initStateMessage(getEntity()); 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);
}
}
try { try {
if (getEntity() instanceof UpdateEntity) { if (getEntity() instanceof UpdateEntity) {
State oldState = initStateMessage(((UpdateEntity) getEntity()).getOriginal()); List<State> states = initStateMessage(((UpdateEntity) getEntity()).getOriginal());
State oldState = null;
if (states.size() == 1) {
oldState = states.get(0);
}
if (!Objects.equals(newState, oldState)) { if (!Objects.equals(newState, oldState)) {
getEntity().acceptObserver(this); getEntity().acceptObserver(this);
} }
...@@ -46,26 +61,33 @@ public class InitEntityState extends EntityStateJob implements Observer { ...@@ -46,26 +61,33 @@ 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());
} }
private State initStateMessage(EntityInterface entity) throws Message { private List<State> initStateMessage(EntityInterface entity) throws Message {
ClientMessage stateClientMessage = getStateClientMessage(entity, true); List<ClientMessage> stateClientMessages = getStateClientMessages(entity, true);
if (stateClientMessage != null) { List<State> result = new ArrayList<>();
StateMessage stateMessage = createStateMessage(stateClientMessage); if (stateClientMessages != null) {
for (ClientMessage s : stateClientMessages) {
State stateMessage = createState(s);
entity.addMessage(stateMessage); entity.addMessage(stateMessage);
return stateMessage.getState(); result.add(stateMessage);
} }
Property stateProperty = getStateProperty(entity, true); }
if (stateProperty != null) { List<Property> stateProperties = getStateProperties(entity, true);
StateMessage stateMessage = createStateMessage(stateProperty); if (stateProperties != null) {
for (Property p : stateProperties) {
State stateMessage = createState(p);
entity.addMessage(stateMessage); entity.addMessage(stateMessage);
return stateMessage.getState(); result.add(stateMessage);
}
} }
return null; return result;
} }
@Override @Override
public boolean notifyObserver(String e, Observable o) { public boolean notifyObserver(String e, Observable o) {
if (e == Entity.ENTITY_STATUS_CHANGED_EVENT) { if (e == Entity.ENTITY_STATUS_CHANGED_EVENT) {
if (o == getEntity() && getEntity().getEntityStatus() == EntityStatus.VALID) { if (o == getEntity() && getEntity().getEntityStatus() == EntityStatus.VALID) {
// The Update.deriveUpdate method didn't recognize that the state is changing and set the
// entity to "VALID"
getEntity().setEntityStatus(EntityStatus.QUALIFIED); getEntity().setEntityStatus(EntityStatus.QUALIFIED);
return false; return false;
} }
......
package org.caosdb.server.jobs.core; package org.caosdb.server.jobs.core;
import java.util.List;
import org.caosdb.server.entity.Message; import org.caosdb.server.entity.Message;
import org.caosdb.server.entity.wrapper.Property; import org.caosdb.server.entity.wrapper.Property;
import org.caosdb.server.jobs.JobAnnotation; import org.caosdb.server.jobs.JobAnnotation;
import org.caosdb.server.jobs.JobExecutionTime; import org.caosdb.server.jobs.JobExecutionTime;
import org.caosdb.server.transaction.Retrieve;
@JobAnnotation(loadAlways = true, time = JobExecutionTime.POST_TRANSACTION) @JobAnnotation(loadAlways = true, time = JobExecutionTime.POST_TRANSACTION)
public class WriteStateMessage extends EntityStateJob { public class MakeStateMessage extends EntityStateJob {
@Override @Override
protected void run() { protected void run() {
try { try {
Property stateProperty = getStateProperty(true); List<Property> stateProperties = getStateProperties(true);
if (stateProperty != null) {
StateMessage stateMessage = createStateMessage(stateProperty); // only add the State during Retrieve. In all other cases, the State is already present.
if (stateProperties != null && getTransaction() instanceof Retrieve) {
for (Property s : stateProperties) {
State stateMessage = createState(s);
getEntity().addMessage(stateMessage); getEntity().addMessage(stateMessage);
} }
}
} catch (Message e) { } catch (Message e) {
getEntity().addError(e); getEntity().addError(e);
} }
......
package org.caosdb.server.jobs.core; package org.caosdb.server.jobs.core;
import org.caosdb.server.entity.Message;
import org.caosdb.server.jobs.JobAnnotation; import org.caosdb.server.jobs.JobAnnotation;
import org.caosdb.server.jobs.JobExecutionTime; import org.caosdb.server.jobs.JobExecutionTime;
import org.caosdb.server.transaction.WriteTransaction; import org.caosdb.server.transaction.WriteTransaction;
...@@ -8,15 +9,21 @@ import org.caosdb.server.transaction.WriteTransaction; ...@@ -8,15 +9,21 @@ import org.caosdb.server.transaction.WriteTransaction;
loadAlways = true, loadAlways = true,
transaction = WriteTransaction.class, transaction = WriteTransaction.class,
time = JobExecutionTime.PRE_TRANSACTION) time = JobExecutionTime.PRE_TRANSACTION)
public class ParseStateMessage extends EntityStateJob { public class MakeStateProperty extends EntityStateJob {
@Override @Override
protected void run() { protected void run() {
StateMessage s = getStateMessage(true); State s = getState();
if (s != null) addStateProperty(s); if (s != null) {
try {
addStateProperty(s);
} catch (Message e) {
getEntity().addError(e);
}
}
} }
private void addStateProperty(StateMessage stateEntity) { private void addStateProperty(State stateEntity) throws Message {
getEntity().addProperty(stateEntity.createStateProperty()); getEntity().addProperty(stateEntity.createStateProperty());
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment