info.rmapproject.api.responsemgr.AgentResponseManager.java Source code

Java tutorial

Introduction

Here is the source code for info.rmapproject.api.responsemgr.AgentResponseManager.java

Source

/*******************************************************************************
 * Copyright 2016 Johns Hopkins University
 *
 * 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.
 *
 * This software was produced as part of the RMap Project (http://rmap-project.info),
 * The RMap Project was funded by the Alfred P. Sloan Foundation and is a 
 * collaboration between Data Conservancy, Portico, and IEEE.
 *******************************************************************************/
package info.rmapproject.api.responsemgr;

import info.rmapproject.api.exception.ErrorCode;
import info.rmapproject.api.exception.RMapApiException;
import info.rmapproject.api.lists.NonRdfType;
import info.rmapproject.api.lists.RdfMediaType;
import info.rmapproject.api.utils.Constants;
import info.rmapproject.api.utils.HttpTypeMediator;
import info.rmapproject.api.utils.URIListHandler;
import info.rmapproject.api.utils.Utils;
import info.rmapproject.core.exception.RMapAgentNotFoundException;
import info.rmapproject.core.exception.RMapDefectiveArgumentException;
import info.rmapproject.core.exception.RMapDeletedObjectException;
import info.rmapproject.core.exception.RMapException;
import info.rmapproject.core.exception.RMapObjectNotFoundException;
import info.rmapproject.core.exception.RMapTombstonedObjectException;
import info.rmapproject.core.model.RMapObjectType;
import info.rmapproject.core.model.RMapStatus;
import info.rmapproject.core.model.agent.RMapAgent;
import info.rmapproject.core.model.request.RMapSearchParams;
import info.rmapproject.core.rdfhandler.RDFHandler;
import info.rmapproject.core.rmapservice.RMapService;
import info.rmapproject.core.utils.Terms;

import java.io.OutputStream;
import java.net.URI;
import java.net.URLDecoder;
import java.util.List;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.openrdf.model.vocabulary.DC;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Creates HTTP responses for RMap Agent REST API requests.
 *
 * @author khanson
 */
public class AgentResponseManager extends ResponseManager {

    /**
     * Constructor autowires the RMapService and RDFHandler.
     *
     * @param rmapService the RMap Service
     * @param rdfHandler the RDF handler
     * @throws RMapApiException the RMap API Exception
     */
    @Autowired
    public AgentResponseManager(RMapService rmapService, RDFHandler rdfHandler) throws RMapApiException {
        super(rmapService, rdfHandler);
    }

    /**
     * Displays Agent Service Options.
     *
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getAgentServiceOptions() throws RMapApiException {
        boolean reqSuccessful = false;
        Response response = null;
        try {
            String linkRel = "<" + Utils.getDocumentationPath() + ">;rel=\"" + DC.DESCRIPTION.toString() + "\"";
            response = Response.status(Response.Status.OK)
                    .entity("{\"description\":\"Follow header link to read documentation.\"}")
                    .header("Allow", "HEAD,OPTIONS,GET").header("Link", linkRel).build();
            reqSuccessful = true;
        } catch (Exception ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_RETRIEVING_API_OPTIONS);
        } finally {
            if (!reqSuccessful && response != null)
                response.close();
        }
        return response;
    }

    /**
     * Displays Agent Service Options Header.
     *
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getAgentServiceHead() throws RMapApiException {
        boolean reqSuccessful = false;
        Response response = null;
        try {
            String linkRel = "<" + Utils.getDocumentationPath() + ">;rel=\"" + DC.DESCRIPTION.toString() + "\"";
            response = Response.status(Response.Status.OK).header("Allow", "HEAD,OPTIONS,GET")
                    .header("Link", linkRel).build();
            reqSuccessful = true;
        } catch (Exception ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_RETRIEVING_API_HEAD);
        } finally {
            if (!reqSuccessful && response != null)
                response.close();
        }
        return response;
    }

    /**
     * Retrieves RMap Agent in requested RDF format and forms an HTTP response.
     *
     * @param strAgentUri the Agent URI
     * @param returnType the return media type
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getRMapAgent(String strAgentUri, RdfMediaType returnType) throws RMapApiException {
        boolean reqSuccessful = false;
        Response response = null;
        try {
            if (strAgentUri == null || strAgentUri.length() == 0) {
                throw new RMapApiException(ErrorCode.ER_NO_OBJECT_URI_PROVIDED);
            }
            if (returnType == null) {
                returnType = Constants.DEFAULT_RDF_TYPE;
            }

            URI uriAgentId = convertPathStringToURI(strAgentUri);

            RMapAgent rmapAgent = rmapService.readAgent(uriAgentId);
            if (rmapAgent == null) {
                throw new RMapApiException(ErrorCode.ER_CORE_READ_AGENT_RETURNED_NULL);
            }

            OutputStream agentOutput = rdfHandler.agent2Rdf(rmapAgent, returnType.getRdfType());
            if (agentOutput == null) {
                throw new RMapApiException(ErrorCode.ER_CORE_RDFHANDLER_OUTPUT_ISNULL);
            }

            RMapStatus status = rmapService.getAgentStatus(uriAgentId);
            if (status == null) {
                throw new RMapApiException(ErrorCode.ER_CORE_GET_STATUS_RETURNED_NULL);
            }
            String linkRel = "<" + status.getPath().toString() + ">" + ";rel=\"" + Terms.RMAP_HASSTATUS_PATH + "\"";

            response = Response.status(Response.Status.OK).entity(agentOutput.toString())
                    .location(new URI(Utils.makeAgentUrl(strAgentUri))).header("Link", linkRel) //switch this to link()
                    .type(HttpTypeMediator.getResponseRMapMediaType("agent", returnType.getRdfType())) //TODO move version number to a property?
                    .build();

            reqSuccessful = true;

        } catch (RMapApiException ex) {
            throw RMapApiException.wrap(ex);
        } catch (RMapDefectiveArgumentException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_GET_AGENT_BAD_ARGUMENT);
        } catch (RMapAgentNotFoundException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_AGENT_OBJECT_NOT_FOUND);
        } catch (RMapException ex) {
            if (ex.getCause() instanceof RMapDeletedObjectException) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_DELETED);
            } else if (ex.getCause() instanceof RMapTombstonedObjectException) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_TOMBSTONED);
            } else if (ex.getCause() instanceof RMapObjectNotFoundException) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_NOT_FOUND);
            } else {
                throw RMapApiException.wrap(ex, ErrorCode.ER_CORE_GENERIC_RMAP_EXCEPTION);
            }
        } catch (Exception ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_UNKNOWN_SYSTEM_ERROR);
        } finally {
            if (rmapService != null)
                rmapService.closeConnection();
            if (!reqSuccessful && response != null)
                response.close();
        }
        return response;
    }

    /**
     * Retrieves status of specific RMap Agent as HTTP response.
     *
     * @param strAgentUri the Agent URI
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getRMapAgentHeader(String strAgentUri) throws RMapApiException {
        boolean reqSuccessful = false;
        Response response = null;
        try {
            if (strAgentUri == null || strAgentUri.length() == 0) {
                throw new RMapApiException(ErrorCode.ER_NO_OBJECT_URI_PROVIDED);
            }

            URI uriAgentId = null;
            try {
                strAgentUri = URLDecoder.decode(strAgentUri, "UTF-8");
                uriAgentId = new URI(strAgentUri);
            } catch (Exception ex) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_PARAM_WONT_CONVERT_TO_URI);
            }

            RMapStatus status = rmapService.getAgentStatus(uriAgentId);
            if (status == null) {
                throw new RMapApiException(ErrorCode.ER_CORE_GET_STATUS_RETURNED_NULL);
            }
            String linkRel = "<" + status.getPath().toString() + ">" + ";rel=\"" + Terms.RMAP_HASSTATUS_PATH + "\"";

            response = Response.status(Response.Status.OK).location(new URI(Utils.makeAgentUrl(strAgentUri)))
                    .header("Link", linkRel) //switch this to link()
                    .build();

            reqSuccessful = true;

        } catch (RMapApiException ex) {
            throw RMapApiException.wrap(ex);
        } catch (RMapDefectiveArgumentException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_GET_AGENT_BAD_ARGUMENT);
        } catch (RMapAgentNotFoundException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_AGENT_OBJECT_NOT_FOUND);
        } catch (RMapException ex) {
            if (ex.getCause() instanceof RMapDeletedObjectException) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_DELETED);
            } else if (ex.getCause() instanceof RMapTombstonedObjectException) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_TOMBSTONED);
            } else if (ex.getCause() instanceof RMapObjectNotFoundException) {
                throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_NOT_FOUND);
            } else {
                throw RMapApiException.wrap(ex, ErrorCode.ER_CORE_GENERIC_RMAP_EXCEPTION);
            }
        } catch (Exception ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_UNKNOWN_SYSTEM_ERROR);
        } finally {
            if (rmapService != null)
                rmapService.closeConnection();
            if (!reqSuccessful && response != null)
                response.close();
        }
        return response;
    }

    /**
     * Retrieves list of RMap:DiSCO URIs that were created by the RMap:Agent URI provided and returns 
     * the results as a JSON or Plain Text list.
     *
     * @param agentUri the Agent URI
     * @param returnType the non-RDF return type
     * @param queryParams the query params
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getRMapAgentDiSCOs(String agentUri, NonRdfType returnType,
            MultivaluedMap<String, String> queryParams) throws RMapApiException {
        return getRMapAgentObjects(agentUri, returnType, queryParams, RMapObjectType.DISCO);
    }

    /**
     * Retrieves list of RMap:Event URIs that were initiated by the RMap:Agent URI provided and returns 
     * the results as a JSON or Plain Text list.
     *
     * @param agentUri the Agent URI
     * @param returnType the non-RDF return type
     * @param queryParams the query params
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getRMapAgentEvents(String agentUri, NonRdfType returnType,
            MultivaluedMap<String, String> queryParams) throws RMapApiException {
        return getRMapAgentObjects(agentUri, returnType, queryParams, RMapObjectType.EVENT);
    }

    /**
     * Retrieves list of RMap:Event or RMap:DiSCO URIs associated with the RMap:Agent URI provided and returns 
     * the results as a JSON or Plain Text list.
     *
     * @param agentUri the Agent URI
     * @param returnType the non-RDF return type
     * @param queryParams the query params
     * @param rmapObjType (will return DISCO or EVENT URIs)
     * @return HTTP Response
     * @throws RMapApiException the RMap API Exception
     */
    public Response getRMapAgentObjects(String agentUri, NonRdfType returnType,
            MultivaluedMap<String, String> queryParams, RMapObjectType rmapObjType) throws RMapApiException {

        boolean reqSuccessful = false;
        Response response = null;
        try {
            if (agentUri == null || agentUri.length() == 0) {
                throw new RMapApiException(ErrorCode.ER_NO_OBJECT_URI_PROVIDED);
            }
            if (returnType == null) {
                returnType = Constants.DEFAULT_NONRDF_TYPE;
            }

            URI uriAgentUri = convertPathStringToURI(agentUri);
            RMapSearchParams params = generateSearchParamObj(queryParams);

            Integer currPage = extractPage(queryParams);
            Integer limit = params.getLimit();
            //we are going to get one extra record to see if we need a "next"
            params.setLimit(limit + 1);

            String path = Utils.makeAgentUrl(agentUri);

            List<URI> uriList = null;
            switch (rmapObjType) {
            case EVENT:
                uriList = rmapService.getAgentEventsInitiated(uriAgentUri, params);
                path = path + "/events";
                break;
            case DISCO:
                uriList = rmapService.getAgentDiSCOs(uriAgentUri, params);
                path = path + "/discos";
                break;
            default: //default to DiSCO
                uriList = rmapService.getAgentDiSCOs(uriAgentUri, params);
                path = path + "/discos";
                break;
            }
            //now that we've run the query, set the limit back to correct value
            params.setLimit(limit);

            if (uriList == null || uriList.size() == 0) {
                //if the object is found, should always have at least one event
                throw new RMapApiException(ErrorCode.ER_CORE_GET_URILIST_EMPTY);
            }

            ResponseBuilder responseBldr = null;

            //if the list is longer than the limit and there is currently no page defined, then do 303 with pagination
            if (!queryParams.containsKey(PAGE_PARAM) && uriList.size() > limit) {
                //start See Other response to indicate need for pagination
                String seeOtherUrl = getPaginatedLinkTemplate(path, queryParams, limit);
                seeOtherUrl = seeOtherUrl.replace(PAGENUM_PLACEHOLDER, FIRST_PAGE);
                responseBldr = Response.status(Response.Status.SEE_OTHER)
                        .entity(ErrorCode.ER_RESPONSE_TOO_LONG_NEED_PAGINATION.getMessage())
                        .location(new URI(seeOtherUrl));
            } else {
                //show results list as normal
                responseBldr = Response.status(Response.Status.OK)
                        .type(HttpTypeMediator.getResponseNonRdfMediaType(returnType));

                //are we doing page links?
                if (uriList.size() > limit || currPage > 1) {
                    String pageLinkTemplate = getPaginatedLinkTemplate(path, queryParams, limit);
                    boolean showNextLink = uriList.size() > limit;
                    String pageLinks = generatePaginationLinks(pageLinkTemplate, currPage, showNextLink);
                    responseBldr.header("Link", pageLinks);
                    if (showNextLink) {
                        //gone over limit so remove the last record since it was only added to check for record that would spill to next page
                        uriList.remove(uriList.size() - 1);
                    }
                }

                String outputString = "";
                if (returnType == NonRdfType.PLAIN_TEXT) {
                    outputString = URIListHandler.uriListToPlainText(uriList);
                } else {
                    outputString = URIListHandler.uriListToJson(uriList, rmapObjType.getPath().toString());
                }
                responseBldr.entity(outputString.toString());
            }

            response = responseBldr.build();

            reqSuccessful = true;

        } catch (RMapApiException ex) {
            throw RMapApiException.wrap(ex);
        } catch (RMapAgentNotFoundException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_AGENT_OBJECT_NOT_FOUND);
        } catch (RMapObjectNotFoundException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_OBJECT_NOT_FOUND);
        } catch (RMapDefectiveArgumentException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_GET_AGENT_BAD_ARGUMENT);
        } catch (RMapException ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_CORE_GENERIC_RMAP_EXCEPTION);
        } catch (Exception ex) {
            throw RMapApiException.wrap(ex, ErrorCode.ER_UNKNOWN_SYSTEM_ERROR);
        } finally {
            if (rmapService != null)
                rmapService.closeConnection();
            if (!reqSuccessful && response != null)
                response.close();
        }
        return response;
    }

}