// BridgeDb, // An abstraction layer for identifier mapping services, both local and online. // // Copyright 2006-2009 BridgeDb developers // Copyright 2012-2013 Christian Y. A. Brenninkmeijer // Copyright 2012-2013 OpenPhacts // // 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.bridgedb.ws; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.log4j.Logger; import org.bridgedb.DataSource; import org.bridgedb.IDMapper; import org.bridgedb.IDMapperCapabilities; import org.bridgedb.IDMapperException; import org.bridgedb.Xref; import org.bridgedb.pairs.SyscodeBasedCodeMapper; import org.bridgedb.sql.SQLIdMapper; import org.bridgedb.utils.BridgeDBException; import org.bridgedb.utils.ConfigReader; import org.bridgedb.ws.bean.CapabilitiesBean; import org.bridgedb.ws.bean.DataSourcesBean; import org.bridgedb.ws.bean.FreeSearchSupportedBean; import org.bridgedb.ws.bean.MappingSupportedBean; import org.bridgedb.ws.bean.PropertiesBean; import org.bridgedb.ws.bean.PropertyBean; import org.bridgedb.ws.bean.XrefExistsBean; import org.bridgedb.ws.bean.XrefMapsBean; import org.bridgedb.ws.bean.XrefsBean; /** * Webservice server code, that uses the ws.core * functionality to expose BridgeDB data * @author Christian Y. A. Brenninkmeijer * */ @Path("/") public class WSCoreService implements WSCoreInterface { static final String NO_CONTENT_ON_EMPTY = "no.content.on.empty"; protected final boolean noContentOnEmpty; static final Logger logger = Logger.getLogger(WSCoreService.class); protected IDMapper idMapper; /** * Default constructor for super classes. * * Super classes will have the responsibilities of setting up the idMapper. */ private WSCoreService() throws BridgeDBException{ this(new SQLIdMapper(false, new SyscodeBasedCodeMapper())); } public WSCoreService(IDMapper idMapper) throws BridgeDBException { this.idMapper = idMapper; String property = ConfigReader.getProperty(NO_CONTENT_ON_EMPTY); noContentOnEmpty = Boolean.valueOf(property); logger.info("WS Service running using supplied idMapper"); } private DataSourcesBean getSupportedSrcDataSourcesInner() throws BridgeDBException { IDMapperCapabilities capabilities = idMapper.getCapabilities(); try { Set<DataSource> dataSources = capabilities.getSupportedSrcDataSources(); return new DataSourcesBean (dataSources); } catch (IDMapperException e){ throw BridgeDBException.convertToBridgeDB(e); } } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.GET_SUPPORTED_SOURCE_DATA_SOURCES) @Override public Response getSupportedSrcDataSources() throws BridgeDBException { DataSourcesBean bean = getSupportedSrcDataSourcesInner(); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.GET_SUPPORTED_SOURCE_DATA_SOURCES) public Response getSupportedSrcDataSourcesJson() throws BridgeDBException { DataSourcesBean bean = getSupportedSrcDataSourcesInner(); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } @GET @Produces({MediaType.TEXT_HTML}) @Path("/" + WsConstants.GET_SUPPORTED_SOURCE_DATA_SOURCES) public Response getSupportedSrcDataSources(@Context HttpServletRequest httpServletRequest) throws BridgeDBException { DataSourcesBean bean = getSupportedSrcDataSourcesInner(); if (noContentOnEmpty & bean.isEmpty()){ noContentWrapper(httpServletRequest); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } private XrefsBean freeSearchInner(String text, String limitString) throws BridgeDBException { if (text == null) { throw new BridgeDBException(WsConstants.TEXT + " parameter missing"); } Set<Xref> mappings; try { if (limitString == null || limitString.isEmpty()){ mappings = idMapper.freeSearch(text, Integer.MAX_VALUE); } else { int limit = Integer.parseInt(limitString); mappings = idMapper.freeSearch(text,limit); } } catch (IDMapperException e){ throw BridgeDBException.convertToBridgeDB(e); } return new XrefsBean(mappings); } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.FREE_SEARCH) @Override public Response freeSearch( @QueryParam(WsConstants.TEXT) String text, @QueryParam(WsConstants.LIMIT) String limitString) throws BridgeDBException { XrefsBean bean = freeSearchInner(text, limitString); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.FREE_SEARCH) public Response freeSearchJson( @QueryParam(WsConstants.TEXT) String text, @QueryParam(WsConstants.LIMIT) String limitString) throws BridgeDBException { XrefsBean bean = freeSearchInner(text, limitString); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } @GET @Produces({MediaType.TEXT_HTML}) @Path("/" + WsConstants.FREE_SEARCH) public Response freeSearch( @QueryParam(WsConstants.TEXT) String text, @QueryParam(WsConstants.LIMIT) String limitString, @Context HttpServletRequest httpServletRequest) throws BridgeDBException { XrefsBean bean = freeSearchInner(text, limitString); if (noContentOnEmpty & bean.isEmpty()){ return noContentWrapper(httpServletRequest); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } private XrefMapsBean mapIDInner(List<String> id, List<String> scrCode, List<String> targetCodes) throws BridgeDBException { if (id == null) { throw new BridgeDBException(WsConstants.ID + " parameter missing"); } if (id.isEmpty()) { throw new BridgeDBException(WsConstants.ID + " parameter missing"); } if (scrCode == null) { throw new BridgeDBException(WsConstants.DATASOURCE_SYSTEM_CODE + " parameter missing"); } if (scrCode.isEmpty()) { throw new BridgeDBException(WsConstants.DATASOURCE_SYSTEM_CODE + " parameter missing"); } if (id.size() != scrCode.size()) { throw new BridgeDBException("Must have same number of " + WsConstants.ID + " and " + WsConstants.DATASOURCE_SYSTEM_CODE + " parameters"); } ArrayList<Xref> srcXrefs = new ArrayList<Xref>(); for (int i = 0; i < id.size() ;i++){ try { DataSource dataSource = DataSource.getExistingBySystemCode(scrCode.get(i)); Xref source = new Xref(id.get(i), dataSource); srcXrefs.add(source); } catch (IllegalArgumentException ex){ logger.error(ex.getMessage()); } } DataSource[] targetDataSources = new DataSource[targetCodes.size()]; for (int i=0; i< targetCodes.size(); i++){ targetDataSources[i] = DataSource.getExistingBySystemCode(targetCodes.get(i)); } try { Map<Xref, Set<Xref>> mappings = idMapper.mapID(srcXrefs, targetDataSources); return new XrefMapsBean(mappings); } catch (IDMapperException e){ throw BridgeDBException.convertToBridgeDB(e); } } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.MAP_ID) @Override public Response mapID( @QueryParam(WsConstants.ID) List<String> id, @QueryParam(WsConstants.DATASOURCE_SYSTEM_CODE) List<String> scrCode, @QueryParam(WsConstants.TARGET_DATASOURCE_SYSTEM_CODE) List<String> targetCodes) throws BridgeDBException { XrefMapsBean bean = mapIDInner(id, scrCode, targetCodes); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.MAP_ID) public Response mapIDJson( @QueryParam(WsConstants.ID) List<String> id, @QueryParam(WsConstants.DATASOURCE_SYSTEM_CODE) List<String> scrCode, @QueryParam(WsConstants.TARGET_DATASOURCE_SYSTEM_CODE) List<String> targetCodes) throws BridgeDBException { XrefMapsBean bean = mapIDInner(id, scrCode, targetCodes); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } @GET @Produces({MediaType.TEXT_HTML}) @Path("/" + WsConstants.MAP_ID) public Response mapID( @QueryParam(WsConstants.ID) List<String> id, @QueryParam(WsConstants.DATASOURCE_SYSTEM_CODE) List<String> scrCode, @QueryParam(WsConstants.TARGET_DATASOURCE_SYSTEM_CODE) List<String> targetCodes, @Context HttpServletRequest httpServletRequest) throws BridgeDBException { XrefMapsBean bean = mapIDInner(id, scrCode, targetCodes); if (noContentOnEmpty & bean.isEmpty()){ return noContentWrapper(httpServletRequest); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } private XrefExistsBean xrefExistsInner(String id, String scrCode) throws BridgeDBException { if (id == null) { throw new BridgeDBException (WsConstants.ID + " parameter can not be null"); } if (scrCode == null) { throw new BridgeDBException (WsConstants.DATASOURCE_SYSTEM_CODE + " parameter can not be null"); } DataSource dataSource; try { dataSource = DataSource.getExistingBySystemCode(scrCode); } catch (IllegalArgumentException ex){ logger.error(ex.getMessage()); return new XrefExistsBean(id, scrCode, false); } Xref source = new Xref(id, dataSource); try { return new XrefExistsBean(source, idMapper.xrefExists(source)); } catch (IDMapperException e){ throw BridgeDBException.convertToBridgeDB(e); } } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.XREF_EXISTS) @Override public Response xrefExists( @QueryParam(WsConstants.ID) String id, @QueryParam(WsConstants.DATASOURCE_SYSTEM_CODE) String scrCode) throws BridgeDBException { XrefExistsBean bean = xrefExistsInner(id, scrCode); return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.XREF_EXISTS) public Response xrefExistsJson( @QueryParam(WsConstants.ID) String id, @QueryParam(WsConstants.DATASOURCE_SYSTEM_CODE) String scrCode) throws BridgeDBException { XrefExistsBean bean = xrefExistsInner(id, scrCode); return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } private DataSourcesBean getSupportedTgtDataSourcesInner() throws BridgeDBException { try { Set<DataSource> dataSources = idMapper.getCapabilities().getSupportedSrcDataSources(); return new DataSourcesBean(dataSources); } catch (IDMapperException e){ throw BridgeDBException.convertToBridgeDB(e); } } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.GET_SUPPORTED_TARGET_DATA_SOURCES) @Override public Response getSupportedTgtDataSources() throws BridgeDBException { DataSourcesBean bean = getSupportedTgtDataSourcesInner(); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.GET_SUPPORTED_TARGET_DATA_SOURCES) public Response getSupportedTgtDataSourcesJson() throws BridgeDBException { DataSourcesBean bean = getSupportedTgtDataSourcesInner(); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } @GET @Produces({MediaType.TEXT_HTML}) @Path("/" + WsConstants.GET_SUPPORTED_TARGET_DATA_SOURCES) public Response getSupportedTgtDataSources(@Context HttpServletRequest httpServletRequest) throws BridgeDBException { DataSourcesBean bean = getSupportedTgtDataSourcesInner(); if (noContentOnEmpty & bean.isEmpty()){ return noContentWrapper(httpServletRequest); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_XML}) @Path(WsConstants.IS_FREE_SEARCH_SUPPORTED) @Override public Response isFreeSearchSupported() { FreeSearchSupportedBean bean = new FreeSearchSupportedBean(idMapper.getCapabilities().isFreeSearchSupported()); //FreeSearchSupported is never empty so never no context return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path(WsConstants.IS_FREE_SEARCH_SUPPORTED) public Response isFreeSearchSupportedJson() { FreeSearchSupportedBean bean = new FreeSearchSupportedBean(idMapper.getCapabilities().isFreeSearchSupported()); //FreeSearchSupported is never empty so never no context return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } private MappingSupportedBean isMappingSupportedInner(String sourceCode, String targetCode) throws BridgeDBException { if (sourceCode == null) { throw new BridgeDBException (WsConstants.SOURCE_DATASOURCE_SYSTEM_CODE + " parameter can not be null"); } if (targetCode == null) { throw new BridgeDBException (WsConstants.TARGET_DATASOURCE_SYSTEM_CODE + " parameter can not be null"); } DataSource src = DataSource.getExistingBySystemCode(sourceCode); DataSource tgt = DataSource.getExistingBySystemCode(targetCode); try { return new MappingSupportedBean(src, tgt, idMapper.getCapabilities().isMappingSupported(src, tgt)); } catch (IDMapperException e){ throw BridgeDBException.convertToBridgeDB(e); } } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.IS_MAPPING_SUPPORTED) @Override public Response isMappingSupported( @QueryParam(WsConstants.SOURCE_DATASOURCE_SYSTEM_CODE) String sourceCode, @QueryParam(WsConstants.TARGET_DATASOURCE_SYSTEM_CODE) String targetCode) throws BridgeDBException { MappingSupportedBean bean = isMappingSupportedInner(sourceCode, targetCode); //MappingSupported is never empty so never no content return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.IS_MAPPING_SUPPORTED) public Response isMappingSupportedJson( @QueryParam(WsConstants.SOURCE_DATASOURCE_SYSTEM_CODE) String sourceCode, @QueryParam(WsConstants.TARGET_DATASOURCE_SYSTEM_CODE) String targetCode) throws BridgeDBException { MappingSupportedBean bean = isMappingSupportedInner(sourceCode, targetCode); //MappingSupported is never empty so never no content return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } private PropertyBean getPropertyInner(String key) { String property = idMapper.getCapabilities().getProperty(key); return new PropertyBean(key, property); } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.PROPERTY + "/{key}") @Override public Response getProperty(@PathParam("key")String key) { PropertyBean bean = getPropertyInner(key); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.PROPERTY + "/{key}") public Response getPropertyJson(@PathParam("key")String key) { PropertyBean bean = getPropertyInner(key); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.PROPERTY + "/{key}") public Response getProperty(@PathParam("key")String key, @Context HttpServletRequest httpServletRequest) throws BridgeDBException { PropertyBean bean = getPropertyInner(key); if (noContentOnEmpty & bean.isEmpty()){ return noContentWrapper(httpServletRequest); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } private PropertiesBean getKeysInner() { PropertiesBean bean = new PropertiesBean(); Set<String> keys = idMapper.getCapabilities().getKeys(); IDMapperCapabilities idMapperCapabilities = idMapper.getCapabilities(); for (String key:keys){ bean.addProperty(key, idMapperCapabilities.getProperty(key)); } return bean; } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.GET_KEYS) @Override public Response getKeys() { PropertiesBean bean = getKeysInner(); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.GET_KEYS) public Response getKeysJson() { PropertiesBean bean = getKeysInner(); if (noContentOnEmpty & bean.isEmpty()){ return Response.noContent().build(); } return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } @GET @Produces({MediaType.TEXT_HTML}) @Path("/" + WsConstants.GET_KEYS) public Response getKeys(@Context HttpServletRequest httpServletRequest) throws BridgeDBException { PropertiesBean bean = getKeysInner(); if (noContentOnEmpty & bean.isEmpty()){ return noContentWrapper(httpServletRequest); } return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_XML}) @Path("/" + WsConstants.GET_CAPABILITIES) @Override public Response getCapabilities() { CapabilitiesBean bean = new CapabilitiesBean(idMapper.getCapabilities()); return Response.ok(bean, MediaType.APPLICATION_XML_TYPE).build(); } @GET @Produces({MediaType.APPLICATION_JSON}) @Path("/" + WsConstants.GET_CAPABILITIES) public Response getCapabilitiesJson() { CapabilitiesBean bean = new CapabilitiesBean(idMapper.getCapabilities()); return Response.ok(bean, MediaType.APPLICATION_JSON_TYPE).build(); } /** * Simple warning that no Context was found. * * Can be overwritten with nicer page * @param httpServletRequest Used by super classes * @return * @throws BridgeDBException thrown by super classes */ protected Response noContentWrapper(HttpServletRequest httpServletRequest) { StringBuilder sb = new StringBuilder(); sb.append("<?xml version=\"1.0\"?>"); sb.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "); sb.append("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); sb.append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">"); sb.append("<meta http-equiv=\"content-type\" content=\"text/html; charset=ISO-8859-1\"/>"); sb.append("<head>\n"); sb.append("<title>No Results found</title>\n"); sb.append("</head>\n<body>\n"); sb.append("<h1>Sorry no results found!</h1>\n"); sb.append("<h2>The parameters provided resulted in an empty set.</h2>\n"); sb.append("<h3>No exception was thrown so the parameters where valid just too restrictive.</h3>\n"); sb.append("<h2>XML and json version return status 204 in this case</h2>\n"); sb.append("</body></html>"); return Response.ok(sb.toString(), MediaType.TEXT_HTML).build(); } }