<commit_before>package net.trajano.doxdb.rest;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.PathSegment;
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 javax.ws.rs.core.UriInfo;

import org.bson.BsonDocument;
import org.bson.BsonValue;

import net.trajano.doxdb.DoxID;
import net.trajano.doxdb.DoxMeta;
import net.trajano.doxdb.IndexView;
import net.trajano.doxdb.SearchResult;
import net.trajano.doxdb.ejb.DoxLocal;
import net.trajano.doxdb.schema.DoxType;
import net.trajano.doxdb.ws.SessionManager;

/**
 * This provides the REST API for DoxDB. The API is built to support AngularJS
 * $resource natively.
 *
 * @author <NAME>
 */
@Path("")
@RequestScoped
public class DoxResource {

    private static final CacheControl NO_CACHE;

    /**
     * <code>application/json</code> with the the UTF-8 character set. Needs to
     * be a constant string in order to be used in annotations.
     */
    private static final String RESPONSE_TYPE = "application/json; charset=utf-8";

    static {
        NO_CACHE = new CacheControl();
        NO_CACHE.setNoCache(true);
        NO_CACHE.setMaxAge(-1);
        NO_CACHE.setMustRevalidate(true);
    }

    @EJB
    private DoxLocal dox;

    @EJB
    private SessionManager sessionManager;

    @Path("{collection}")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(RESPONSE_TYPE)
    public Response create(@PathParam("collection") final String collection,
        final String json) {

        final BsonDocument bson = BsonDocument.parse(json);
        for (final String key : bson.keySet()) {
            if (key.startsWith("_")) {
                bson.remove(key);
            }
        }

        final DoxMeta meta = dox.create(collection, bson);
        sessionManager.sendMessage("CREATE", meta.getDoxId(), collection, meta.getLastUpdatedOn());
        return Response.ok(meta.getContentJson()).lastModified(meta.getLastUpdatedOn()).build();
    }

    @DELETE
    @Path("{collection}/{id}")
    public Response delete(@PathParam("collection") final String collection,
        @PathParam("id") final DoxID doxid,
        @QueryParam("v") final int version) {

        dox.delete(collection, doxid, version);
        sessionManager.sendMessage("DELETE", doxid, collection, new Date());
        return Response.noContent().build();
    }

    @GET
    @Path("{collection}/{id}")
    @Produces(RESPONSE_TYPE)
    public Response get(@PathParam("collection") final String collection,
        @PathParam("id") final DoxID doxid) {

        final DoxMeta meta = dox.read(collection, doxid);
        if (meta == null) {
            return Response.status(Status.NOT_FOUND).type(MediaType.TEXT_PLAIN).entity("Dox not found").build();
        }
        final EntityTag entityTag = new EntityTag(String.valueOf(meta.getVersion()));
        return Response.ok(meta.getContentJson()).tag(entityTag).lastModified(meta.getLastUpdatedOn()).build();
    }

    @GET
    @Path("module.js")
    @Produces("application/javascript")
    public Response getAngularModule(final @Context UriInfo uriInfo) {

        final StreamingOutput out = new StreamingOutput() {

            @Override
            public void write(final OutputStream os) throws IOException,
                WebApplicationException {

                try (final PrintStream w = new PrintStream(os)) {
                    w.println("\"use strict\";");
                    w.print("(function(){");
                    w.print("angular.module('doxdb',['ngResource'])");
                    for (final DoxType doxType : dox.getConfiguration().getDox()) {
                        final String name = doxType.getName();
                        w.print(".factory('DoxDB" + name + "', ['$resource',function(r){");
                        final String uri = uriInfo.getBaseUriBuilder().path(name).build() + "/:id?v=:version";
                        w.print("return r('" + uri + "',{'id':'@_id','version':'@_version'});");
                        w.print("}])");
                    }
                    w.print(";})();");
                }
            }
        };

        return Response.ok(out).tag(dox.toString()).build();
    }

    /**
     * Returns the schema document. It does a check to make sure each path
     * segment contains a restricted set of characters.
     *
     * @param segments
     *            path segments after the URL
     * @return the schema document.
     */
    @GET
    @Path("schema/{segments: .*}")
    @Produces(RESPONSE_TYPE)<commit_msg>Added cache control when cache is OK<commit_after>package net.trajano.doxdb.rest;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.PathSegment;
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 javax.ws.rs.core.UriInfo;

import org.bson.BsonDocument;
import org.bson.BsonValue;

import net.trajano.doxdb.DoxID;
import net.trajano.doxdb.DoxMeta;
import net.trajano.doxdb.IndexView;
import net.trajano.doxdb.SearchResult;
import net.trajano.doxdb.ejb.DoxLocal;
import net.trajano.doxdb.schema.DoxType;
import net.trajano.doxdb.ws.SessionManager;

/**
 * This provides the REST API for DoxDB. The API is built to support AngularJS
 * $resource natively.
 *
 * @author <NAME>
 */
@Path("")
@RequestScoped
public class DoxResource {

    /**
     * Cache control when the data should not be cached.
     */
    private static final CacheControl NO_CACHE;

    /**
     * Cache control when the data can be cached. However, it should still not
     * be persisted on disk
     */
    private static final CacheControl OK_CACHE;

    /**
     * <code>application/json</code> with the the UTF-8 character set. Needs to
     * be a constant string in order to be used in annotations.
     */
    private static final String RESPONSE_TYPE = "application/json; charset=utf-8";

    static {
        NO_CACHE = new CacheControl();
        NO_CACHE.setNoCache(true);
        NO_CACHE.setNoStore(true);
        NO_CACHE.setMaxAge(-1);
        NO_CACHE.setProxyRevalidate(true);
        NO_CACHE.setSMaxAge(-1);
        NO_CACHE.setMustRevalidate(true);

        OK_CACHE = new CacheControl();
        OK_CACHE.setNoCache(false);
        OK_CACHE.setNoStore(true);
        OK_CACHE.setMaxAge(3600);
        OK_CACHE.setProxyRevalidate(true);
        OK_CACHE.setSMaxAge(-1);
        OK_CACHE.setMustRevalidate(true);
    }

    @EJB
    private DoxLocal dox;

    @EJB
    private SessionManager sessionManager;

    @Path("{collection}")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(RESPONSE_TYPE)
    public Response create(@PathParam("collection") final String collection,
        final String json) {

        final BsonDocument bson = BsonDocument.parse(json);
        for (final String key : bson.keySet()) {
            if (key.startsWith("_")) {
                bson.remove(key);
            }
        }

        final DoxMeta meta = dox.create(collection, bson);
        sessionManager.sendMessage("CREATE", meta.getDoxId(), collection, meta.getLastUpdatedOn());
        return Response.ok(meta.getContentJson()).lastModified(meta.getLastUpdatedOn()).build();
    }

    @DELETE
    @Path("{collection}/{id}")
    public Response delete(@PathParam("collection") final String collection,
        @PathParam("id") final DoxID doxid,
        @QueryParam("v") final int version) {

        dox.delete(collection, doxid, version);
        sessionManager.sendMessage("DELETE", doxid, collection, new Date());
        return Response.noContent().build();
    }

    @GET
    @Path("{collection}/{id}")
    @Produces(RESPONSE_TYPE)
    public Response get(@PathParam("collection") final String collection,
        @PathParam("id") final DoxID doxid) {

        final DoxMeta meta = dox.read(collection, doxid);
        if (meta == null) {
            return Response.status(Status.NOT_FOUND).type(MediaType.TEXT_PLAIN).entity("Dox not found").build();
        }
        final EntityTag entityTag = new EntityTag(String.valueOf(meta.getVersion()));
        return Response.ok(meta.getContentJson()).cacheControl(OK_CACHE).tag(entityTag).lastModified(meta.getLastUpdatedOn()).build();
    }

    @GET
    @Path("module.js")
    @Produces("application/javascript")
    public Response getAngularModule(final @Context UriInfo uriInfo) {

        final StreamingOutput out = new StreamingOutput() {

            @Override
            public void write(final OutputStream os) throws IOException,
                WebApplicationException {

                try (final PrintStream w = new PrintStream(os)) {
                    w.println("\"use strict\";");
                    w.print("(function(){");
                    w.print("angular.module('doxdb',['ngResource'])");
                    for (final DoxType doxType : dox.getConfiguration().getDox()) {
                        final String name = doxType.getName();
                        w.print(".factory('DoxDB" + name + "', ['$resource',function(r){");
                        final String uri = uriInfo.getBaseUriBuilder().path(name).build() + "/:id?v=:version";
                        w.print("return r('" + uri + "',{'id':'@_id','version':'@_version'});");
                        w.print("}])");
                    }
                    w.print(";})();");
                }
            }
        };

        return Response.ok(out).cacheControl(OK_CACHE).tag(dox.toString()).build();
    }

    /**
     * Returns the schema document. It does a check to make sure each path
     * segment contains a restricted set of characters.
     *
     * @param segments
     *            path segments after the URL
     * @return the schema document.
     */
    @GET
    @Path("schema/{segments: .*}")
    @Produces(RESPONSE_TYPE)
{'fraction_non_alphanumeric': 0.12768997982515132, 'fraction_numerical': 0.0010087424344317419, 'mean_word_length': 2.8601557430240105, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '980926', 'n_tokens_mistral': 3670, 'n_tokens_neox': 3586, 'n_words': 760}