diff --git a/app.db b/app.db index a99e382..2b34b99 100644 Binary files a/app.db and b/app.db differ diff --git a/src/main/java/com/iflytop/digester/StartResetTaskThread.java b/src/main/java/com/iflytop/digester/StartResetTaskThread.java new file mode 100644 index 0000000..5810e11 --- /dev/null +++ b/src/main/java/com/iflytop/digester/StartResetTaskThread.java @@ -0,0 +1,248 @@ +package com.iflytop.digester; +import com.iflytop.digester.deviceinstance.Device; +import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable; +public class StartResetTaskThread extends Thread { + // 是否需要放置异常处理试管架 + private Boolean isErrorTubeRackRequired = true; + + @Override + public void run() { + var device = Device.getInstance(); + device.setStatus("preparing"); + this.setProgressMessage("设备初始化..."); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + +// this.getDevice().getIO().setValue("LightRed", 1); +// +// this.setProgressMessage("设备初始化 : 关闭设备门"); +// DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class); +// doorMotor.setEnable(true); +// MoveDoorClose.execute(this.getDevice()); +// +// this.setProgressMessage("设备初始化 : 加液臂复位"); +// DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class); +// liquidMotor.setEnable(true); +// liquidMotor.reset(); +// liquidMotor.moveTo("LiquidArmStandby"); +// +// this.setProgressMessage("设备初始化 : 关闭夹爪"); +// DiActServo transferClipServo = this.getActuator(MyDevice.ACT_TRANSFER_CLIP_SERVO, DiActServo.class); +// transferClipServo.setEnable(true); +// transferClipServo.moveTo("TransClipServoClose"); +// +// this.setProgressMessage("设备初始化 : 搬运机械臂上下移动复位"); +// DiActMotor transUdMotor = this.getActuator(MyDevice.ACT_TRANSFER_UD_MOTOR, DiActMotor.class); +// transUdMotor.setEnable(true); +// transUdMotor.reset(); +// transUdMotor.moveTo("TransUdMotorStandby"); +// +// this.setProgressMessage("设备初始化 : 搬运机械臂左右移动复位"); +// DiActMotor transLrMotor = this.getActuator(MyDevice.ACT_TRANSFER_LR_MOTOR, DiActMotor.class); +// transLrMotor.setEnable(true); +// transLrMotor.reset(); +// transLrMotor.setMoveOffset("TransLrMotorGlobalOffset"); +// transLrMotor.moveTo("TransLrMotorStandby"); +// +// // @TODO : http://127.0.0.1:5566/issues/39 +// this.setProgressMessage("设备初始化 : 加液转盘复位"); +// DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class); +// liquidPlateMotor.setEnable(true); +// liquidPlateMotor.reset(); +// +// // @TODO : http://127.0.0.1:5566/issues/40 +// this.setProgressMessage("设备初始化 : 加热盘转盘复位"); +// DiActMotor heatPlateMotor = this.getActuator(MyDevice.ACT_HEAT_PLATE_MOTOR, DiActMotor.class); +// heatPlateMotor.setEnable(true); +// heatPlateMotor.reset(); +// heatPlateMotor.moveTo("HeatPlateStandby"); +// +// this.setupHeatingSlotCover(); +// this.setupPeristalticPump(); +// +// this.setProgressMessage("设备初始化 : 相机"); +// DiActCameraBasler camera = this.getActuator(MyDevice.ACT_CAMERA, DiActCameraBasler.class); +// camera.setEnable(true); +// +// this.setProgressMessage("设备初始化 : 定时刷新加热盘温度"); +// var slotMan = this.getResourceManager(ResHeatingTubeRackSlotManager.class); +// slotMan.startTemperatureRefresh(); +// +// if ( this.isErrorTubeRackRequired ) { +// this.setProgressMessage("设备初始化 : 放入异常处理试管架"); +// doorMotor.reset(); // 打开设备门 +// DiMdbNotification.taskAction(this, "TaskStartResetErrorTubeRackPutIn"); +// this.waitAction("TaskStartResetErrorTubeRackPutIn"); +// } +// +// this.getDevice().getIO().setValue("LightRed", 0); +// this.getDevice().getIO().setValue("LightGreen", 1); + + this.setProgressMessage("设备初始化 : 完成"); + device.setStatus("ready"); + UfMdbRuntimeVariable.setString("设备已就绪","device.message"); + } +// +// // 设置蠕动泵 +// private void setupPeristalticPump() { +// int peristalticPumpCount = 1; +// var actuators = this.getDevice().getActuators().getAll(); +// for ( var actuator : actuators ) { +// if (actuator instanceof DiActPeristalticPump pump) { +// this.setProgressMessage("设备初始化 : 蠕动泵复位 " + peristalticPumpCount + "/16"); +// pump.setEnable(true); +// peristalticPumpCount++; +// } +// } +// +// Boolean enableSetup = this.getDevice().getEnv().getProperty("app.liquidPeristalticPumpPipeSetupEnable",Boolean.class); +// assert enableSetup != null; +// if ( !enableSetup ) { +// return ; +// } +// +// DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class); +// DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class); +// +// this.setProgressMessage("设备初始化 : 初始化加液管路"); +// MoveDoorOpen.execute(this.getDevice()); +// DiMdbNotification.taskAction(this, "TaskStartResetPumpPipeSetupTubeRankPutIn"); +// this.waitAction("TaskStartResetPumpPipeSetupTubeRankPutIn"); +// MoveDoorClose.execute(this.getDevice()); +// +// // 加液管充满 +// for ( int i=0; i<8; i++ ) { +// this.setProgressMessage("设备初始化 : 初始化加液管路 " + (i+1) + "/8"); +// if ( 0 == i%2 ) { +// liquidMotor.moveTo("LiquidArmPumpGroupOut"); +// liquidPlateMotor.moveTo("LiquidPlateSlotPumpOutGroup",i/2); +// } else { +// liquidMotor.moveTo("LiquidArmPumpGroupIn"); +// liquidPlateMotor.moveTo("LiquidPlateSlotPumpInGroup", i/2); +// } +// +// var pump0 = this.getActuator("LiquidPeristalticPump_"+i+"_0", DiActPeristalticPump.class); +// var pump1 = this.getActuator("LiquidPeristalticPump_"+i+"_1", DiActPeristalticPump.class); +// var pipeVolumeCircle0 = pump1.getLocationValue("LiquidPeristalticPumpPipeVolumeCircle",i, 0); +// var pipeVolumeCircle1 = pump1.getLocationValue("LiquidPeristalticPumpPipeVolumeCircle",i, 1); +// this.batchExecute(List.of( +// () -> pump0.moveBy(pipeVolumeCircle0), +// () -> pump1.moveBy(pipeVolumeCircle1) +// )); +// pump0.retract(); +// pump1.retract(); +// } +// +// liquidMotor.moveTo("LiquidArmStandby"); +// +// // 加液管充满, 需要取出试管架 +// MoveDoorOpen.execute(this.getDevice()); +// DiMdbNotification.taskAction(this, "TaskStartResetPumpPipeSetupTubeRankTakeOut"); +// this.waitAction("TaskStartResetPumpPipeSetupTubeRankTakeOut"); +// MoveDoorClose.execute(this.getDevice()); +// } +// +// /** +// * 清理试管架 +// * @issue : 无法获取加液位置是否存在试管架 +// */ +// private void setupHeatingSlotCover() { +// boolean isDoorOpen = false; +// Integer errorSlotIndex = this.getDevice().getEnv().getProperty("app.errorSlotIndex",Integer.class); +// +// for ( int i=0; i<5; i++ ) { +// this.setProgressMessage("设备初始化 : 检查试管架 " + (i+1) + "/5"); +// String key = "HeatingPlateMotorSlotCover_" + i; +// DiActServo heatSlotCoverServo = this.getActuator(key, DiActServo.class); +// heatSlotCoverServo.setEnable(true); +// var currentPos = heatSlotCoverServo.getCurrentPos(); +// LOG.info("HeatingPlateMotorSlotCover #{} : current pos = {}", i, currentPos); +// +// // 如果是空的,则初始化位置后继续下一步 +// var rackExistsPos = heatSlotCoverServo.getLocationValue("HeatingPlateMotorSlotCoverRackExists"); +// if ( currentPos > rackExistsPos ) { +// heatSlotCoverServo.setCurrentPosAsMiddle(); +// continue; +// } +// +// // 如果是空试管架, 又是异常区域则不处理, 因为异常区域始终要有个试管架 +// var emptyRackExistsPos = heatSlotCoverServo.getLocationValue("HeatingPlateMotorSlotCoverEmptyRackExists"); +// if ( currentPos > emptyRackExistsPos && null != errorSlotIndex && errorSlotIndex == i ) { // 异常区域存在空试管架 +// this.isErrorTubeRackRequired = false; +// continue; +// } +// +// var moveToLiquidPlate = new MoveMoveTubeRackFromHeatPlateToLiquidPlate(); +// moveToLiquidPlate.setDevice(this.getDevice()); +// moveToLiquidPlate.slotIndex = i; +// moveToLiquidPlate.updateSlotStatus = false; +// moveToLiquidPlate.run(); +// +// if ( !isDoorOpen ) { +// MoveDoorOpen.execute(this.getDevice()); +// isDoorOpen = true; +// } +// +// heatSlotCoverServo.moveTo("HeatingPlateMotorSlotCoverEmpty"); +// heatSlotCoverServo.setEnable(false); +// +// // 等待取出试管架 +// DiMdbNotification.taskAction(this, "TaskStartResetErrorTubeRackTakeOut"); +// this.waitAction("TaskStartResetErrorTubeRackTakeOut"); +// LOG.info("HeatingPlateMotorSlotCover #{} : take out", i); +// +// heatSlotCoverServo.setEnable(true); +// heatSlotCoverServo.setCurrentPosAsMiddle(); +// } +// +// if ( isDoorOpen ) { +// MoveDoorClose.execute(this.getDevice()); +// } +// } +// +// // 异常处理位试管架取出 +// public void actionErrorTubeRackTakeOut() { +// var action = this.getAction("TaskStartResetErrorTubeRackTakeOut"); +// action.finish(); +// } +// +// // 放入异常处理位试管架 +// public void actionErrorTubeRackPutIn() { +// var slotMan = this.getResourceManager(ResHeatingTubeRackSlotManager.class); +// var slot = slotMan.getErrorSlot(); +// +// // 关闭设备门 +// DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class); +// doorMotor.moveToIO(1, 1); +// +// var move = new MoveMoveTubeRackFromLiquidPlateToHeatPlate(); +// move.slotIndex = slot.index; +// move.setDevice(this.getDevice()); +// move.run(); +// slot.lock(); +// +// var action = this.getAction("TaskStartResetErrorTubeRackPutIn"); +// action.finish(); +// } +// +// // 蠕动泵管路初始化 +// public void actionPumpPipeSetupTubeRankPutIn() { +// var action = this.getAction("TaskStartResetPumpPipeSetupTubeRankPutIn"); +// action.finish(); +// } +// +// // 蠕动泵管路初始化 +// public void actionPumpPipeSetupTubeRankTakeOut() { +// var action = this.getAction("TaskStartResetPumpPipeSetupTubeRankTakeOut"); +// action.finish(); +// } + + // set progress message + private void setProgressMessage(String message) { + UfMdbRuntimeVariable.setString(message, "device.start.message"); + } +} diff --git a/src/main/java/com/iflytop/digester/controller/DeviceController.java b/src/main/java/com/iflytop/digester/controller/DeviceController.java new file mode 100644 index 0000000..beeeb2d --- /dev/null +++ b/src/main/java/com/iflytop/digester/controller/DeviceController.java @@ -0,0 +1,31 @@ +package com.iflytop.digester.controller; +import com.iflytop.digester.StartResetTaskThread; +import com.iflytop.digester.deviceinstance.Device; +import com.iflytop.digester.underframework.controller.UfApiControllerBase; +import com.iflytop.digester.underframework.controller.UfApiResponse; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +@Controller +public class DeviceController extends UfApiControllerBase { + @Resource + private Device device; + + @ResponseBody + @PostMapping("/api/device/start") + public UfApiResponse start() { + if (!"new".equals(this.device.getStatus())) { + return this.error("当前设备无法执行启动操作"); + } + var startReset = new StartResetTaskThread(); + startReset.start(); + return this.success(); + } + + @ResponseBody + @PostMapping("/api/device/status-get") + public UfApiResponse statusGet() { + return this.success(this.device.getStatus()); + } +} diff --git a/src/main/java/com/iflytop/digester/controller/HeatSlotController.java b/src/main/java/com/iflytop/digester/controller/HeatSlotController.java new file mode 100644 index 0000000..fe8cec2 --- /dev/null +++ b/src/main/java/com/iflytop/digester/controller/HeatSlotController.java @@ -0,0 +1,21 @@ +package com.iflytop.digester.controller; +import com.iflytop.digester.deviceinstance.Device; +import com.iflytop.digester.underframework.controller.UfApiControllerBase; +import com.iflytop.digester.underframework.controller.UfApiResponse; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import java.util.Map; +@Controller +public class HeatSlotController extends UfApiControllerBase { + @Resource + private Device device; + + @ResponseBody + @PostMapping("/api/heat-slot/list") + public UfApiResponse list() { + var heatSlots = this.device.heatingTurntable.getSlots(); + return this.success(Map.of("slots", heatSlots)); + } +} diff --git a/src/main/java/com/iflytop/digester/controller/LiquidController.java b/src/main/java/com/iflytop/digester/controller/LiquidController.java new file mode 100644 index 0000000..52a86de --- /dev/null +++ b/src/main/java/com/iflytop/digester/controller/LiquidController.java @@ -0,0 +1,21 @@ +package com.iflytop.digester.controller; +import com.iflytop.digester.deviceinstance.Device; +import com.iflytop.digester.underframework.controller.UfApiControllerBase; +import com.iflytop.digester.underframework.controller.UfApiResponse; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import java.util.Map; +@Controller +public class LiquidController extends UfApiControllerBase { + @Resource + private Device device; + + @ResponseBody + @PostMapping("/api/liquid/list") + public UfApiResponse list() { + var liquids = this.device.liquidAddition.getLiquids(); + return this.success(Map.of("liquids", liquids)); + } +} diff --git a/src/main/java/com/iflytop/digester/deviceinstance/Device.java b/src/main/java/com/iflytop/digester/deviceinstance/Device.java index e4f37b6..02eb416 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/Device.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/Device.java @@ -1,9 +1,14 @@ package com.iflytop.digester.deviceinstance; +import com.iflytop.digester.DigestionTaskThread; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class Device { + // logger + public static final Logger LOG = LoggerFactory.getLogger(Device.class); // device instance private static Device instance = null; @@ -22,6 +27,9 @@ public class Device { @Resource public Camera camera; + // device status + private String status = "new"; // new, preparing, ready, running, stopping, stopped + // get device instance public static Device getInstance() { return instance; @@ -31,4 +39,15 @@ public class Device { public void init() { instance = this; } + + // start device + public String getStatus() { + return status; + } + + // set device status + public void setStatus(String status) { + LOG.info("[Device Status] {} => {}", this.status, status); + this.status = status; + } } diff --git a/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java b/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java index 8ea72a5..d5311ca 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java @@ -17,6 +17,11 @@ public class HeatingTurntableInstance { } } + // 获取槽位列表 + public List getSlots() { + return slots; + } + // 分配加热位 synchronized public HeatingTurntableSlot allocSlot( String tubeRackNo ) { for (HeatingTurntableSlot slot : slots) { diff --git a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java index cdfe016..e52132e 100644 --- a/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java +++ b/src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java @@ -17,13 +17,19 @@ public class LiquidAdditionInstance { LiquidAdditionLiquid liquid = new LiquidAdditionLiquid(); // @TODO : 测试用,要删除 - liquid.type = "盐酸"; + liquid.type = "hydrochloric"; liquid.volume = 100; liquids.add(liquid); } } + // get liquids + public List getLiquids() { + return this.liquids; + } + + // 针对试管加液 public void addLiquidToTubes(List tubes, String type, int volume ) { var pumpIndexes = this.getPumpIndexForGroupOutAndIn(type); diff --git a/src/main/java/com/iflytop/digester/underframework/controller/UfApiDictionary.java b/src/main/java/com/iflytop/digester/underframework/controller/UfApiDictionary.java new file mode 100644 index 0000000..eb7892d --- /dev/null +++ b/src/main/java/com/iflytop/digester/underframework/controller/UfApiDictionary.java @@ -0,0 +1,17 @@ +package com.iflytop.digester.underframework.controller; +import com.iflytop.digester.underframework.dao.model.UfMdbDictItem; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseBody; +import java.util.Map; +@Controller +public class UfApiDictionary extends UfApiControllerBase { + @ResponseBody + @PostMapping("/api/dictionary/list-by-group") + public UfApiResponse listByGroup(@RequestBody Map params ) { + var group = (String)params.get("group"); + var items = UfMdbDictItem.getItems(group); + return success(items); + } +} diff --git a/src/main/java/com/iflytop/digester/underframework/controller/UfApiRuntimeVariable.java b/src/main/java/com/iflytop/digester/underframework/controller/UfApiRuntimeVariable.java new file mode 100644 index 0000000..0040cd2 --- /dev/null +++ b/src/main/java/com/iflytop/digester/underframework/controller/UfApiRuntimeVariable.java @@ -0,0 +1,18 @@ +package com.iflytop.digester.underframework.controller; +import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseBody; +import java.util.Map; +@Controller +public class UfApiRuntimeVariable extends UfApiControllerBase { + @ResponseBody + @PostMapping("/api/runtime-variable/get") + public UfApiResponse get(@RequestBody Map params ) { + String key = (String)params.get("key"); + var value = UfMdbRuntimeVariable.getString(key); + assert value != null; + return success(Map.of("value", value)); + } +} diff --git a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbDictItem.java b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbDictItem.java new file mode 100644 index 0000000..fb362f5 --- /dev/null +++ b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbDictItem.java @@ -0,0 +1,33 @@ +package com.iflytop.digester.underframework.dao.model; +import com.iflytop.digester.underframework.dao.record.UfActiveRecord; +import com.iflytop.digester.underframework.dao.record.UfActiveRecordField; + +import java.util.List; +import java.util.Map; + +public class UfMdbDictItem extends UfActiveRecord { + @UfActiveRecordField + public String groupKey; + + @UfActiveRecordField + public String groupName; + + @UfActiveRecordField + public String itemKey; + + @UfActiveRecordField + public String itemName; + + @UfActiveRecordField + public String itemValue; + + // get table name + public static String getTableName() { + return "app_dict_items"; + } + + // get items + public static List getItems(String groupKey) { + return UfActiveRecord.find(UfMdbDictItem.class, Map.of("groupKey", groupKey)); + } +} diff --git a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java new file mode 100644 index 0000000..5488f35 --- /dev/null +++ b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java @@ -0,0 +1,67 @@ +package com.iflytop.digester.underframework.dao.model; +import com.iflytop.digester.underframework.dao.record.UfActiveRecord; +import com.iflytop.digester.underframework.dao.record.UfActiveRecordField; +import java.util.Map; +public class UfMdbRuntimeVariable extends UfActiveRecord { + @UfActiveRecordField + public String key; + + @UfActiveRecordField + public String value; + + // get table name + public static String getTableName() { + return "app_runtime_variables"; + } + + // build key + private static String buildKey(String key, Object ... args) { + StringBuilder keyBuilder = new StringBuilder(key); + for (Object arg : args) { + keyBuilder.append(".").append(arg.toString()); + } + return keyBuilder.toString(); + } + + // get location value + public static UfMdbRuntimeVariable getVariable(String key, Object ... args ) { + key = UfMdbRuntimeVariable.buildKey(key, args); + return UfActiveRecord.findOne(UfMdbRuntimeVariable.class, Map.of("key", key)); + } + + // get string + public static String getString(String name, Object ... args ) { + var variable = UfMdbRuntimeVariable.getVariable(name, args); + return null == variable ? null : variable.value; + } + + // get integer + public static Integer getInteger(String name, Object ... args ) { + var variable = UfMdbRuntimeVariable.getVariable(name, args); + return null == variable ? null : Integer.parseInt(variable.value); + } + + // set string + public static void setString(String value, String name, Object ... args ) { + var variable = UfMdbRuntimeVariable.getVariable(name, args); + if ( null == variable ) { + variable = new UfMdbRuntimeVariable(); + variable.key = UfMdbRuntimeVariable.buildKey(name, args); + } + variable.value = value; + variable.save(); + } + + // set integer + public static void setInteger(Integer value, String name, Object ... args ) { + UfMdbRuntimeVariable.setString(value.toString(), name, args); + } + + // remove + public static void remove(String name, Object ... args ) { + var variable = UfMdbRuntimeVariable.getVariable(name); + if ( null != variable ) { + variable.delete(); + } + } +} diff --git a/src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java b/src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java index c87e991..ae51de4 100644 --- a/src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java +++ b/src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java @@ -103,6 +103,13 @@ public class UfActiveRecord { return mapper.count(criteria); } + // find by conditions + public static List find(Class modelClass, Map conditions) { + var criteria = new UfActiveRecordCriteria(); + criteria.conditions = conditions; + return UfActiveRecord.find(modelClass, criteria); + } + // find all by criteria public static List find(Class modelClass, UfActiveRecordCriteria criteria ) { criteria.tableName = UfActiveRecord.getTableNameFromModelClass(modelClass); diff --git a/web b/web index 1281f43..7f4d0b8 160000 --- a/web +++ b/web @@ -1 +1 @@ -Subproject commit 1281f43be8a5de2f98d83c2a32506bb878eb5495 +Subproject commit 7f4d0b8bfe683b41e75233368ed1ec1e98c8c350