org.jaqpot.core.service.resource.ValidationResource.java Source code

Java tutorial

Introduction

Here is the source code for org.jaqpot.core.service.resource.ValidationResource.java

Source

/*
 *
 * JAQPOT Quattro
 *
 * JAQPOT Quattro and the components shipped with it (web applications and beans)
 * are licensed by GPL v3 as specified hereafter. Additional components may ship
 * with some other licence as will be specified therein.
 *
 * Copyright (C) 2014-2015 KinkyDesign (Charalampos Chomenidis, Pantelis Sopasakis)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Source code:
 * The source code of JAQPOT Quattro is available on github at:
 * https://github.com/KinkyDesign/JaqpotQuattro
 * All source files of JAQPOT Quattro that are stored on github are licensed
 * with the aforementioned licence. 
 */
package org.jaqpot.core.service.resource;

import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.inject.Inject;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.Topic;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
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 javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.validator.routines.UrlValidator;
import org.jaqpot.core.annotations.Jackson;
import org.jaqpot.core.data.ReportHandler;
import org.jaqpot.core.data.TaskHandler;
import org.jaqpot.core.data.UserHandler;
import org.jaqpot.core.data.serialize.JSONSerializer;
import org.jaqpot.core.model.Task;
import org.jaqpot.core.model.User;
import org.jaqpot.core.model.builder.MetaInfoBuilder;
import org.jaqpot.core.model.facades.UserFacade;
import org.jaqpot.core.model.util.ROG;
import org.jaqpot.core.service.annotations.Authorize;
import org.jaqpot.core.service.exceptions.parameter.ParameterInvalidURIException;
import org.jaqpot.core.service.exceptions.parameter.ParameterIsNullException;
import org.jaqpot.core.service.exceptions.QuotaExceededException;

/**
 * @author Angelos Valsamis
 * @author Pantelis Sopasakis
 * @author Charalampos Chomenidis
 *
 */
@Path("validation")
@Api(value = "/validation", description = "Validation API")
@Produces(MediaType.APPLICATION_JSON)
@Authorize
public class ValidationResource {

    private static final Logger LOG = Logger.getLogger(ValidationResource.class.getName());

    private static final String DEFAULT_ALGORITHM = "{\n" + "  \"trainingService\":\"http://z.ch/t/a\",\n"
            + "  \"predictionService\":\"http://z.ch/p/b\",\n" + "  \"ontologicalClasses\":[\n"
            + "        \"ot:Algorithm\",\n" + "        \"ot:Regression\",\n" + "        \"ot:SupervisedLearning\"\n"
            + "       ],\n" + "  \"parameters\": [\n" + "    {\n" + "       \"name\":\"alpha\",\n"
            + "       \"scope\":\"OPTIONAL\",\n" + "       \"value\":101.635\n" + "    }\n" + "  ]\n" + "}",
            DEFAULT_DATASET = "http://app.jaqpot.org:8080/jaqpot/services/dataset/corona",
            DEFAULT_PRED_FEATURE = "https://apps.ideaconsult.net/enmtest/property/TOX/UNKNOWN_TOXICITY_SECTION/Log2+transformed/94D664CFE4929A0F400A5AD8CA733B52E049A688/3ed642f9-1b42-387a-9966-dea5b91e5f8a",
            DEFAULT_DOA = "http://app.jaqpot.org:8080/jaqpot/services/algorithm/leverage",
            SCALING = "http://app.jaqpot.org:8080/jaqpot/services/algorithm/scaling",
            DEFAULT_TRANSFORMATIONS = "http://app.jaqpot.org:8080/jaqpot/services/pmml/corona-standard-transformations",
            STANDARIZATION = "http://app.jaqpot.org:8080/jaqpot/services/algorithm/standarization";

    @EJB
    TaskHandler taskHandler;

    @EJB
    UserHandler userHandler;

    @EJB
    ReportHandler reportHandler;

    @Inject
    @Jackson
    JSONSerializer serializer;

    @Context
    SecurityContext securityContext;

    @Context
    UriInfo uriInfo;

    @Resource(lookup = "java:jboss/exported/jms/topic/validationCross")
    private Topic crossValidationQueue;

    @Resource(lookup = "java:jboss/exported/jms/topic/validationSplit")
    private Topic splitValidationQueue;

    @Resource(lookup = "java:jboss/exported/jms/topic/validationExternal")
    private Topic externalValidationQueue;

    @Inject
    private JMSContext jmsContext;

    @POST
    @Path("/training_test_cross")
    @ApiOperation(value = "Creates Validation Report", notes = "Creates Validation Report", response = Task.class)
    @org.jaqpot.core.service.annotations.Task
    public Response crossValidateAlgorithm(@FormParam("algorithm_uri") String algorithmURI,
            @FormParam("training_dataset_uri") String datasetURI,
            @FormParam("algorithm_params") String algorithmParameters,
            @FormParam("prediction_feature") String predictionFeature,
            @ApiParam(name = "transformations", defaultValue = DEFAULT_TRANSFORMATIONS) @FormParam("transformations") String transformations,
            @ApiParam(name = "scaling", defaultValue = STANDARIZATION) @FormParam("scaling") String scaling, //, allowableValues = SCALING + "," + STANDARIZATION
            @FormParam("folds") Integer folds, @FormParam("stratify") String stratify,
            @FormParam("seed") Integer seed, @HeaderParam("subjectId") String subjectId)
            throws QuotaExceededException, JMSException, ParameterInvalidURIException, ParameterIsNullException {
        if (algorithmURI == null)
            throw new ParameterIsNullException("algorithmURI");
        if (datasetURI == null)
            throw new ParameterIsNullException("datasetURI");
        if (folds == null)
            throw new ParameterIsNullException("folds");

        User user = userHandler.find(securityContext.getUserPrincipal().getName());
        long reportCount = reportHandler.countAllOfCreator(user.getId());
        int maxAllowedReports = new UserFacade(user).getMaxReports();

        if (reportCount > maxAllowedReports) {
            LOG.info(String.format("User %s has %d algorithms while maximum is %d", user.getId(), reportCount,
                    maxAllowedReports));
            throw new QuotaExceededException("Dear " + user.getId()
                    + ", your quota has been exceeded; you already have " + reportCount + " reports. "
                    + "No more than " + maxAllowedReports + " are allowed with your subscription.");
        }

        UrlValidator urlValidator = new UrlValidator();
        if (!urlValidator.isValid(algorithmURI)) {
            throw new ParameterInvalidURIException("Not valid algorithm URI.");
        }
        if (!urlValidator.isValid(datasetURI)) {
            throw new ParameterInvalidURIException("Not valid dataset URI.");
        }
        if (!urlValidator.isValid(predictionFeature)) {
            throw new ParameterInvalidURIException("Not valid prediction feature URI.");
        }
        if (transformations != null && !transformations.isEmpty() && !urlValidator.isValid(transformations)) {
            throw new ParameterInvalidURIException("Not valid transformation URI.");
        }
        if (scaling != null && !scaling.isEmpty() && !urlValidator.isValid(scaling)) {
            throw new ParameterInvalidURIException("Not valid scaling URI.");
        }
        if ((stratify != null && !stratify.isEmpty() && !stratify.equals("random") && !stratify.equals("normal"))) {
            throw new BadRequestException("Not valid stratify option - choose between random and normal");
        }

        Task task = new Task(new ROG(true).nextString(12));
        task.setMeta(MetaInfoBuilder.builder().setCurrentDate()
                .addTitles("Validation on algorithm: " + algorithmURI).addComments("Validation task created")
                .addDescriptions("Validation task using algorithm " + algorithmURI + " and dataset " + datasetURI)
                .addCreators(securityContext.getUserPrincipal().getName()).build());
        task.setType(Task.Type.VALIDATION);
        task.setHttpStatus(202);
        task.setStatus(Task.Status.QUEUED);
        task.setVisible(Boolean.TRUE);
        Map<String, Object> options = new HashMap<>();
        options.put("taskId", task.getId());
        options.put("algorithm_uri", algorithmURI);
        options.put("dataset_uri", datasetURI);
        options.put("algorithm_params", algorithmParameters);
        options.put("prediction_feature", predictionFeature);
        options.put("folds", folds);
        options.put("stratify", stratify);
        options.put("seed", seed);
        options.put("creator", user.getId());
        options.put("subjectId", subjectId);

        Map<String, String> transformationAlgorithms = new LinkedHashMap<>();
        if (transformations != null && !transformations.isEmpty()) {
            transformationAlgorithms.put(uriInfo.getBaseUri().toString() + "algorithm/pmml",
                    "{\"transformations\" : \"" + transformations + "\"}");
        }
        if (scaling != null && !scaling.isEmpty()) {
            transformationAlgorithms.put(scaling, "");
        }
        if (!transformationAlgorithms.isEmpty()) {
            String transformationAlgorithmsString = serializer.write(transformationAlgorithms);
            LOG.log(Level.INFO, "Transformations:{0}", transformationAlgorithmsString);
            options.put("transformations", transformationAlgorithmsString);
        }

        taskHandler.create(task);
        jmsContext.createProducer().setDeliveryDelay(1000).send(crossValidationQueue, options);

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

    @POST
    @Path("/training_test_split")
    @ApiOperation(value = "Creates Validation Report", notes = "Creates Validation Report", response = Task.class)
    @org.jaqpot.core.service.annotations.Task
    public Response splitValidateAlgorithm(@FormParam("algorithm_uri") String algorithmURI,
            @FormParam("training_dataset_uri") String datasetURI,
            @FormParam("algorithm_params") String algorithmParameters,
            @FormParam("prediction_feature") String predictionFeature,
            @ApiParam(name = "transformations", defaultValue = DEFAULT_TRANSFORMATIONS) @FormParam("transformations") String transformations,
            @ApiParam(name = "scaling", defaultValue = STANDARIZATION) @FormParam("scaling") String scaling, //, allowableValues = SCALING + "," + STANDARIZATION          
            @ApiParam(name = "split_ratio", required = true) @FormParam("split_ratio") Double splitRatio,
            @FormParam("stratify") String stratify, @FormParam("seed") Integer seed,
            @HeaderParam("subjectId") String subjectId)
            throws QuotaExceededException, JMSException, ParameterInvalidURIException, ParameterIsNullException {
        if (algorithmURI == null)
            throw new ParameterIsNullException("algorithmURI");
        if (datasetURI == null)
            throw new ParameterIsNullException("datasetURI");
        if (splitRatio == null)
            throw new ParameterIsNullException("splitRatio");

        User user = userHandler.find(securityContext.getUserPrincipal().getName());
        long reportCount = reportHandler.countAllOfCreator(user.getId());
        int maxAllowedReports = new UserFacade(user).getMaxReports();

        if (reportCount > maxAllowedReports) {
            LOG.info(String.format("User %s has %d reports while maximum is %d", user.getId(), reportCount,
                    maxAllowedReports));
            throw new QuotaExceededException("Dear " + user.getId()
                    + ", your quota has been exceeded; you already have " + reportCount + " reports. "
                    + "No more than " + maxAllowedReports + " are allowed with your subscription.");
        }

        UrlValidator urlValidator = new UrlValidator();
        if (!urlValidator.isValid(algorithmURI)) {
            throw new ParameterInvalidURIException("Not valid algorithm URI.");
        }
        if (!urlValidator.isValid(datasetURI)) {
            throw new ParameterInvalidURIException("Not valid dataset URI.");
        }
        if (!urlValidator.isValid(predictionFeature)) {
            throw new ParameterInvalidURIException("Not valid prediction feature URI.");
        }
        if (transformations != null && !transformations.isEmpty() && !urlValidator.isValid(transformations)) {
            throw new ParameterInvalidURIException("Not valid transformation URI.");
        }
        if (scaling != null && !scaling.isEmpty() && !urlValidator.isValid(scaling)) {
            throw new ParameterInvalidURIException("Not valid scaling URI.");
        }
        if ((stratify != null && !stratify.isEmpty() && !stratify.equals("random") && !stratify.equals("normal"))) {
            throw new BadRequestException("Not valid stratify option - choose between random and normal");
        }

        Task task = new Task(new ROG(true).nextString(12));
        task.setMeta(MetaInfoBuilder.builder().setCurrentDate()
                .addTitles("Validation on algorithm: " + algorithmURI).addComments("Validation task created")
                .addDescriptions("Validation task using algorithm " + algorithmURI + " and dataset " + datasetURI)
                .addCreators(securityContext.getUserPrincipal().getName()).build());
        task.setType(Task.Type.VALIDATION);
        task.setHttpStatus(202);
        task.setStatus(Task.Status.QUEUED);
        task.setVisible(Boolean.TRUE);
        Map<String, Object> options = new HashMap<>();
        options.put("taskId", task.getId());
        options.put("algorithm_uri", algorithmURI);
        options.put("dataset_uri", datasetURI);
        options.put("algorithm_params", algorithmParameters);
        options.put("prediction_feature", predictionFeature);
        options.put("scaling", scaling);
        options.put("split_ratio", splitRatio);
        options.put("stratify", stratify);
        options.put("seed", seed);
        options.put("type", "SPLIT");
        options.put("subjectId", subjectId);

        Map<String, String> transformationAlgorithms = new LinkedHashMap<>();
        if (transformations != null && !transformations.isEmpty()) {
            transformationAlgorithms.put(uriInfo.getBaseUri().toString() + "algorithm/pmml",
                    "{\"transformations\" : \"" + transformations + "\"}");
        }
        if (scaling != null && !scaling.isEmpty()) {
            transformationAlgorithms.put(scaling, "");
        }
        if (!transformationAlgorithms.isEmpty()) {
            String transformationAlgorithmsString = serializer.write(transformationAlgorithms);
            LOG.log(Level.INFO, "Transformations:{0}", transformationAlgorithmsString);
            options.put("transformations", transformationAlgorithmsString);
        }

        taskHandler.create(task);
        System.out.println(splitValidationQueue.getTopicName());
        jmsContext.createProducer().setDeliveryDelay(1000).send(splitValidationQueue, options);
        return Response.ok(task).build();
    }

    @POST
    @Path("/test_set_validation")
    @ApiOperation(value = "Creates Validation Report", notes = "Creates Validation Report", response = Task.class)
    @org.jaqpot.core.service.annotations.Task
    public Response externalValidateAlgorithm(@FormParam("model_uri") String modelURI,
            @FormParam("test_dataset_uri") String datasetURI, @HeaderParam("subjectId") String subjectId)
            throws QuotaExceededException, ParameterIsNullException, ParameterInvalidURIException {
        if (modelURI == null)
            throw new ParameterIsNullException("modelURI");
        if (datasetURI == null)
            throw new ParameterIsNullException("datasetURI");

        User user = userHandler.find(securityContext.getUserPrincipal().getName());
        long reportCount = reportHandler.countAllOfCreator(user.getId());
        int maxAllowedReports = new UserFacade(user).getMaxReports();

        if (reportCount > maxAllowedReports) {
            LOG.info(String.format("User %s has %d algorithms while maximum is %d", user.getId(), reportCount,
                    maxAllowedReports));
            throw new QuotaExceededException("Dear " + user.getId()
                    + ", your quota has been exceeded; you already have " + reportCount + " reports. "
                    + "No more than " + maxAllowedReports + " are allowed with your subscription.");
        }

        UrlValidator urlValidator = new UrlValidator();
        if (!urlValidator.isValid(modelURI)) {
            throw new ParameterInvalidURIException("Not valid model URI.");
        }
        if (!urlValidator.isValid(datasetURI)) {
            throw new ParameterInvalidURIException("Not valid dataset URI.");
        }

        Task task = new Task(new ROG(true).nextString(12));
        task.setMeta(MetaInfoBuilder.builder().setCurrentDate().addTitles("Validation on model: " + modelURI)
                .addComments("Validation task created")
                .addDescriptions("Validation task using model " + modelURI + " and dataset " + datasetURI)
                .addCreators(securityContext.getUserPrincipal().getName()).build());
        task.setType(Task.Type.VALIDATION);
        task.setHttpStatus(202);
        task.setStatus(Task.Status.QUEUED);
        task.setVisible(Boolean.TRUE);
        Map<String, Object> options = new HashMap<>();
        options.put("taskId", task.getId());
        options.put("model_uri", modelURI);
        options.put("subjectId", subjectId);
        options.put("dataset_uri", datasetURI);
        options.put("base_uri", uriInfo.getBaseUri().toString());
        options.put("type", "EXTERNAL");
        options.put("subjectId", subjectId);
        options.put("creator", user.getId());

        taskHandler.create(task);
        jmsContext.createProducer().setDeliveryDelay(1000).send(externalValidationQueue, options);

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

}