package li.strolch.rest.endpoint;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import li.strolch.agent.api.ActivityMap;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.Tags;
import li.strolch.model.activity.Activity;
import li.strolch.model.json.ActivityToJsonVisitor;
import li.strolch.model.json.OrderToJsonVisitor;
import li.strolch.model.json.ResourceToJsonVisitor;
import li.strolch.model.query.ActivityQuery;
import li.strolch.model.query.OrderQuery;
import li.strolch.model.query.ResourceQuery;
import li.strolch.model.query.StrolchTypeNavigation;
import li.strolch.model.query.parser.QueryParser;
import li.strolch.model.visitor.StrolchElementVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.runtime.StrolchConstants;
import li.strolch.utils.collections.Paging;
import li.strolch.utils.helper.StringHelper;
@Path("strolch/model")
public class ModelQuery {
private static final Logger logger = LoggerFactory.getLogger(ModelQuery.class);
/**
* Query {@link Resource Resources} by parsing the query string in {@link QueryData#getQuery()} using
* {@link QueryParser}
*
* @param queryData
* the data from the client
* @param request
* the {@link HttpServletRequest} on which to get the {@link Certificate}
*
* @return {@link Response} containing the JSONified {@link Resource Resources} queried
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("resources")
public Response queryResources(@BeanParam QueryData queryData, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// see if a special realm was requested
String realmName = getRealmName(queryData);
List<Resource> resources = new ArrayList<>();
// parse the query string
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(queryData.getQuery(), true);
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realmName)) {
ResourceMap resourceMap = tx.getResourceMap();
if (query.hasNavigation()) {
String type = ((StrolchTypeNavigation) query.getNavigation()).getType();
dataSetSize = resourceMap.querySize(tx, type);
resources.addAll(tx.doQuery(query));
} else {
Set<String> types = resourceMap.getTypes(tx);
dataSetSize = resourceMap.querySize(tx);
for (String type : types) {
query.setNavigation(new StrolchTypeNavigation(type));
resources.addAll(tx.doQuery(query));
}
}
tx.doNothingOnClose();
}
// do ordering
doOrdering(queryData, resources);
// build JSON response
ResourceToJsonVisitor toJsonVisitor = new ResourceToJsonVisitor();
JsonObject root = marshall(queryData, dataSetSize, resources, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String entity = gson.toJson(root);
return Response.ok(entity).build();
}
/**
* Query {@link Order Orders} by parsing the query string in {@link QueryData#getQuery()} using {@link QueryParser}
*
* @param queryData
* the data from the client
* @param request
* the {@link HttpServletRequest} on which to get the {@link Certificate}
*
* @return {@link Response} containing the JSONified {@link Order Orders} queried
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("orders")
public Response queryOrders(@BeanParam QueryData queryData, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// see if a special realm was requested
String realmName = getRealmName(queryData);
List<Order> orders = new ArrayList<>();
// parse the query string
OrderQuery<Order> query = QueryParser.parseToOrderQuery(queryData.getQuery(), true);
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realmName)) {
OrderMap orderMap = tx.getOrderMap();
if (query.hasNavigation()) {
String type = ((StrolchTypeNavigation) query.getNavigation()).getType();
dataSetSize = orderMap.querySize(tx, type);
orders.addAll(tx.doQuery(query));
} else {
Set<String> types = orderMap.getTypes(tx);
dataSetSize = orderMap.querySize(tx);
for (String type : types) {
query.setNavigation(new StrolchTypeNavigation(type));
orders.addAll(tx.doQuery(query));
}
}
tx.doNothingOnClose();
}
// do ordering
doOrdering(queryData, orders);
// build JSON response
OrderToJsonVisitor toJsonVisitor = new OrderToJsonVisitor();
JsonObject root = marshall(queryData, dataSetSize, orders, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String entity = gson.toJson(root);
return Response.ok(entity).build();
}
/**
* Query {@link Activity Activities} by parsing the query string in {@link QueryData#getQuery()} using
* {@link QueryParser}
*
* @param queryData
* the data from the client
* @param request
* the {@link HttpServletRequest} on which to get the {@link Certificate}
*
* @return {@link Response} containing the JSONified {@link Activity Activities} queried
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("activities")
public Response queryActivities(@BeanParam QueryData queryData, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// see if a special realm was requested
String realmName = getRealmName(queryData);
List<Activity> activities = new ArrayList<>();
// parse the query string
ActivityQuery<Activity> query = QueryParser.parseToActivityQuery(queryData.getQuery(), true);
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realmName)) {
ActivityMap activityMap = tx.getActivityMap();
if (query.hasNavigation()) {
String type = ((StrolchTypeNavigation) query.getNavigation()).getType();
dataSetSize = activityMap.querySize(tx, type);
activities.addAll(tx.doQuery(query));
} else {
Set<String> types = activityMap.getTypes(tx);
dataSetSize = activityMap.querySize(tx);
for (String type : types) {
query.setNavigation(new StrolchTypeNavigation(type));
activities.addAll(tx.doQuery(query));
}
}
tx.doNothingOnClose();
}
// do ordering
doOrdering(queryData, activities);
// build JSON response
ActivityToJsonVisitor toJsonVisitor = new ActivityToJsonVisitor();
JsonObject root = marshall(queryData, dataSetSize, activities, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String entity = gson.toJson(root);
return Response.ok(entity).build();
}
private <T extends StrolchRootElement> JsonObject marshall(QueryData queryData, long dataSetSize, List<T> elements,
StrolchElementVisitor<T, JsonObject> toJsonVisitor) {
// paging
Paging<T> paging = Paging.asPage(elements, queryData.getPageSize(), queryData.getPage());
// get page
List<T> page = paging.getPage();
JsonObject root = new JsonObject();
root.addProperty("msg", "-");
root.addProperty("draw", queryData.getDraw());
root.addProperty("dataSetSize", dataSetSize);
root.addProperty("nrOfElements", paging.getNrOfElements());
if (StringHelper.isNotEmpty(queryData.getOrderBy()))
root.addProperty("sortBy", queryData.getOrderBy());
root.addProperty("ascending", queryData.isAscending());
root.addProperty("nrOfPages", paging.getNrOfPages());
root.addProperty("pageSize", paging.getPageSize());
root.addProperty("page", paging.getPageToReturn());
// add items
JsonArray data = new JsonArray();
for (T t : page) {
JsonObject element = toJsonVisitor.visit(t);
data.add(element);
}
root.add("data", data);
return root;
}
private <T extends StrolchRootElement> void doOrdering(QueryData queryData, List<T> resources) {
if (StringHelper.isNotEmpty(queryData.getOrderBy())) {
if (queryData.getOrderBy().equals(Tags.ID)) {
resources.sort((r1, r2) -> queryData.isAscending() ? r1.getId().compareTo(r2.getId())
: r2.getId().compareTo(r1.getId()));
} else if (queryData.getOrderBy().equals(Tags.NAME)) {
resources.sort((r1, r2) -> queryData.isAscending() ? r1.getName().compareTo(r2.getName())
: r2.getName().compareTo(r1.getName()));
} else if (queryData.getOrderBy().equals(Tags.TYPE)) {
resources.sort((r1, r2) -> queryData.isAscending() ? r1.getType().compareTo(r2.getType())
: r2.getType().compareTo(r1.getType()));
} else {
logger.warn("Unhandled ordering " + queryData.getOrderBy());
}
}
}
private String getRealmName(QueryData queryData) {
String realmName = queryData.getRealmName();
if (StringHelper.isEmpty(realmName))
realmName = StrolchConstants.DEFAULT_REALM;
return realmName;
}
private StrolchTransaction openTx(Certificate certificate, String realm) {
return RestfulStrolchComponent.getInstance().getContainer().getRealm(realm).openTx(certificate,
ModelQuery.class);
}
}