diff --git a/back/pom.xml b/back/pom.xml
index 75123c1..204d311 100644
--- a/back/pom.xml
+++ b/back/pom.xml
@@ -2,7 +2,7 @@
4.0.0
org.kar
karanage
- 0.1.0
+ 0.2.0
3.1
@@ -22,7 +22,7 @@
kangaroo-and-rabbit
archidata
- 0.1.5
+ 0.2.0
diff --git a/back/src/org/kar/karanage/WebLauncher.java b/back/src/org/kar/karanage/WebLauncher.java
index c73e4f3..d037560 100755
--- a/back/src/org/kar/karanage/WebLauncher.java
+++ b/back/src/org/kar/karanage/WebLauncher.java
@@ -11,11 +11,16 @@ import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.karanage.api.Front;
import org.kar.karanage.api.HealthCheck;
+import org.kar.karanage.api.StateHistoryResource;
import org.kar.karanage.api.StateResource;
import org.kar.karanage.api.UserResource;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.UpdateJwtPublicKey;
+import org.kar.archidata.catcher.ExceptionCatcher;
+import org.kar.archidata.catcher.FailExceptionCatcher;
+import org.kar.archidata.catcher.InputExceptionCatcher;
+import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.AuthenticationFilter;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
@@ -60,9 +65,16 @@ public class WebLauncher {
rc.register(new CORSFilter());
// global authentication system
rc.registerClasses(AuthenticationFilter.class);
+ // register exception catcher
+ rc.register(InputExceptionCatcher.class);
+ rc.register(SystemExceptionCatcher.class);
+ rc.register(FailExceptionCatcher.class);
+ rc.register(ExceptionCatcher.class);
+
// add default resource:
rc.registerClasses(UserResource.class);
rc.registerClasses(StateResource.class);
+ rc.registerClasses(StateHistoryResource.class);
rc.registerClasses(HealthCheck.class);
rc.registerClasses(Front.class);
diff --git a/back/src/org/kar/karanage/api/StateHistoryResource.java b/back/src/org/kar/karanage/api/StateHistoryResource.java
new file mode 100644
index 0000000..106662c
--- /dev/null
+++ b/back/src/org/kar/karanage/api/StateHistoryResource.java
@@ -0,0 +1,129 @@
+package org.kar.karanage.api;
+
+import org.kar.archidata.SqlWrapper;
+import org.kar.archidata.WhereCondition;
+import org.kar.karanage.model.DataInstant;
+import org.kar.karanage.model.DataHistory;
+import org.kar.karanage.model.Group;
+import javax.ws.rs.core.Response;
+
+
+import org.kar.archidata.annotation.security.PermitAll;
+import org.kar.archidata.exception.FailException;
+import org.kar.archidata.exception.InputException;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.List;
+
+
+@Path("/state_history")
+@Produces({MediaType.APPLICATION_JSON})
+public class StateHistoryResource {
+
+ @GET
+ @Path("{group}/{topic:.*}")
+ //@RolesAllowed("USER")
+ @PermitAll
+ public static String get(
+ @PathParam("group") String groupName,
+ @PathParam("topic") String topic,
+ @QueryParam("since") String since,
+ @QueryParam("sinceId") Integer sinceId,
+ @QueryParam("limit") Integer limit) throws Exception {
+ // Keep Group ID:
+ if (groupName == null || groupName.length() == 0) {
+ throw new InputException("group", "Missing URL parameter /state/{group}/...");
+ }
+ Group group = SqlWrapper.getWhere(Group.class,
+ List.of(
+ new WhereCondition("name", "=", groupName)
+ ),
+ false);
+ if (group == null) {
+ throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
+ }
+ if (topic == null || topic.length() == 0) {
+ throw new InputException("topic", "Missing URL parameter /state/xxx/{topic}/...");
+ }
+ if (limit == null || limit == 0) {
+ limit = 100;
+ }
+ if (limit > 100) {
+ limit = 100;
+ }
+ if (limit < 0) {
+ throw new InputException("limit", "Limit must be inside [1..100]");
+ }
+ if (since != null && sinceId != null) {
+ throw new InputException("since,sinceId", "The 2 parameters can not be set at the same time...");
+ }
+
+ List datas = null;
+ if (since != null) {
+ Timestamp time = null;
+ try {
+ time = Timestamp.from(Instant.parse(since));
+ } catch (Exception ex) {
+ throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
+ }
+ datas = SqlWrapper.getsWhere(DataHistory.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("topic", "=", topic),
+ new WhereCondition("modify_date", ">", time)
+ ),
+ "modify_date",
+ true,
+ limit);
+ if (datas == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
+ }
+ } else if (sinceId != null) {
+ datas = SqlWrapper.getsWhere(DataHistory.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("topic", "=", topic),
+ new WhereCondition("id", ">", sinceId)
+ ),
+ "id",
+ true,
+ limit);
+ if (datas == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
+ }
+ } else {
+ datas = SqlWrapper.getsWhere(DataHistory.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("topic", "=", topic)
+ ),
+ "id",
+ true,
+ limit);
+ if (datas == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "Topic does not exist: '" + topic + "'");
+ }
+ }
+
+ StringBuilder out = new StringBuilder("[");
+ boolean first = true;
+ for (DataInstant data : datas) {
+ if (first) {
+ first = false;
+ } else {
+ out.append(",");
+ }
+ out.append("{ \"id\": " + data.id + ", \"time\": \"" + data.modify_date.toInstant().toString() + "\", \"data\":" + data.data + "}");
+ }
+ out.append("]");
+ return out.toString();
+ }
+
+}
+
diff --git a/back/src/org/kar/karanage/api/StateResource.java b/back/src/org/kar/karanage/api/StateResource.java
index a8afc2c..0b7c23e 100644
--- a/back/src/org/kar/karanage/api/StateResource.java
+++ b/back/src/org/kar/karanage/api/StateResource.java
@@ -1,6 +1,7 @@
package org.kar.karanage.api;
import org.kar.archidata.SqlWrapper;
+import org.kar.archidata.WhereCondition;
import org.kar.karanage.model.DataInstant;
import org.kar.karanage.model.DataHistory;
import org.kar.karanage.model.Group;
@@ -8,6 +9,9 @@ import javax.ws.rs.core.Response;
import org.kar.archidata.annotation.security.PermitAll;
+import org.kar.archidata.exception.FailException;
+import org.kar.archidata.exception.InputException;
+
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
@@ -26,35 +30,94 @@ public class StateResource {
@Path("{group}/{topic:.*}")
//@RolesAllowed("USER")
@PermitAll
- public static String getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception {
- Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
- if (group == null) {
- throw new Exception("Missing Group !!!");
+ public static String getWithTopic(
+ @PathParam("group") String groupName,
+ @PathParam("topic") String topic,
+ @QueryParam("since") String since) throws Exception {
+ if (groupName == null || groupName.length() == 0) {
+ throw new InputException("group", "Missing URL parameter /state/{group}/...");
}
- DataInstant data = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true);
-
- return "{ \"time\": \"" + data.modify_date.toLocalDateTime().toString() + "\", \"data\":" + data.data + "}";
+ Group group = SqlWrapper.getWhere(Group.class,
+ List.of(
+ new WhereCondition("name", "=", groupName)
+ ),
+ false);
+ if (group == null) {
+ throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
+ }
+ DataInstant data = null;
+ if (since != null) {
+ Timestamp time = null;
+ try {
+ time = Timestamp.from(Instant.parse(since));
+ } catch (Exception ex) {
+ throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
+ }
+ data = SqlWrapper.getWhere(DataInstant.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("topic", "=", topic),
+ new WhereCondition("modify_date", ">", time)
+ ),
+ true);
+ if (data == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
+ }
+ } else {
+ data = SqlWrapper.getWhere(DataInstant.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("topic", "=", topic)
+ ),
+ true);
+ if (data == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "Topic does not exist: '" + topic + "'");
+ }
+ }
+ return "{ \"time\": \"" + data.modify_date.toInstant().toString() + "\", \"data\":" + data.data + "}";
}
- /*
- public static DataInstant getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception {
- Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
- if (group == null) {
- throw new Exception("Missing Group !!!");
- }
- return SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic);
- }*/
@GET
@Path("{group}")
//@RolesAllowed("USER")
@PermitAll
- public String get(@PathParam("group") String groupName) throws Exception {
- Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
+ public String get(
+ @PathParam("group") String groupName,
+ @QueryParam("since") String since) throws Exception {
+ if (groupName == null || groupName.length() == 0) {
+ throw new InputException("group", "Missing URL parameter /state/{group}/...");
+ }
+ Group group = SqlWrapper.getWhere(Group.class,
+ List.of(
+ new WhereCondition("name", "=", groupName)
+ ),
+ false);
if (group == null) {
- throw new Exception("Missing Group !!!");
+ throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
+ }
+
+ List datas = null;
+ if (since != null) {
+ Timestamp time = null;
+ try {
+ time = Timestamp.from(Instant.parse(since));
+ } catch (Exception ex) {
+ throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
+ }
+ datas = SqlWrapper.getsWhere(DataInstant.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("modify_date", ">", time)
+ ),
+ true);
+ } else {
+ datas = SqlWrapper.getsWhere(DataInstant.class,
+ List.of(
+ new WhereCondition("group", "=", group.id)
+ ),
+ true);
}
StringBuilder out = new StringBuilder("[");
- List datas = SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id, true);
boolean first = true;
for (DataInstant data : datas) {
if (first) {
@@ -62,7 +125,7 @@ public class StateResource {
} else {
out.append(",");
}
- out.append("{ \"time\": \"" + data.modify_date.toLocalDateTime().toString() + "\", \"topic\": \"" + data.topic + "\", \"data\":" + data.data + "}");
+ out.append("{ \"time\": \"" + data.modify_date.toInstant().toString() + "\", \"topic\": \"" + data.topic + "\", \"data\":" + data.data + "}");
}
out.append("]");
return out.toString();
@@ -82,11 +145,27 @@ public class StateResource {
//@RolesAllowed("ADMIN")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
- public Response post(@PathParam("group") String groupName, @PathParam("topic") String topic, String dataToInsert) throws Exception {
+ public Response post(
+ @PathParam("group") String groupName,
+ @PathParam("topic") String topic,
+ String dataToInsert) throws Exception {
DataInstant previous = null;
- Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
+
+ Group group = SqlWrapper.getWhere(Group.class,
+ List.of(
+ new WhereCondition("name", "=", groupName)
+ ),
+ false);
+ if (group == null) {
+ throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
+ }
if (group != null) {
- previous = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true);
+ previous = SqlWrapper.getWhere(DataInstant.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("topic", "=", topic)
+ ),
+ true);
}
if (previous == null) {
// insert new data
@@ -111,7 +190,6 @@ public class StateResource {
DataHistory dataHistory = new DataHistory(previous);
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
OffsetDateTime sqlTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(previous.modify_date.getTime()), ZoneOffset.UTC);
- //tstamp = Timestamp.valueOf(ofsdatetime.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime())
now.getDayOfMonth();
if (sqlTime.getYear() != now.getYear()) {
diff --git a/back/src/org/kar/karanage/api/UserResource.java b/back/src/org/kar/karanage/api/UserResource.java
index 94f7cff..ecad9ad 100755
--- a/back/src/org/kar/karanage/api/UserResource.java
+++ b/back/src/org/kar/karanage/api/UserResource.java
@@ -1,11 +1,11 @@
package org.kar.karanage.api;
-import org.kar.archidata.SqlWrapper;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.User;
import org.kar.karanage.model.UserKaranage;
-
+import org.kar.archidata.SqlWrapper;
import org.kar.archidata.annotation.security.RolesAllowed;
+
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;