lu.list.itis.dkd.aig.template.TemplateService.java Source code

Java tutorial

Introduction

Here is the source code for lu.list.itis.dkd.aig.template.TemplateService.java

Source

/**
 * Copyright (c) 2016-2017  Luxembourg Institute of Science and Technology (LIST).
 * 
 * This software is 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.
 * 
 * for more information about the software, please contact info@list.lu
 */
package lu.list.itis.dkd.aig.template;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.nio.file.NoSuchFileException;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletContext;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.exception.ExceptionUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import lu.list.itis.dkd.aig.resolution.ItemFactory;
import lu.list.itis.dkd.aig.resolution.ItemFactoryBuilder;
import lu.list.itis.dkd.aig.resolution.ResolutionException;
import lu.list.itis.dkd.aig.resolution.TemplateConsistencyException;
import lu.list.itis.dkd.aig.resolution.TemplateParseException;
import lu.list.itis.dkd.aig.util.TemplateManager;

/**
 * Abstract implementation of all the signatures a template service is required to provide.
 *
 * @author Eric Tobias [eric.tobias@list.lu]
 * @since 2.0
 * @version 2.0.0
 */
public abstract class TemplateService {

    private static final Logger logger = Logger.getLogger(TemplateService.class.getSimpleName());

    protected static final String FILE_SEPARATOR = System.getProperties().get("file.separator").toString(); //$NON-NLS-1$
    public static int defaultMaximumNumberOfItems = Integer
            .parseInt(TemplateManager.getProperty("items.build.limit"));//$NON-NLS-1$

    /**
     * Method defining an endpoint that allows to receive and store an XML-based item template.
     *
     * @param stream
     *        An XML stream of data containing the item template. See the referenced schema for
     *        details on form and layout. TODO Generate and reference schema.
     * @param name
     *        The name to store the template as.
     * @return A {@link Response} indicating the success or failure of the operation.
     */
    public abstract Response storeTemplate(final InputStream stream, final String name);

    protected Response storeTemplate(final ServletContext context, final InputStream stream, final String name,
            final String folder) {
        try {
            TemplateManager.store(context, stream, name, folder);
            return Response.ok().build();
        } catch (final UnsupportedEncodingException e) {
            Logger.getLogger(TemplateService.class.getSimpleName()).log(Level.SEVERE, e.getMessage(), e);
            return Response.serverError()
                    .entity("UTF-8 was not supported by the stream reader!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        } catch (final IOException e) {
            Logger.getLogger(TemplateService.class.getSimpleName()).log(Level.SEVERE, e.getMessage(), e);
            return Response.serverError().entity(
                    "An error occured while attempting to store the template!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        }
    }

    /**
     * Method defining an endpoint that allows to retrieve an XML-based item template.
     *
     * @param name
     *        The name of the template to retrieve.
     * @return A {@link Response} indicating the success or failure of the operation.
     */
    public abstract Response getTemplate(final String name);

    protected Response getTemplate(final ServletContext context, final String name, final String folder) {
        try {
            return Response.status(200).type(MediaType.TEXT_XML)
                    .entity(TemplateManager.fetch(context, name, folder)).build();
        } catch (final NoSuchFileException e) {
            return Response.status(404).type(MediaType.TEXT_PLAIN).entity("No template with given name was found!") //$NON-NLS-1$
                    .build();
        } catch (final IOException e) {
            Logger.getLogger(TemplateService.class.getSimpleName()).log(Level.SEVERE, e.getMessage(), e);
            return Response.serverError()
                    .entity("Error while attempting to retrieve the template!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        }
    }

    /**
     * Method defining an endpoint that allows for the deletion of a stored item template.
     *
     * @param name
     *        The name of the template to delete.
     * @return A {@link Response} holding a message indicating whether the deletion was successful,
     *         that is, if there was such a template to delete.
     */
    public abstract Response deleteTemplate(final String name);

    protected Response deleteTemplate(final ServletContext context, final String name, final String folder) {
        try {
            final boolean result = TemplateManager.delete(context, name, folder);
            return Response.status(200).type(MediaType.TEXT_PLAIN)
                    .entity(result ? "Template deleted!" : "No such template to delete!").build(); //$NON-NLS-1$ //$NON-NLS-2$
        } catch (final IOException e) {
            Logger.getLogger(TemplateService.class.getSimpleName()).log(Level.SEVERE, e.getMessage(), e);
            return Response.serverError()
                    .entity("The template could not be deleted due to an internal server error!\n" //$NON-NLS-1$
                            + ExceptionUtils.getStackTrace(e))
                    .build();
        }
    }

    /**
     * Method called to generate a {@link List} of QTI items corresponding to the template with the
     * given name.
     *
     * @param name
     *        The name of the template to load.
     * @param jsonInput
     *        The inputs map as Json, for example: <code>{"key":"value"}</code
     * @return An XML with a root node <code>items</code> holding <code>assessmentItem</code> child
     *         nodes which contain the generated test items.
     */
    public abstract Response generateItems(@QueryParam(value = "name") final String name,
            @QueryParam(value = "input") final String jsonInput);

    protected Response generateItems(final ServletContext context, final String name, final String jsonInput,
            final String folder, final int maxNumberOfItems) {

        final Gson gson = new Gson();
        final Type mapType = new TypeToken<HashMap<String, String>>() {
        }.getType();

        final HashMap<String, String> input = gson.fromJson(jsonInput, mapType);

        String template;
        try {
            template = TemplateManager.fetch(context, name, folder);
        } catch (final IOException e) {
            Logger.getLogger(TemplateService.class.getSimpleName()).log(Level.SEVERE, e.getMessage(), e);
            return Response.serverError().entity(
                    "An error occured while trying to retrieve the template!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        }

        if (null == template) {
            return Response.status(412).entity("The named template could not be found. No items generated!") //$NON-NLS-1$
                    .build();
        }

        final ItemFactoryBuilder itemFactoryBuilder = new ItemFactoryBuilder();
        try {
            itemFactoryBuilder.withTemplate(template);
        } catch (final TemplateParseException e) {
            return Response.status(500)
                    .entity("The provided template contained errors and could not be used to build items!\n" //$NON-NLS-1$
                            + ExceptionUtils.getStackTrace(e))
                    .build();
        }
        itemFactoryBuilder.withItemLimit(maxNumberOfItems);
        itemFactoryBuilder.withInput(input);
        ItemFactory factory = null;
        try {
            factory = itemFactoryBuilder.build();
        } catch (final TemplateParseException e) {
            return Response.status(500).entity(
                    "Internal server error. Internal state conflicted due to logical fallacy! Contact your administrator!\n" //$NON-NLS-1$
                            + ExceptionUtils.getStackTrace(e))
                    .build();
        } catch (final ResolutionException e) {
            return Response.status(500).entity(
                    "The inputs could not be interpreted or were not provided!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        } catch (final NotImplementedException e) {
            return Response.status(500).entity("The initialization of a required component (process) failed!\n" //$NON-NLS-1$
                    + ExceptionUtils.getStackTrace(e)).build();
        } catch (final TemplateConsistencyException e) {
            return Response.status(500).entity(
                    "Inconsistencies in the provided variables, their identifiers, or their mapping caused an exception while trying to construct an item!\n" //$NON-NLS-1$
                            + ExceptionUtils.getStackTrace(e))
                    .build();
        }

        List<String> items;
        try {
            items = factory.buildItems();
        } catch (final TemplateParseException e) {
            return Response.status(500)
                    .entity("Variables could not be resolved to the template!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        } catch (final TemplateConsistencyException e) {
            return Response.status(500)
                    .entity("Variables could not be resolved as by their specification in the template!\n" //$NON-NLS-1$
                            + ExceptionUtils.getStackTrace(e))
                    .build();
        } catch (final ResolutionException e) {
            return Response.status(500)
                    .entity("The resolution of one or more variables failed!\n" + ExceptionUtils.getStackTrace(e)) //$NON-NLS-1$
                    .build();
        }

        return Response.status(200).type(MediaType.TEXT_XML)
                .entity("<layers>" + String.join("", items) + "</layers>").build(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }
}