/*
* Copyright 2015 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest.endpoint;
import java.io.StringReader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
import li.strolch.exception.StrolchException;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.json.OrderToJsonVisitor;
import li.strolch.model.json.ResourceToJsonVisitor;
import li.strolch.model.xml.OrderToXmlStringVisitor;
import li.strolch.model.xml.ResourceToXmlStringVisitor;
import li.strolch.model.xml.SimpleStrolchElementListener;
import li.strolch.model.xml.XmlModelSaxReader;
import li.strolch.persistence.api.StrolchPersistenceException;
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.rest.model.AgentOverview;
import li.strolch.rest.model.ElementMapOverview;
import li.strolch.rest.model.ElementMapType;
import li.strolch.rest.model.ElementMapsOverview;
import li.strolch.rest.model.OrderOverview;
import li.strolch.rest.model.RealmDetail;
import li.strolch.rest.model.RealmOverview;
import li.strolch.rest.model.ResourceOverview;
import li.strolch.rest.model.Result;
import li.strolch.rest.model.StrolchElementOverview;
import li.strolch.rest.model.TypeDetail;
import li.strolch.rest.model.TypeOverview;
import li.strolch.service.UpdateOrderService;
import li.strolch.service.UpdateOrderService.UpdateOrderArg;
import li.strolch.service.UpdateResourceService;
import li.strolch.service.UpdateResourceService.UpdateResourceArg;
import li.strolch.service.api.ServiceResult;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@Path("strolch/inspector")
public class Inspector {
private StrolchTransaction openTx(Certificate certificate, String realm) {
return RestfulStrolchComponent.getInstance().getContainer().getRealm(realm).openTx(certificate,
Inspector.class);
}
/**
* <p>
* Root path of the inspector
* </p>
*
* <p>
* Returns the root element, which is an overview of the configured realms
* </p>
*
* @return the root element, which is an overview of the configured realms
*
* @see AgentOverview
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAgent(@Context HttpServletRequest request) {
try {
ComponentContainer container = RestfulStrolchComponent.getInstance().getContainer();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Set<String> realmNames = container.getRealmNames();
List<RealmOverview> realmOverviews = new ArrayList<>(realmNames.size());
for (String realmName : realmNames) {
try (StrolchTransaction tx = openTx(cert, realmName)) {
long size = 0;
size += tx.getResourceMap().querySize(tx);
size += tx.getOrderMap().querySize(tx);
RealmOverview realmOverview = new RealmOverview(realmName, size);
realmOverviews.add(realmOverview);
}
}
AgentOverview agentOverview = new AgentOverview(realmOverviews);
GenericEntity<AgentOverview> entity = new GenericEntity<AgentOverview>(agentOverview, AgentOverview.class) {
//
};
return Response.ok().entity(entity).build();
} catch (Exception e) {
//e.printStackTrace();
throw e;
}
}
/**
* <p>
* Realm inspector
* </p>
*
* <p>
* Returns the overview of a specific relam
* </p>
*
* @param realm
* the realm for which the overview is to be returned
*
* @return the overview of a specific relam
*
* @see RealmDetail
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}")
public Response getRealm(@PathParam("realm") String realm, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
List<ElementMapsOverview> elementMapOverviews = new ArrayList<>(2);
try (StrolchTransaction tx = openTx(cert, realm)) {
ResourceMap resourceMap = tx.getResourceMap();
ElementMapsOverview resourceOverview = new ElementMapsOverview(ElementMapType.RESOURCE);
resourceOverview.setNrOfElements(resourceMap.querySize(tx));
resourceOverview.setTypes(resourceMap.getTypes(tx));
elementMapOverviews.add(resourceOverview);
OrderMap orderMap = tx.getOrderMap();
ElementMapsOverview orderOverview = new ElementMapsOverview(ElementMapType.ORDER);
orderOverview.setNrOfElements(orderMap.querySize(tx));
orderOverview.setTypes(orderMap.getTypes(tx));
elementMapOverviews.add(orderOverview);
}
RealmDetail modelOverview = new RealmDetail(elementMapOverviews);
GenericEntity<RealmDetail> entity = new GenericEntity<RealmDetail>(modelOverview, RealmDetail.class) {
//
};
return Response.ok().entity(entity).build();
}
/**
* <p>
* Resource inspector
* </p>
* <p>
* Returns an overview of the {@link Resource Resources}. This is a list of all the types and the size each type has
* </p>
*
* @param realm
* the realm for which the resource overview is to be returned
*
* @return an overview of the {@link Resource Resources}. This is a list of all the types and the size each type has
*
* @see ElementMapOverview
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/Resource")
public Response getResourcesOverview(@PathParam("realm") String realm, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
ElementMapOverview resourcesOverview;
try (StrolchTransaction tx = openTx(cert, realm)) {
ResourceMap resourceMap = tx.getResourceMap();
List<String> types = new ArrayList<>(resourceMap.getTypes(tx));
Collections.sort(types);
List<TypeOverview> typeOverviews = new ArrayList<>(types.size());
for (String type : types) {
long size = resourceMap.querySize(tx, type);
TypeOverview typeOverview = new TypeOverview(type, size);
typeOverviews.add(typeOverview);
}
resourcesOverview = new ElementMapOverview(ElementMapType.RESOURCE.getName(), typeOverviews);
}
GenericEntity<ElementMapOverview> entity = new GenericEntity<ElementMapOverview>(resourcesOverview,
ElementMapOverview.class) {
//
};
return Response.ok().entity(entity).build();
}
/**
* <p>
* Order inspector
* </p>
* <p>
* Returns an overview of the {@link Order Orders}. This is a list of all the types and the size each type has
* </p>
*
* @param realm
* the realm for which the order overview is to be returned
*
* @return an overview of the {@link Order Orders}. This is a list of all the types and the size each type has
*
* @see ElementMapOverview
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/Order")
public Response getOrdersOverview(@PathParam("realm") String realm, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
ElementMapOverview ordersOverview;
try (StrolchTransaction tx = openTx(cert, realm)) {
OrderMap orderMap = tx.getOrderMap();
List<String> types = new ArrayList<>(orderMap.getTypes(tx));
Collections.sort(types);
List<TypeOverview> typeOverviews = new ArrayList<>(types.size());
for (String type : types) {
long size = orderMap.querySize(tx, type);
TypeOverview typeOverview = new TypeOverview(type, size);
typeOverviews.add(typeOverview);
}
ordersOverview = new ElementMapOverview(ElementMapType.ORDER.getName(), typeOverviews);
}
GenericEntity<ElementMapOverview> entity = new GenericEntity<ElementMapOverview>(ordersOverview,
ElementMapOverview.class) {
//
};
return Response.ok().entity(entity).build();
}
// TODO for the get element type details, we should not simply query all objects, but rather find a solution to query only the id, name, type and date, state for the order
/**
* <p>
* Resource type inspector
* </p>
* <p>
* Returns an overview of the {@link Resource Resources} with the given type. This is a list of overviews of the
* resources
* </p>
*
* @param realm
* the realm for which the resource type overview is to be returned
* @param type
*
* @return an overview of the {@link Resource Resources} with the given type. This is a list of overviews of the
* resources
*
* @see TypeDetail
* @see StrolchElementOverview
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/Resource/{type}")
public Response getResourceTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
TypeDetail typeDetail;
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Resource> byType = tx.getResourceMap().getElementsBy(tx, type);
List<StrolchElementOverview> elementOverviews = new ArrayList<>(byType.size());
for (Resource resource : byType) {
ResourceOverview resourceOverview = new ResourceOverview(resource);
elementOverviews.add(resourceOverview);
}
typeDetail = new TypeDetail(type, elementOverviews);
}
GenericEntity<TypeDetail> entity = new GenericEntity<TypeDetail>(typeDetail, TypeDetail.class) {
//
};
return Response.ok().entity(entity).build();
}
/**
* <p>
* Order type inspector
* </p>
* <p>
* Returns an overview of the {@link Order Orders} with the given type. This is a list of overviews of the orders
* </p>
*
* @param realm
* the realm for which the order type overview is to be returned
* @param type
*
* @return an overview of the {@link Order Orders} with the given type. This is a list of overviews of the orders
*
* @see TypeDetail
* @see StrolchElementOverview
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/Order/{type}")
public Response getOrderTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
TypeDetail typeDetail;
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Order> byType = tx.getOrderMap().getElementsBy(tx, type);
List<StrolchElementOverview> elementOverviews = new ArrayList<>(byType.size());
for (Order order : byType) {
OrderOverview orderOverview = new OrderOverview(order);
elementOverviews.add(orderOverview);
}
typeDetail = new TypeDetail(type, elementOverviews);
}
GenericEntity<TypeDetail> entity = new GenericEntity<TypeDetail>(typeDetail, TypeDetail.class) {
//
};
return Response.ok().entity(entity).build();
}
/**
* <p>
* Resource inspector
* </p>
*
* <p>
* Returns the resource with the given id
* </p>
*
* @param realm
* the realm for which the resource is to be returned
* @param type
* the type of the resource
* @param id
* the id of the resource
*
* @return the resource with the given id
*
* @see ResourceDetail
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/Resource/{type}/{id}")
public Response getResourceAsJson(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Resource resource;
try (StrolchTransaction tx = openTx(cert, realm)) {
resource = tx.getResourceMap().getBy(tx, type, id);
}
if (resource == null) {
throw new StrolchException(MessageFormat.format("No Resource exists for {0}/{1}", type, id)); //$NON-NLS-1$
}
return Response.ok().entity(ResourceToJsonVisitor.toJsonString(resource)).build();
}
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("{realm}/Resource/{type}/{id}")
public Response getResourceAsXml(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Resource resource;
try (StrolchTransaction tx = openTx(cert, realm)) {
resource = tx.getResourceMap().getBy(tx, type, id);
}
if (resource == null) {
throw new StrolchException(MessageFormat.format("No Resource exists for {0}/{1}", type, id)); //$NON-NLS-1$
}
String asXml = new ResourceToXmlStringVisitor().visit(resource);
return Response.ok().type(MediaType.APPLICATION_XML).entity(asXml).build();
}
@PUT
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
@Path("{realm}/Resource/{type}/{id}")
public Response updateResourceAsXml(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id, String data, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Resource resource;
try {
SimpleStrolchElementListener listener = new SimpleStrolchElementListener();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new InputSource(new StringReader(data)), new XmlModelSaxReader(listener));
if (listener.getResources().size() == 0)
throw new StrolchPersistenceException(
MessageFormat.format("No Resources parsed from xml value for {0} / {1}", id, type));
if (listener.getResources().size() > 1)
throw new StrolchPersistenceException(
MessageFormat.format("Multiple Resources parsed from xml value for {0} / {1}", id, type));
resource = listener.getResources().get(0);
} catch (Exception e) {
throw new StrolchPersistenceException(
MessageFormat.format("Failed to extract Resources from xml value for {0} / {1}", id, type), e);
}
UpdateResourceService svc = new UpdateResourceService();
UpdateResourceArg arg = new UpdateResourceArg();
arg.resource = resource;
arg.realm = realm;
ServiceResult result = RestfulStrolchComponent.getInstance().getServiceHandler().doService(cert, svc, arg);
if (result.isOk()) {
String asXml = new ResourceToXmlStringVisitor().visit(resource);
return Response.ok().type(MediaType.APPLICATION_XML).entity(asXml).build();
}
return Result.toResponse(result);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/Order/{type}/{id}")
public Response getOrderAsJson(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Order order;
try (StrolchTransaction tx = openTx(cert, realm)) {
order = tx.getOrderMap().getBy(tx, type, id);
}
if (order == null) {
throw new StrolchException(MessageFormat.format("No Order exists for {0}/{1}", type, id)); //$NON-NLS-1$
}
return Response.ok().entity(OrderToJsonVisitor.toJsonString(order)).build();
}
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("{realm}/Order/{type}/{id}")
public Response getOrderAsXml(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Order order;
try (StrolchTransaction tx = openTx(cert, realm)) {
order = tx.getOrderMap().getBy(tx, type, id);
}
if (order == null) {
throw new StrolchException(MessageFormat.format("No Order exists for {0}/{1}", type, id)); //$NON-NLS-1$
}
String asXml = new OrderToXmlStringVisitor().visit(order);
return Response.ok().type(MediaType.APPLICATION_XML).entity(asXml).build();
}
@PUT
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
@Path("{realm}/Order/{type}/{id}")
public Response updateOrderAsXml(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id, String data, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Order order;
try {
SimpleStrolchElementListener listener = new SimpleStrolchElementListener();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new InputSource(new StringReader(data)), new XmlModelSaxReader(listener));
if (listener.getOrders().size() == 0)
throw new StrolchPersistenceException(
MessageFormat.format("No Orders parsed from xml value for {0} / {1}", id, type));
if (listener.getOrders().size() > 1)
throw new StrolchPersistenceException(
MessageFormat.format("Multiple Orders parsed from xml value for {0} / {1}", id, type));
order = listener.getOrders().get(0);
} catch (Exception e) {
throw new StrolchPersistenceException(
MessageFormat.format("Failed to extract Order from xml value for {0} / {1}", id, type), e);
}
UpdateOrderService svc = new UpdateOrderService();
UpdateOrderArg arg = new UpdateOrderArg();
arg.order = order;
arg.realm = realm;
ServiceResult result = RestfulStrolchComponent.getInstance().getServiceHandler().doService(cert, svc, arg);
if (result.isOk()) {
String asXml = new OrderToXmlStringVisitor().visit(order);
return Response.ok().type(MediaType.APPLICATION_XML).entity(asXml).build();
}
return Result.toResponse(result);
}
}