org.hupo.psi.mi.psicquic.ws.SolrBasedPsicquicRestService.java Source code

Java tutorial

Introduction

Here is the source code for org.hupo.psi.mi.psicquic.ws.SolrBasedPsicquicRestService.java

Source

/**
 * Copyright 2008 The European Bioinformatics Institute, and others.
 *
 * 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.
 */
package org.hupo.psi.mi.psicquic.ws;

import org.apache.commons.lang.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.hupo.psi.mi.psicquic.NotSupportedMethodException;
import org.hupo.psi.mi.psicquic.NotSupportedTypeException;
import org.hupo.psi.mi.psicquic.PsicquicServiceException;
import org.hupo.psi.mi.psicquic.model.PsicquicSearchResults;
import org.hupo.psi.mi.psicquic.model.PsicquicSolrServer;
import org.hupo.psi.mi.psicquic.ws.config.PsicquicConfig;
import org.hupo.psi.mi.psicquic.ws.utils.PsicquicConverterUtils;
import org.hupo.psi.mi.psicquic.ws.utils.PsicquicStreamingOutput;
import org.hupo.psi.mi.psicquic.ws.utils.XgmmlStreamingOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import psidev.psi.mi.calimocho.solr.converter.SolrFieldName;
import psidev.psi.mi.xml254.jaxb.EntrySet;

import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * This web service is based on a PSIMITAB SOLR index to search and return the results.
 *
 * @author Marine Dumousseau (marine@ebi.ac.uk)
 * @version $Id: IntactPsicquicService.java 12873 2009-03-18 02:51:31Z baranda $
 */
@Controller
public class SolrBasedPsicquicRestService implements PsicquicRestService {

    private final Logger logger = LoggerFactory.getLogger(SolrBasedPsicquicRestService.class);

    public static final String RETURN_TYPE_XML25 = "xml25";
    public static final String RETURN_TYPE_MITAB25 = "tab25";
    public static final String RETURN_TYPE_MITAB26 = "tab26";
    public static final String RETURN_TYPE_MITAB27 = "tab27";
    public static final String RETURN_TYPE_BIOPAX = "biopax";
    public static final String RETURN_TYPE_BIOPAX_L2 = "biopax-L2";
    public static final String RETURN_TYPE_BIOPAX_L3 = "biopax-L3";
    public static final String RETURN_TYPE_XGMML = "xgmml";
    public static final String RETURN_TYPE_RDF_XML = "rdf-xml";
    public static final String RETURN_TYPE_RDF_XML_ABBREV = "rdf-xml-abbrev";
    public static final String RETURN_TYPE_RDF_N3 = "rdf-n3";
    public static final String RETURN_TYPE_RDF_TURTLE = "rdf-turtle";
    public static final String RETURN_TYPE_COUNT = "count";
    protected static final int MAX_XGMML_INTERACTIONS = 5000;

    @Autowired
    private PsicquicConfig config;

    protected PsicquicSolrServer psicquicSolrServer;

    public static final List<String> SUPPORTED_REST_RETURN_TYPES = Arrays.asList(RETURN_TYPE_XML25,
            RETURN_TYPE_MITAB25, RETURN_TYPE_MITAB26, RETURN_TYPE_MITAB27, RETURN_TYPE_BIOPAX, RETURN_TYPE_XGMML,
            RETURN_TYPE_RDF_XML, RETURN_TYPE_RDF_XML_ABBREV, RETURN_TYPE_RDF_N3, RETURN_TYPE_RDF_TURTLE,
            RETURN_TYPE_COUNT, RETURN_TYPE_BIOPAX_L2, RETURN_TYPE_BIOPAX_L3);

    public SolrBasedPsicquicRestService() {
    }

    public synchronized PsicquicSolrServer getPsicquicSolrServer() {
        if (psicquicSolrServer == null) {
            HttpSolrServer solrServer = new HttpSolrServer(config.getSolrUrl(), createHttpClient());

            psicquicSolrServer = new PsicquicSolrServer(solrServer);
        }

        return psicquicSolrServer;

    }

    protected void logQueryIfConfigured(String query) {
        org.apache.log4j.Logger logger = this.config.getQueryLogger();

        if (logger != null && query != null) {
            logger.info("query: " + query);
        }
    }

    public Response getByInteractor(String interactorAc, String db, String format, String firstResult,
            String maxResults)
            throws PsicquicServiceException, NotSupportedMethodException, NotSupportedTypeException {
        String query = SolrFieldName.identifier.toString() + ":" + createQueryValue(interactorAc, db);
        return getByQuery(query, format, firstResult, maxResults);
    }

    public Response getByInteraction(String interactionAc, String db, String format, String firstResult,
            String maxResults)
            throws PsicquicServiceException, NotSupportedMethodException, NotSupportedTypeException {
        String query = SolrFieldName.interaction_id.toString() + ":" + createQueryValue(interactionAc, db);
        return getByQuery(query, format, firstResult, maxResults);
    }

    public Response getByQuery(String query, String format, String firstResultStr, String maxResultsStr)
            throws PsicquicServiceException, NotSupportedMethodException, NotSupportedTypeException {
        if (query == null)
            throw new NullPointerException("Null query");

        logQueryIfConfigured(query);

        PsicquicSolrServer psicquicSolrServer = getPsicquicSolrServer();

        int firstResult;
        int maxResults;

        try {
            firstResult = Integer.parseInt(firstResultStr);
        } catch (NumberFormatException e) {
            throw new PsicquicServiceException("firstResult parameter is not a number: " + firstResultStr);
        }

        try {
            if (maxResultsStr == null) {
                maxResults = Integer.MAX_VALUE - firstResult;
            } else {
                maxResults = Integer.parseInt(maxResultsStr);
            }
        } catch (NumberFormatException e) {
            throw new PsicquicServiceException("maxResults parameter is not a number: " + maxResultsStr);
        }

        format = format.toLowerCase();

        try {
            if (RETURN_TYPE_XML25.equalsIgnoreCase(format)) {

                // Maximum of 500 results to be exported in XML otherwise exception
                if (maxResults > SolrBasedPsicquicService.BLOCKSIZE_MAX) {
                    // check that total number of results is less than 500, otherwise throw an Exception
                    PsicquicSearchResults results = psicquicSolrServer.searchWithFilters(query, 0, 0,
                            PsicquicSolrServer.RETURN_TYPE_COUNT, new String[] { config.getQueryFilter() });

                    long total = results.getNumberResults();
                    // check that remaining number of results is less than 500. If not, throw an exception
                    if (total - firstResult > SolrBasedPsicquicService.BLOCKSIZE_MAX) {
                        return Response.status(400).type(MediaType.TEXT_PLAIN).entity(
                                "Too many results to return in XML. Please use a more specific search or reduce the maxResults parameter to 500 and use pagination in your query.")
                                .build();
                    }
                }

                PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, firstResult, maxResults,
                        PsicquicSolrServer.RETURN_TYPE_XML25, config.getQueryFilter());

                final EntrySet entrySet = PsicquicConverterUtils.extractJaxbEntrySetFromPsicquicResults(
                        psicquicResults, query, maxResults, SolrBasedPsicquicService.BLOCKSIZE_MAX);
                long count = psicquicResults.getNumberResults();

                return prepareResponse(Response.status(200).type(MediaType.APPLICATION_XML),
                        new GenericEntity<EntrySet>(entrySet) {
                        }, count).build();
            } else if ((format.toLowerCase().startsWith("rdf") && format.length() > 5)
                    || format.toLowerCase().startsWith("biopax") || format.toLowerCase().startsWith("biopax-L3")
                    || format.toLowerCase().startsWith("biopax-L2")) {
                // Maximum of 500 results to be exported in RDF or Biopax otherwise exception
                if (maxResults > SolrBasedPsicquicService.BLOCKSIZE_MAX) {
                    // check that total number of results is less than 500, otherwise throw an Exception
                    PsicquicSearchResults results = psicquicSolrServer.searchWithFilters(query, 0, 0,
                            PsicquicSolrServer.RETURN_TYPE_COUNT, new String[] { config.getQueryFilter() });

                    long total = results.getNumberResults();
                    // check that remaining number of results is less than 500. If not, throw an exception
                    if (total - firstResult > SolrBasedPsicquicService.BLOCKSIZE_MAX) {
                        return Response.status(400).type(MediaType.TEXT_PLAIN)
                                .entity("Too many results to return in " + format
                                        + ". Please use a more specific search or reduce the maxResults parameter to 500 and use pagination in your query.")
                                .build();
                    }
                }
                // Maximum of 500 results to be exported in RDF or biopax
                PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, firstResult,
                        Math.min(maxResults, SolrBasedPsicquicService.BLOCKSIZE_MAX),
                        PsicquicSolrServer.RETURN_TYPE_MITAB27, config.getQueryFilter());

                InputStream rdf = psicquicResults.createRDFOrBiopax(format);
                String mediaType = (format.contains("xml") || format.toLowerCase().startsWith("biopax"))
                        ? MediaType.APPLICATION_XML
                        : MediaType.TEXT_PLAIN;

                return prepareResponse(Response.status(200).type(mediaType), new GenericEntity<InputStream>(rdf) {
                }, psicquicResults.getNumberResults()).build();

            } else {
                long count = 0;

                if (RETURN_TYPE_COUNT.equalsIgnoreCase(format)) {
                    PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, 0, 0,
                            PsicquicSolrServer.RETURN_TYPE_COUNT, config.getQueryFilter());

                    return prepareResponse(Response.status(200).type(MediaType.TEXT_PLAIN),
                            new GenericEntity<Long>(psicquicResults.getNumberResults()) {
                            }, psicquicResults.getNumberResults()).build();
                } else if (RETURN_TYPE_XGMML.equalsIgnoreCase(format)) {
                    PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, 0, 0,
                            PsicquicSolrServer.RETURN_TYPE_COUNT, config.getQueryFilter());

                    count = psicquicResults.getNumberResults();

                    String fixedQuery = query;
                    if (fixedQuery.contains("&")) {
                        fixedQuery = query.substring(0, query.indexOf("&"));
                    }
                    fixedQuery = fixedQuery.replaceAll("q=", "");
                    fixedQuery = fixedQuery.replaceAll(":", "_");
                    fixedQuery = fixedQuery.replaceAll(" ", "_");
                    fixedQuery = fixedQuery.replaceAll("\\(", "");
                    fixedQuery = fixedQuery.replaceAll("\\)", "");

                    String name = fixedQuery.substring(0, Math.min(10, fixedQuery.length())) + ".xgmml";

                    XgmmlStreamingOutput xgmml = new XgmmlStreamingOutput(psicquicSolrServer, query, firstResult,
                            maxResults, PsicquicSolrServer.RETURN_TYPE_MITAB27,
                            new String[] { config.getQueryFilter() }, (int) count);

                    Response resp = prepareResponse(
                            Response.status(200).type(MediaType.APPLICATION_XML).header("Content-Disposition",
                                    "attachment; filename=" + name),
                            new GenericEntity<XgmmlStreamingOutput>(xgmml) {
                            }, count).build();

                    return resp;
                } else if (RETURN_TYPE_MITAB25.equalsIgnoreCase(format) || format == null) {
                    PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, 0, 0,
                            PsicquicSolrServer.RETURN_TYPE_COUNT, config.getQueryFilter());

                    PsicquicStreamingOutput psicquicStreaming = new PsicquicStreamingOutput(psicquicSolrServer,
                            query, firstResult, maxResults, PsicquicSolrServer.RETURN_TYPE_MITAB25,
                            new String[] { config.getQueryFilter() });
                    return prepareResponse(Response.status(200).type(MediaType.TEXT_PLAIN),
                            new GenericEntity<PsicquicStreamingOutput>(psicquicStreaming) {
                            }, psicquicResults.getNumberResults()).build();
                } else if (RETURN_TYPE_MITAB26.equalsIgnoreCase(format)) {
                    PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, firstResult,
                            maxResults, PsicquicSolrServer.RETURN_TYPE_COUNT, config.getQueryFilter());

                    PsicquicStreamingOutput psicquicStreaming = new PsicquicStreamingOutput(psicquicSolrServer,
                            query, firstResult, maxResults, PsicquicSolrServer.RETURN_TYPE_MITAB26,
                            new String[] { config.getQueryFilter() });
                    return prepareResponse(Response.status(200).type(MediaType.TEXT_PLAIN),
                            new GenericEntity<PsicquicStreamingOutput>(psicquicStreaming) {
                            }, psicquicResults.getNumberResults()).build();
                } else if (RETURN_TYPE_MITAB27.equalsIgnoreCase(format)) {
                    PsicquicSearchResults psicquicResults = psicquicSolrServer.search(query, 0, 0,
                            PsicquicSolrServer.RETURN_TYPE_COUNT, config.getQueryFilter());

                    PsicquicStreamingOutput psicquicStreaming = new PsicquicStreamingOutput(psicquicSolrServer,
                            query, firstResult, maxResults, PsicquicSolrServer.RETURN_TYPE_MITAB27,
                            new String[] { config.getQueryFilter() });
                    return prepareResponse(Response.status(200).type(MediaType.TEXT_PLAIN),
                            new GenericEntity<PsicquicStreamingOutput>(psicquicStreaming) {
                            }, psicquicResults.getNumberResults()).build();
                } else {
                    return formatNotSupportedResponse(format);
                }
            }
        } catch (InterruptedIOException e) {
            return Response.status(503).type(MediaType.TEXT_PLAIN)
                    .entity(new GenericEntity<String>("Service unavailable. Please try later.") {
                    }).build();
        } catch (SolrServerException e) {
            return Response.status(503).type(MediaType.TEXT_PLAIN)
                    .entity(new GenericEntity<String>("Service unavailable. Please try later.") {
                    }).build();
        } catch (Throwable e) {
            throw new PsicquicServiceException("Problem creating output", e);
        }

    }

    protected Response formatNotSupportedResponse(String format) {
        return Response.status(406).type(MediaType.TEXT_PLAIN)
                .entity(new GenericEntity<String>("Format not supported: " + format) {
                }).build();
    }

    protected Response.ResponseBuilder prepareResponse(Response.ResponseBuilder responseBuilder, Object entity,
            long totalCount) throws IOException {
        responseBuilder.entity(entity);

        prepareHeaders(responseBuilder).header("X-PSICQUIC-Count", String.valueOf(totalCount));

        return responseBuilder;
    }

    public Response.ResponseBuilder prepareHeaders(Response.ResponseBuilder responseBuilder) {
        responseBuilder.header("X-PSICQUIC-Impl", config.getImplementationName());
        responseBuilder.header("X-PSICQUIC-Impl-Version", config.getVersion());
        responseBuilder.header("X-PSICQUIC-Spec-Version", config.getRestSpecVersion());
        responseBuilder.header("X-PSICQUIC-Supports-Formats", StringUtils.join(SUPPORTED_REST_RETURN_TYPES, ", "));

        return responseBuilder;
    }

    public Object getSupportedFormats()
            throws PsicquicServiceException, NotSupportedMethodException, NotSupportedTypeException {
        return Response.status(200).type(MediaType.TEXT_PLAIN)
                .entity(new GenericEntity<String>(StringUtils.join(SUPPORTED_REST_RETURN_TYPES, "\n")) {
                }).build();
    }

    public Object getProperty(String propertyName) {
        final String val = config.getProperties().get(propertyName);

        if (val == null) {
            return Response.status(404).type(MediaType.TEXT_PLAIN)
                    .entity(new GenericEntity<String>("Property not found: " + propertyName) {
                    }).build();
        }

        return Response.status(200).type(MediaType.TEXT_PLAIN).entity(new GenericEntity<String>(val) {
        }).build();
    }

    public Response getProperties() {
        StringBuilder sb = new StringBuilder(256);

        for (Map.Entry entry : config.getProperties().entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
        }

        return Response.status(200).type(MediaType.TEXT_PLAIN).entity(new GenericEntity<String>(sb.toString()) {
        }).build();
    }

    public String getVersion() {
        return config.getVersion();
    }

    private String createQueryValue(String interactorAc, String db) {
        StringBuilder sb = new StringBuilder(256);
        if (db != null && db.length() > 0) {
            sb.append(db);

            if (interactorAc != null && interactorAc.length() > 0) {
                sb.append(':').append(interactorAc);
            }
        } else {
            sb.append(interactorAc);
        }
        return sb.toString();
    }

    protected HttpClient createHttpClient() {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(SolrBasedPsicquicService.maxTotalConnections);
        cm.setDefaultMaxPerRoute(SolrBasedPsicquicService.defaultMaxConnectionsPerHost);

        RequestConfig.Builder requestBuilder = RequestConfig.custom();
        requestBuilder = requestBuilder.setConnectTimeout(SolrBasedPsicquicService.connectionTimeOut);
        requestBuilder = requestBuilder.setSocketTimeout(SolrBasedPsicquicService.soTimeOut);

        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setDefaultRequestConfig(requestBuilder.build());
        builder.setConnectionManager(cm);

        return builder.build();
    }

    private boolean isValueSet(String value) {
        return value != null && !value.startsWith("$");
    }

}