Java tutorial
/** * Copyright 2014 EBI, University of Zrich, SIB, and others. * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. The ASF licenses this file * to you 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.string_db.psicquic.ws; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpHost; import org.apache.http.client.HttpClient; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.PoolingClientConnectionManager; 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.PsicquicRestService; 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 org.string_db.psicquic.AppProperties; import psidev.psi.mi.calimocho.solr.converter.SolrFieldName; import psidev.psi.mi.xml254.jaxb.EntrySet; import javax.ws.rs.DefaultValue; 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.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) * @author Milan Simonovic (milan.simonovic@imls.uzh.ch) */ @Controller public class StringdbSolrBasedPsicquicRestService implements PsicquicRestService { private final Logger logger = LoggerFactory.getLogger(StringdbSolrBasedPsicquicRestService.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"; // settings SOLRServer public static int maxTotalConnections = 128; public static int defaultMaxConnectionsPerHost = 24; public static int connectionTimeOut = 20000; public static int soTimeOut = 20000; public static boolean allowCompression = true; 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); protected PsicquicSolrServer psicquicSolrServer; @Autowired private PsicquicConfig config; @Override public Object getByInteractor(String interactorAc, @DefaultValue("") String db, @DefaultValue("tab25") String format, @DefaultValue("0") String firstResult, @DefaultValue("2147483647") String maxResults) throws PsicquicServiceException, NotSupportedMethodException, NotSupportedTypeException { String query = SolrFieldName.identifier.toString() + ":" + createQueryValue(interactorAc, db); return getByQuery(query, format, firstResult, maxResults); } @Override public Object getByInteraction(String interactionAc, @DefaultValue("") String db, @DefaultValue("tab25") String format, @DefaultValue("0") String firstResult, @DefaultValue("2147483647") String maxResults) throws PsicquicServiceException, NotSupportedMethodException, NotSupportedTypeException { String query = SolrFieldName.interaction_id.toString() + ":" + createQueryValue(interactionAc, db); return getByQuery(query, format, firstResult, maxResults); } @Override public Object getByQuery(String query, @DefaultValue("tab25") String format, @DefaultValue("0") String firstResultStr, @DefaultValue("2147483647") 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 > XgmmlStreamingOutput.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 > XgmmlStreamingOutput.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, XgmmlStreamingOutput.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 > XgmmlStreamingOutput.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 > XgmmlStreamingOutput.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, XgmmlStreamingOutput.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 (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(); } /** * [Milan]: what's the point of having this lazy eval? * * @return */ public synchronized PsicquicSolrServer getPsicquicSolrServer() { if (psicquicSolrServer == null) { HttpSolrServer solrServer = new HttpSolrServer(AppProperties.instance.solrUrl, createHttpClient()); solrServer.setConnectionTimeout(connectionTimeOut); solrServer.setSoTimeout(soTimeOut); solrServer.setAllowCompression(allowCompression); psicquicSolrServer = new PsicquicSolrServer(solrServer); } return psicquicSolrServer; } protected HttpClient createHttpClient() { SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory())); schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry); cm.setMaxTotal(maxTotalConnections); cm.setDefaultMaxPerRoute(defaultMaxConnectionsPerHost); HttpClient httpClient = new DefaultHttpClient(cm); String proxyHost = config.getProxyHost(); String proxyPort = config.getProxyPort(); if (isValueSet(proxyHost) && proxyHost.trim().length() > 0 && isValueSet(proxyPort) && proxyPort.trim().length() > 0) { try { HttpHost proxy = new HttpHost(proxyHost, Integer.parseInt(proxyPort)); httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); } catch (Exception e) { logger.error("Impossible to create proxy host:" + proxyHost + ", port:" + proxyPort, e); } } return httpClient; } private boolean isValueSet(String value) { return value != null && !value.startsWith("$"); } protected void logQueryIfConfigured(String query) { org.apache.log4j.Logger logger = this.config.getQueryLogger(); if (logger != null && query != null) { logger.info("query: " + query); } } 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(); } }