package org.bridgedb.rdb; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.bridgedb.AbstractIDMapperCapabilities; import org.bridgedb.DataSource; import org.bridgedb.IDMapperCapabilities; import org.bridgedb.IDMapperException; import org.bridgedb.Xref; import org.bridgedb.impl.InternalUtils; /** * Some methods and constants that are shared between SimpleGdbImpl2 and SimpleGdbImpl3 */ public abstract class SimpleGdbImplCommon extends SimpleGdb { SimpleGdbImplCommon(String dbName, String connectionString) throws IDMapperException { super(dbName, connectionString); caps = new SimpleGdbCapabilities(); } final SimpleGdb.QueryLifeCycle qDatasources = new SimpleGdb.QueryLifeCycle( "SELECT codeRight FROM link GROUP BY codeRight" ); final SimpleGdb.QueryLifeCycle qInfo = new SimpleGdb.QueryLifeCycle( "SELECT * FROM info" ); final SimpleGdb.QueryLifeCycle qXrefExists = new SimpleGdb.QueryLifeCycle( "SELECT id FROM " + "datanode" + " WHERE " + "id = ? AND code = ?" ); final SimpleGdb.QueryLifeCycle qAttribute = new SimpleGdb.QueryLifeCycle( "SELECT attrvalue FROM attribute " + " WHERE id = ? AND code = ? AND attrname = ?" ); final SimpleGdb.QueryLifeCycle qAllAttributes = new SimpleGdb.QueryLifeCycle( "SELECT attrname, attrvalue FROM attribute " + " WHERE id = ? AND code = ?" ); final SimpleGdb.QueryLifeCycle qAttributesSet = new SimpleGdb.QueryLifeCycle( "SELECT attrname FROM attribute GROUP BY attrname" ); final SimpleGdb.QueryLifeCycle qCrossRefs = new SimpleGdb.QueryLifeCycle ( "SELECT dest.idRight, dest.codeRight FROM link AS src JOIN link AS dest " + "ON src.idLeft = dest.idLeft and src.codeLeft = dest.codeLeft " + "WHERE src.idRight = ? AND src.codeRight = ?" ); final SimpleGdb.QueryLifeCycle qCrossRefsWithCode = new SimpleGdb.QueryLifeCycle ( "SELECT dest.idRight, dest.codeRight FROM link AS src JOIN link AS dest " + "ON src.idLeft = dest.idLeft and src.codeLeft = dest.codeLeft " + "WHERE src.idRight = ? AND src.codeRight = ? AND dest.codeRight = ?" ); final SimpleGdb.QueryLifeCycle qRefsByAttribute = new SimpleGdb.QueryLifeCycle ( "SELECT datanode.id, datanode.code FROM datanode " + " LEFT JOIN attribute ON attribute.code = datanode.code AND attribute.id = datanode.id " + "WHERE attrName = ? AND attrValue = ?" ); final SimpleGdb.QueryLifeCycle qFreeSearch = new SimpleGdb.QueryLifeCycle ( "SELECT id, code FROM datanode WHERE " + "LOWER(ID) LIKE ?" ); final SimpleGdb.QueryLifeCycle qAttributeSearch = new SimpleGdb.QueryLifeCycle ( "SELECT id, code, attrvalue FROM attribute WHERE " + "attrname = ? AND LOWER(attrvalue) LIKE ?" ); final SimpleGdb.QueryLifeCycle qIdSearchWithAttributes = new SimpleGdb.QueryLifeCycle ( "SELECT id, code, attrvalue FROM attribute WHERE " + "attrname = ? AND LOWER(ID) LIKE ?" ); final SimpleGdb.QueryLifeCycle qAllXrefs = new SimpleGdb.QueryLifeCycle( "SELECT id, code FROM datanode" ); final SimpleGdb.QueryLifeCycle qAllXrefsByDatasource = new SimpleGdb.QueryLifeCycle( "SELECT id, code FROM datanode WHERE code = ?" ); /** {@inheritDoc} */ public boolean xrefExists(Xref xref) throws IDMapperException { if (xref.getDataSource() == null) return false; final QueryLifeCycle pst = qXrefExists; synchronized (pst) { try { pst.init(); pst.setString(1, xref.getId()); pst.setString(2, xref.getDataSource().getSystemCode()); ResultSet r = pst.executeQuery(); while(r.next()) { return true; } } catch (SQLException e) { throw new IDMapperException (e); } finally {pst.cleanup(); } return false; } } /** * Read the info table and return as properties. * @return a map where keys are column names and values are the fields in the first row. * @throws IDMapperException when the database became unavailable */ Map<String, String> getInfo() throws IDMapperException { Map<String, String> result = new HashMap<String, String>(); final QueryLifeCycle pst = qInfo; synchronized (pst) { try { pst.init(); ResultSet rs = pst.executeQuery(); if (rs.next()) { ResultSetMetaData rsmd = rs.getMetaData(); for (int i = 1; i <= rsmd.getColumnCount(); ++i) { String key = rsmd.getColumnName(i); String val = rs.getString(i); result.put (key, val); } } } catch (SQLException ex) { throw new IDMapperException (ex); } return result; } } /** {@inheritDoc} */ public Set<Xref> mapID (Xref idc, DataSource... resultDs) throws IDMapperException { final QueryLifeCycle pst = resultDs.length != 1 ? qCrossRefs : qCrossRefsWithCode; Set<Xref> refs = new HashSet<Xref>(); if (idc.getDataSource() == null) return refs; synchronized (pst) { try { pst.init(); pst.setString(1, idc.getId()); pst.setString(2, idc.getDataSource().getSystemCode()); if (resultDs.length == 1) pst.setString(3, resultDs[0].getSystemCode()); Set<DataSource> dsFilter = new HashSet<DataSource>(Arrays.asList(resultDs)); ResultSet rs = pst.executeQuery(); while (rs.next()) { DataSource ds = DataSource.getExistingBySystemCode(rs.getString(2)); if (resultDs.length == 0 || dsFilter.contains(ds)) { refs.add (new Xref (rs.getString(1), ds)); } } } catch (SQLException e) { throw new IDMapperException (e); } finally {pst.cleanup(); } return refs; } } /** {@inheritDoc} */ public List<Xref> getCrossRefsByAttribute(String attrName, String attrValue) throws IDMapperException { // Logger.log.trace("Fetching cross references by attribute: " + attrName + " = " + attrValue); List<Xref> refs = new ArrayList<Xref>(); final QueryLifeCycle pst = qRefsByAttribute; synchronized (pst) { try { pst.init(); pst.setString(1, attrName); pst.setString(2, attrValue); ResultSet r = pst.executeQuery(); while(r.next()) { Xref ref = new Xref(r.getString(1), DataSource.getExistingBySystemCode(r.getString(2))); refs.add(ref); } } catch(SQLException e) { throw new IDMapperException (e); } finally {pst.cleanup(); } // Logger.log.trace("End fetching cross references by attribute"); return refs; } } /** {@inheritDoc} */ public Set<Xref> freeSearch (String text, int limit) throws IDMapperException { Set<Xref> result = new HashSet<Xref>(); final QueryLifeCycle pst = qFreeSearch; synchronized (pst) { try { pst.init(limit); pst.setString(1, "%" + text.toLowerCase() + "%"); ResultSet r = pst.executeQuery(); while(r.next()) { String id = r.getString(1); DataSource ds = DataSource.getExistingBySystemCode(r.getString(2)); Xref ref = new Xref (id, ds); result.add (ref); } } catch (SQLException e) { throw new IDMapperException(e); } finally {pst.cleanup(); } return result; } } /** * @return a list of data sources present in this database. @throws IDMapperException when the database is unavailable */ private Set<DataSource> getDataSources() throws IDMapperException { Set<DataSource> result = new HashSet<DataSource>(); final QueryLifeCycle pst = qDatasources; synchronized (pst) { try { pst.init(); ResultSet rs = pst.executeQuery(); while (rs.next()) { String syscode = rs.getString(1); if (DataSource.systemCodeExists(syscode)) { DataSource ds = DataSource.getExistingBySystemCode(syscode); result.add (ds); } else { DataSource ds = DataSource.register(syscode, "Unknown data source").asDataSource(); result.add (ds); } } } catch (SQLException ignore) { throw new IDMapperException(ignore); } finally {pst.cleanup(); } return result; } } private final IDMapperCapabilities caps; class SimpleGdbCapabilities extends AbstractIDMapperCapabilities { /** default constructor. * @throws IDMapperException when database is not available */ public SimpleGdbCapabilities() throws IDMapperException { super (SimpleGdbImplCommon.this.getDataSources(), true, SimpleGdbImplCommon.this.getInfo()); } } /** * @return the capabilities of this gene database */ public IDMapperCapabilities getCapabilities() { return caps; } /** * * @return true */ public boolean isFreeAttributeSearchSupported() { return true; } /** * free text search for matching symbols. * @return references that match the query * @param query The text to search for * @param attrType the attribute to look for, e.g. 'Symbol' or 'Description'. * @param limit The number of results to limit the search to * @throws IDMapperException if the mapping service is (temporarily) unavailable */ public Map<Xref, String> freeAttributeSearch (String query, String attrType, int limit) throws IDMapperException { Map<Xref, String> result = new HashMap<Xref, String>(); final QueryLifeCycle pst = (MATCH_ID.equals (attrType)) ? qIdSearchWithAttributes : qAttributeSearch; synchronized (pst) { try { pst.init(limit); pst.setString(1, attrType); pst.setString(2, "%" + query.toLowerCase() + "%"); ResultSet r = pst.executeQuery(); while(r.next()) { String id = r.getString("id"); String code = r.getString("code"); String symbol = r.getString("attrValue"); result.put(new Xref (id, DataSource.getExistingBySystemCode(code)), symbol); } } catch (SQLException e) { throw new IDMapperException (e); } finally {pst.cleanup(); } return result; } } public Map<Xref, Set<String>> freeAttributeSearchEx (String query, String attrType, int limit) throws IDMapperException { Map<Xref, Set<String>> result = new HashMap<Xref, Set<String>>(); final QueryLifeCycle pst = (MATCH_ID.equals (attrType)) ? qIdSearchWithAttributes : qAttributeSearch; synchronized (pst) { try { pst.init(limit); pst.setString(1, attrType); pst.setString(2, "%" + query.toLowerCase() + "%"); ResultSet r = pst.executeQuery(); while(r.next()) { String id = r.getString("id"); String code = r.getString("code"); String symbol = r.getString("attrValue"); Xref ref = new Xref (id, DataSource.getExistingBySystemCode(code)); InternalUtils.multiMapPut(result, ref, symbol); } } catch (SQLException e) { throw new IDMapperException (e); } finally { pst.cleanup(); } return result; } } /** {@inheritDoc} */ public Set<String> getAttributeSet() throws IDMapperException { Set<String> result = new HashSet<String>(); final QueryLifeCycle pst = qAttributesSet; synchronized (pst) { try { pst.init(); ResultSet rs = pst.executeQuery(); while (rs.next()) { result.add (rs.getString(1)); } } catch (SQLException ignore) { throw new IDMapperException(ignore); } finally {pst.cleanup(); } return result; } } @Override public Iterable<Xref> getIterator() throws IDMapperException { Set<Xref> xrefs = new HashSet<Xref>(); final QueryLifeCycle pst = qAllXrefs; synchronized (pst) { try { pst.init(); ResultSet rs = pst.executeQuery(); while (rs.next()) { xrefs.add(new Xref(rs.getString(1), DataSource.getExistingBySystemCode(rs.getString(2)))); } } catch (SQLException ignore) { throw new IDMapperException(ignore); } finally {pst.cleanup(); } return xrefs; } } @Override public Iterable<Xref> getIterator(DataSource ds) throws IDMapperException { Set<Xref> xrefs = new HashSet<Xref>(); final QueryLifeCycle pst = qAllXrefsByDatasource; synchronized (pst) { try { pst.init(); pst.setString(1, ds.getSystemCode()); ResultSet rs = pst.executeQuery(); while (rs.next()) { xrefs.add(new Xref(rs.getString(1), ds)); } } catch (SQLException ignore) { throw new IDMapperException(ignore); } finally {pst.cleanup(); } return xrefs; } } }