All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.byu.hbll.box.internal.web.DocumentService Maven / Gradle / Ivy

There is a newer version: 1.3.5
Show newest version
/** */
package edu.byu.hbll.box.internal.web;

import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.io.JsonStringEncoder;
import com.fasterxml.jackson.core.util.BufferRecyclers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.byu.hbll.box.BoxDocument;
import edu.byu.hbll.box.QueryResult;
import edu.byu.hbll.box.Source;
import edu.byu.hbll.box.internal.core.Registry;
import edu.byu.hbll.box.internal.util.CursorUtils;
import edu.byu.hbll.box.internal.util.FlexDateParser;

/**
 * NOTE: The {@link Path} endpoints in this class are designed with an extra unnecessary template in
 * order to push them down in matching precedence so as to not hijack all of the application's other
 * paths. https://www.safaribooksonline.com/library/view/restful-java-with/9781449361433/ch04.html
 */
@Path("{sourceName}{x: /documents}")
public class DocumentService {

  /** */
  static final Logger logger = LoggerFactory.getLogger(DocumentService.class);

  /** */
  private static final ObjectMapper mapper = new ObjectMapper();

  /** */
  @Inject private Registry registry;

  /**
   * Post a document to box.
   *
   * @param json the json document in the body
   * @return Response {@link Response}
   */
  @POST
  @Produces(MediaType.APPLICATION_JSON)
  public Response postDocument(String json) {
    String sourceName = registry.getPrincipalSource().getName();
    String idField = registry.getPrincipalSource().getIdField();
    ObjectNode node = null;
    try {
      node = (ObjectNode) mapper.readTree(json);
    } catch (Exception e) {
      logger.error("Could not parse posted document as json", e);
      return Response.status(Status.BAD_REQUEST)
          .entity("The posted document was not valid json")
          .build();
    }
    String id = node.path(idField).asText();
    BoxDocument boxDocument = new BoxDocument(id, node);
    registry.getDocumentHandler().save(sourceName, boxDocument);
    return Response.ok(new WebDocument(boxDocument)).build();
  }

  /**
   * @param params
   * @return
   */
  @GET
  @Path("{id}")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getDocument(@BeanParam DocumentParams params) {

    logger.debug("{}", params.getUriInfo().getRequestUri());

    try {
      registry.verifySource(params.getSourceName());
    } catch (Exception e) {
      return Response.status(Status.BAD_REQUEST)
          .entity(errorMessage("source not recognized"))
          .build();
    }

    List docs;

    try {
      docs =
          registry
              .getDocumentHandler()
              .find(params.getSourceName(), new DocumentsParams(params).toQuery());
    } catch (Exception e) {
      logger.error(e.toString(), e);
      return Response.status(Status.INTERNAL_SERVER_ERROR)
          .entity(errorMessage("unable to retrieve document: " + e))
          .build();
    }

    BoxDocument doc = docs.isEmpty() ? null : docs.get(0);
    WebDocument webDoc = new WebDocument(doc, params.getMetadataLevel());

    if (doc.getMessage() != null) {
      return Response.status(Status.INTERNAL_SERVER_ERROR).entity(webDoc).build();
    } else if (doc.isDeleted()) {
      return Response.status(Status.GONE).entity(webDoc).build();
    } else if (!doc.isProcessed()) {
      return Response.status(Status.NOT_FOUND).entity(webDoc).build();
    }

    return Response.ok(webDoc).build();
  }

  /**
   * @param params
   * @return
   */
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response getDocuments(@BeanParam DocumentsParams params) {

    logger.debug("{}", params.getUriInfo().getRequestUri());

    String sourceName = params.getSourceName();

    try {
      sourceName = registry.verifySource(sourceName);
    } catch (Exception e) {
      return Response.status(Status.BAD_REQUEST)
          .entity(errorMessage("source not recognized"))
          .build();
    }

    Source source = registry.getSource(sourceName);

    if (params.getLimit() < 0) {
      params.setLimit(source.getDefaultLimit());
    }

    String finalSourceName = sourceName;

    if (params.getFromText() != null) {
      try {
        Instant from = FlexDateParser.parse(params.getFromText());
        long cursor = CursorUtils.getCursor(from);
        params.setCursor(cursor);
      } catch (DateTimeParseException e) {
        return Response.status(Status.BAD_REQUEST)
            .entity(errorMessage("from parameter must be a ISO 8601 date: " + e))
            .build();
      }
    }

    StreamingOutput entity =
        new StreamingOutput() {
          @Override
          public void write(OutputStream out) {
            try {
              BufferedOutputStream bout = new BufferedOutputStream(out);
              PrintWriter writer =
                  new PrintWriter(new OutputStreamWriter(bout, StandardCharsets.UTF_8));

              writer.print("{\"documents\":[");
              writer.flush();

              QueryResult result =
                  registry.getDocumentHandler().find(finalSourceName, params.toQuery(), bout);

              writer.print("],");

              String nextUri =
                  UriBuilder.fromUri(params.getUriInfo().getRequestUri())
                      .replaceQueryParam("cursor", result.getNextCursor())
                      .replaceQueryParam("from")
                      .build()
                      .toString();

              JsonStringEncoder e = BufferRecyclers.getJsonStringEncoder();

              writer.print("\"nextUri\":\"" + new String(e.quoteAsString(nextUri)) + "\",");
              writer.print("\"nextCursor\":\"" + result.getNextCursor() + "\"}");
              writer.close();
            } catch (Exception e) {
              logger.error(e.toString(), e);
              throw new InternalServerErrorException(
                  Response.status(Status.INTERNAL_SERVER_ERROR)
                      .entity(errorMessage("unable to retrieve documents: " + e))
                      .build());
            }
          }
        };

    return Response.ok(entity).build();
  }

  /**
   * @param value
   * @return
   */
  static boolean booleanValueOf(String value) {
    if (value == null) {
      return false;
    }

    switch (value.toLowerCase()) {
      case "true":
      case "yes":
      case "y":
      case "":
      case "1":
        return true;
      default:
        return false;
    }
  }

  private String errorMessage(String message) {
    return mapper.createObjectNode().put("error", message).toString();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy