Refactored storing logic of triggers and actions. issue 6

This commit is contained in:
Ziver Koc 2017-01-30 17:16:56 +01:00
parent 8d9354d845
commit a1cb12f6ce
12 changed files with 227 additions and 201 deletions

View file

@ -94,7 +94,7 @@
<target name="build-dependencies">
<mkdir dir="${buildDir}" />
<get src="http://ci.koc.se/jenkins/job/Zutil/119/artifact/build/release/Zutil.jar"
<get src="http://ci.koc.se/jenkins/job/Zutil/131/artifact/build/release/Zutil.jar"
dest="${libDir}" verbose="true" usetimestamp="true"/>
</target>

View file

@ -98,6 +98,53 @@
<!-------------------------------- MODALS -------------------------------->
<script>
$(function(){
initDynamicModalForm("trigger");
initDynamicModalForm("action");
});
var dynamicConf = {};
function initDynamicModalForm(name){
// read in all configurations into global variable (to skip naming issues)
dynamicConf[name] = [];
$("#"+name+"-data-conf-template div").each(function(){
dynamicConf[name][$(this).attr("id")] = $(this).html();
});
// Update dynamic inputs
$("#"+name+"Modal select[name=type]").change(function(){
$("#"+name+"Modal #"+name+"-data-conf").html(dynamicConf[name][$(this).val()]);
});
// click event
$("#"+name+"Modal").on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
var modal = $(this);
modal.find("input[type=text]").val(""); // Reset all inputs
if(button.data("id") >= 0){ // edit
modal.find("input[name=action]").val("modify_"+name);
}
else{ // create
modal.find("input[name=action]").val("create_"+name);
modal.find("input[name=id]").val(-1);
}
// set dynamic form data
modal.find("select[name=type]").val(button.data("type"));
modal.find("select[name=type]").change(); // Update dynamic inputs
$.each(button.attr(), function(fieldName, value) {
if(fieldName.startsWith("data-")) {
fieldName = fieldName.substring(5);
console.log(fieldName, value);
// case insensitive search
modal.find("input").filter(function() {
return this.name.toLowerCase() == fieldName;
}).val(value);
}
});
});
}
</script>
<div class="modal fade" id="triggerModal" tabindex="-1">
<div class="modal-dialog">
@ -119,6 +166,10 @@
</select>
</div>
<hr>
<div id="trigger-data-conf">
<!-- Dynamic form -->
</div>
</div>
<div class="modal-footer">
<button type="reset" class="btn btn-default" data-dismiss="modal">Cancel</button>
@ -150,6 +201,10 @@
</select>
</div>
<hr>
<div id="action-data-conf">
<!-- Dynamic form -->
</div>
</div>
<div class="modal-footer">
<button type="reset" class="btn btn-default" data-dismiss="modal">Cancel</button>
@ -158,4 +213,45 @@
</form>
</div>
</div>
</div>
<div id="trigger-data-conf-template" class="hidden">
{{#triggerConf}}
<div id="{{.clazz.getName()}}">
{{#.params}}
<div class="form-group">
<label class="control-label">{{.getNiceName()}}:</label>
{{#.isTypeString()}}<input type="text" class="form-control" name="{{.getName()}}">{{/#.isTypeString()}}
{{#.isTypeInt()}}<input type="number" class="form-control" name="{{.getName()}}">{{/#.isTypeInt()}}
{{#.isTypeBoolean()}}<input type="checkbox" name="{{.getName()}}">{{/#.isTypeBoolean()}}
{{#.isTypeEnum()}}
<select class="form-control" name="{{.getName()}}">
{{#.getPossibleValues()}}<option>{{.}}</option>{{/.getPossibleValues()}}
</select>
{{/#.isTypeEnum()}}
</div>
{{/.params}}
</div>
{{/triggerConf}}
</div>
<div id="sensor-data-conf-template" class="hidden">
{{#actionConf}}
<div id="{{.clazz.getName()}}">
{{#.params}}
<div class="form-group">
<label class="control-label">{{.getNiceName()}}:</label>
{{#.isTypeString()}}<input type="text" class="form-control" name="{{.getName()}}">{{/#.isTypeString()}}
{{#.isTypeInt()}}<input type="number" class="form-control" name="{{.getName()}}">{{/#.isTypeInt()}}
{{#.isTypeBoolean()}}<input type="checkbox" name="{{.getName()}}">{{/#.isTypeBoolean()}}
{{#.isTypeEnum()}}
<select class="form-control" name="{{.getName()}}">
{{#.getPossibleValues()}}<option>{{.}}</option>{{/.getPossibleValues()}}
</select>
{{/#.isTypeEnum()}}
</div>
{{/.params}}
</div>
{{/actionConf}}
</div>

View file

@ -1,49 +1,14 @@
package se.hal.intf;
import se.hal.struct.TriggerFlow;
import se.hal.struct.dso.ActionDSO;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import java.sql.SQLException;
import java.util.List;
/**
* Defines a action that will be executed
*/
public abstract class HalAction{
private ActionDSO dso;
public static HalAction getAction(DBConnection db, long id) throws SQLException {
ActionDSO dso = DBBean.load(db, ActionDSO.class, id);
dso.getObject().dso = dso;
return dso.getObject();
}
public static List<HalAction> getActions(DBConnection db, TriggerFlow flow) {
// TODO:
return null;
}
public Long getId(){
return (dso!=null ? dso.getId() : null);
}
public void save(DBConnection db) throws SQLException {
if (dso == null)
dso = new ActionDSO();
dso.setObject(this);
dso.save(db);
}
public void delete(DBConnection db) throws SQLException {
dso.delete(db);
}
public interface HalAction{
/**
* Executes this specific action
*/
public abstract void execute();
void execute();
}

View file

@ -1,58 +1,22 @@
package se.hal.intf;
import se.hal.struct.TriggerFlow;
import se.hal.struct.dso.TriggerDSO;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import java.sql.SQLException;
import java.util.List;
/**
* A class that declares a trigger/condition that
* A interface that declares a trigger/condition that
* needs to be validated before an action can be run
*/
public abstract class HalTrigger{
private TriggerDSO dso;
public static HalTrigger getTrigger(DBConnection db, long id) throws SQLException {
TriggerDSO dso = DBBean.load(db, TriggerDSO.class, id);
dso.getObject().dso = dso;
return dso.getObject();
}
public static List<HalTrigger> getTriggers(DBConnection db, TriggerFlow flow) {
return null;
}
public Long getId(){
return (dso!=null ? dso.getId() : null);
}
public void save(DBConnection db) throws SQLException {
if (dso == null)
dso = new TriggerDSO();
dso.setObject(this);
dso.save(db);
}
public void delete(DBConnection db) throws SQLException {
dso.delete(db);
}
public interface HalTrigger{
/**
* Evaluates if this trigger has passed. If the trigger is
* true then this method will return true until the {@link #reset()}
* method is called.
*/
public abstract boolean evaluate();
boolean evaluate();
/**
* Reset the evaluation to false.
*/
public abstract void reset();
void reset();
}

View file

@ -5,7 +5,9 @@ import se.hal.TriggerManager;
import se.hal.intf.HalAction;
import se.hal.intf.HalHttpPage;
import se.hal.intf.HalTrigger;
import se.hal.struct.Action;
import se.hal.struct.ClassConfigurationData;
import se.hal.struct.Trigger;
import se.hal.struct.TriggerFlow;
import zutil.db.DBConnection;
import zutil.io.file.FileUtil;
@ -46,12 +48,12 @@ public class TriggerHttpPage extends HalHttpPage {
TriggerFlow flow = null;
if (request.containsKey("flow_id"))
flow = TriggerFlow.getTriggerFlow(db, Integer.parseInt(request.get("flow_id")));
HalTrigger trigger = null;
Trigger trigger = null;
if (request.containsKey("trigger_id"))
trigger = HalTrigger.getTrigger(db, Integer.parseInt(request.get("trigger_id")));
HalAction action = null;
trigger = Trigger.getTrigger(db, Integer.parseInt(request.get("trigger_id")));
Action action = null;
if (request.containsKey("action_id"))
action = HalAction.getAction(db, Integer.parseInt(request.get("action_id")));
action = Action.getAction(db, Integer.parseInt(request.get("action_id")));
switch(request.get("action")) {
@ -94,8 +96,8 @@ public class TriggerHttpPage extends HalHttpPage {
Templator tmpl = new Templator(FileUtil.find(TEMPLATE));
tmpl.set("triggerConfigurations", triggerConfigurators);
tmpl.set("actionConfigurations", actionConfigurators);
tmpl.set("triggerConf", triggerConfigurators);
tmpl.set("actionConf", actionConfigurators);
tmpl.set("availableTriggers", TriggerManager.getInstance().getAvailableTriggers());
tmpl.set("availableActions", TriggerManager.getInstance().getAvailableActions());
tmpl.set("flows", TriggerFlow.getTriggerFlows(db));

43
src/se/hal/struct/Action.java Executable file
View file

@ -0,0 +1,43 @@
package se.hal.struct;
import se.hal.intf.HalAction;
import se.hal.intf.HalTrigger;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import zutil.db.bean.DBBeanObjectDSO;
import java.sql.SQLException;
import java.util.List;
/**
* Defines a action that will be executed
*/
@DBBean.DBTable(value = "action", superBean = true)
public class Action extends DBBeanObjectDSO<HalAction>{
public static Action getAction(DBConnection db, long id) throws SQLException {
return DBBean.load(db, Action.class, id);
}
public static List<Action> getActions(DBConnection db, TriggerFlow flow) {
// TODO:
return null;
}
public Action() { }
public Action(HalAction action) {
this.setObject(action);
}
/**
* Executes this specific action
*/
public void execute(){
if (getObject() != null)
getObject().execute();
}
}

54
src/se/hal/struct/Trigger.java Executable file
View file

@ -0,0 +1,54 @@
package se.hal.struct;
import se.hal.intf.HalTrigger;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import zutil.db.bean.DBBeanObjectDSO;
import java.sql.SQLException;
import java.util.List;
/**
* A class that declares a trigger/condition that
* needs to be validated before an action can be run
*/
@DBBean.DBTable(value = "trigger", superBean = true)
public class Trigger extends DBBeanObjectDSO<HalTrigger>{
public static Trigger getTrigger(DBConnection db, long id) throws SQLException {
return DBBean.load(db, Trigger.class, id);
}
public static List<Trigger> getTriggers(DBConnection db, TriggerFlow flow) {
// Todo:
return null;
}
public Trigger() { }
public Trigger(HalTrigger trigger) {
this.setObject(trigger);
}
/**
* Evaluates if this trigger has passed. If the trigger is
* true then this method will return true until the {@link #reset()}
* method is called.
*/
public boolean evaluate(){
if (getObject() != null)
return getObject().evaluate();
return false;
}
/**
* Reset the evaluation to false.
*/
public void reset(){
if (getObject() != null)
getObject().reset();
}
}

View file

@ -26,8 +26,8 @@ import java.util.logging.Logger;
public class TriggerFlow extends DBBean {
private static final Logger logger = LogUtil.getLogger();
private transient List<HalTrigger> triggerList = new ArrayList<>();
private transient List<HalAction> actionList = new ArrayList<>();
private transient List<Trigger> triggerList = new ArrayList<>();
private transient List<Action> actionList = new ArrayList<>();
@ -46,24 +46,24 @@ public class TriggerFlow extends DBBean {
DBConnection db = HalContext.getDB();
triggerList.clear();
triggerList = HalTrigger.getTriggers(db, this);
triggerList = Trigger.getTriggers(db, this);
actionList.clear();
actionList = HalAction.getActions(db, this);
actionList = Action.getActions(db, this);
}
public void addTrigger(HalTrigger trigger) {
public void addTrigger(Trigger trigger) {
triggerList.add(trigger);
}
public void removeTrigger(HalTrigger trigger) {
public void removeTrigger(Trigger trigger) {
triggerList.remove(trigger);
}
public void addAction(HalAction action) {
public void addAction(Action action) {
actionList.add(action);
}
public void removeAction(HalAction action) {
public void removeAction(Action action) {
actionList.remove(action);
}
@ -73,7 +73,7 @@ public class TriggerFlow extends DBBean {
* Note: this method will not execute any actionList
*/
public boolean evaluate(){
for(HalTrigger trigger : triggerList){
for(Trigger trigger : triggerList){
if (trigger.evaluate())
return true;
}
@ -84,7 +84,7 @@ public class TriggerFlow extends DBBean {
* Executes the associated actionList in this flow
*/
public void execute(){
for(HalAction action : actionList){
for(Action action : actionList){
action.execute();
}
}
@ -93,7 +93,7 @@ public class TriggerFlow extends DBBean {
* Resets all trigger evaluations
*/
public void reset() {
for(HalTrigger trigger : triggerList){
for(Trigger trigger : triggerList){
trigger.reset();
}
}

View file

@ -1,14 +0,0 @@
package se.hal.struct.dso;
import se.hal.intf.HalAction;
import zutil.db.bean.DBBean;
/**
* A intermediate class for loading HalAction objects from DB
*/
@DBBean.DBTable(value = "action", superBean = true)
public class ActionDSO extends ObjectDSO<HalAction>{
}

View file

@ -1,72 +0,0 @@
package se.hal.struct.dso;
import se.hal.intf.HalTrigger;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import zutil.log.LogUtil;
import zutil.parser.json.JSONParser;
import zutil.parser.json.JSONWriter;
import zutil.ui.Configurator;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A intermediate class for loading HalTrigger objects from DB
*/
public abstract class ObjectDSO<T> extends DBBean{
private static final Logger logger = LogUtil.getLogger();
// DB parameters
private String type;
private String config;
// Local parameters
private transient T cachedObj;
@Override
protected void postUpdateAction() {
if (type != null && !type.isEmpty()) {
if (cachedObj == null) {
try {
Class clazz = Class.forName(type);
cachedObj = (T) clazz.newInstance();
} catch (Exception e) {
logger.log(Level.SEVERE, "Unable instantiate class: " + type, e);
}
}
if (config != null && !config.isEmpty()) {
Configurator<T> configurator = new Configurator<>(cachedObj);
configurator.setValues(JSONParser.read(config));
configurator.applyConfiguration();
}
}
}
@Override
public void save(DBConnection db) throws SQLException {
if (cachedObj == null)
this.config = null;
else {
Configurator<T> configurator = new Configurator<>(cachedObj);
this.config = JSONWriter.toString(configurator.getValuesAsNode());
}
super.save(db);
}
public T getObject(){
return cachedObj;
}
public void setObject(T obj){
this.cachedObj = obj;
}
}

View file

@ -1,14 +0,0 @@
package se.hal.struct.dso;
import se.hal.intf.HalTrigger;
import zutil.db.bean.DBBean;
/**
* A intermediate class for loading HalTrigger objects from DB
*/
@DBBean.DBTable(value = "trigger", superBean = true)
public class TriggerDSO extends ObjectDSO<HalTrigger>{
}

View file

@ -3,6 +3,8 @@ package se.hal;
import org.junit.Test;
import se.hal.intf.HalAction;
import se.hal.intf.HalTrigger;
import se.hal.struct.Action;
import se.hal.struct.Trigger;
import se.hal.struct.TriggerFlow;
import java.util.Collections;
@ -43,9 +45,9 @@ public class TriggerManagerTest {
registerAvailableTrigger();
TriggerFlow flow = new TriggerFlow();
flow.addTrigger(new TestTrigger(true));
flow.addTrigger(new Trigger(new TestTrigger(true)));
TestAction action = new TestAction();
flow.addAction(action);
flow.addAction(new Action(action));
manager.register(flow);
manager.evaluateAndExecute();
assertEquals(1, action.nrOfExecutions);
@ -58,9 +60,9 @@ public class TriggerManagerTest {
TriggerFlow flow = new TriggerFlow();
TestTrigger trigger = new TestTrigger(true);
flow.addTrigger(trigger);
flow.addTrigger(new Trigger(trigger));
TestAction action = new TestAction();
flow.addAction(action);
flow.addAction(new Action(action));
manager.register(flow);
manager.evaluateAndExecute();
@ -75,7 +77,7 @@ public class TriggerManagerTest {
/////////////////////////////////////////////////////////////////////////////
private static class TestTrigger extends HalTrigger {
private static class TestTrigger implements HalTrigger {
boolean evaluation;
TestTrigger(boolean b){ evaluation = b; }
@Override
@ -86,7 +88,7 @@ public class TriggerManagerTest {
}
private class TestAction extends HalAction {
private class TestAction implements HalAction {
int nrOfExecutions;
@Override
public void execute() { nrOfExecutions++; }