-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
- * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle\r
- * \r
- * This file is part of Jalview.\r
- * \r
- * Jalview is free software: you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License \r
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
- * \r
- * Jalview is distributed in the hope that it will be useful, but \r
- * WITHOUT ANY WARRANTY; without even the implied warranty \r
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
- * PURPOSE. See the GNU General Public License for more details.\r
- * \r
- * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-package jalview.ws;\r
-\r
-import jalview.bin.Cache;\r
-import jalview.datamodel.DBRefEntry;\r
-import jalview.datamodel.SequenceFeature;\r
-import jalview.datamodel.SequenceI;\r
-import jalview.gui.AlignFrame;\r
-import jalview.gui.Desktop;\r
-import jalview.gui.FeatureSettings;\r
-import jalview.util.UrlLink;\r
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;\r
-import jalview.ws.dbsources.das.api.jalviewSourceI;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Enumeration;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.StringTokenizer;\r
-import java.util.Vector;\r
-\r
-import javax.swing.JOptionPane;\r
-\r
-import org.biodas.jdas.client.FeaturesClient;\r
-import org.biodas.jdas.client.adapters.features.DasGFFAdapter;\r
-import org.biodas.jdas.client.adapters.features.DasGFFAdapter.GFFAdapter;\r
-import org.biodas.jdas.client.threads.FeaturesClientMultipleSources;\r
-import org.biodas.jdas.schema.features.ERRORSEGMENT;\r
-import org.biodas.jdas.schema.features.FEATURE;\r
-import org.biodas.jdas.schema.features.LINK;\r
-import org.biodas.jdas.schema.features.SEGMENT;\r
-import org.biodas.jdas.schema.features.TYPE;\r
-import org.biodas.jdas.schema.features.UNKNOWNFEATURE;\r
-import org.biodas.jdas.schema.features.UNKNOWNSEGMENT;\r
-import org.biodas.jdas.schema.sources.COORDINATES;\r
-\r
-/**\r
- * DOCUMENT ME!\r
- * \r
- * @author $author$\r
- * @version $Revision$\r
- */\r
-public class DasSequenceFeatureFetcher\r
-{\r
- SequenceI[] sequences;\r
-\r
- AlignFrame af;\r
-\r
- FeatureSettings fsettings;\r
-\r
- StringBuffer sbuffer = new StringBuffer();\r
-\r
- List<jalviewSourceI> selectedSources;\r
-\r
- boolean cancelled = false;\r
-\r
- private void debug(String mesg)\r
- {\r
- debug(mesg, null);\r
- }\r
-\r
- private void debug(String mesg, Exception e)\r
- {\r
- if (Cache.log != null)\r
- {\r
- Cache.log.debug(mesg, e);\r
- }\r
- else\r
- {\r
- System.err.println(mesg);\r
- if (e != null)\r
- {\r
- e.printStackTrace();\r
- }\r
- }\r
- }\r
-\r
- long startTime;\r
-\r
- private DasSourceRegistryI sourceRegistry;\r
- private boolean useJDASMultiThread=true;\r
- /**\r
- * Creates a new SequenceFeatureFetcher object. Uses default\r
- * \r
- * @param align\r
- * DOCUMENT ME!\r
- * @param ap\r
- * DOCUMENT ME!\r
- */\r
- public DasSequenceFeatureFetcher(SequenceI[] sequences,\r
- FeatureSettings fsettings, Vector selectedSources)\r
- {\r
- this(sequences, fsettings, selectedSources, true, true, true);\r
- }\r
-\r
- public DasSequenceFeatureFetcher(SequenceI[] oursequences,\r
- FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,\r
- boolean checkDbrefs, boolean promptFetchDbrefs)\r
- {\r
- this(oursequences,fsettings,selectedSources2,checkDbrefs,promptFetchDbrefs,true);\r
- }\r
- public DasSequenceFeatureFetcher(SequenceI[] oursequences,\r
- FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,\r
- boolean checkDbrefs, boolean promptFetchDbrefs, boolean useJDasMultiThread)\r
- {\r
- this.useJDASMultiThread=useJDasMultiThread;\r
- this.selectedSources = new ArrayList<jalviewSourceI>();\r
- // filter both sequences and sources to eliminate duplicates\r
- for (jalviewSourceI src : selectedSources2)\r
- {\r
- if (!selectedSources.contains(src))\r
- {\r
- selectedSources.add(src);\r
- }\r
- ;\r
- }\r
- Vector sqs = new Vector();\r
- for (int i = 0; i < oursequences.length; i++)\r
- {\r
- if (!sqs.contains(oursequences[i]))\r
- {\r
- sqs.addElement(oursequences[i]);\r
- }\r
- }\r
- sequences = new SequenceI[sqs.size()];\r
- for (int i = 0; i < sequences.length; i++)\r
- {\r
- sequences[i] = (SequenceI) sqs.elementAt(i);\r
- }\r
- if (fsettings != null)\r
- {\r
- this.fsettings = fsettings;\r
- this.af = fsettings.af;\r
- af.setShowSeqFeatures(true);\r
- }\r
- int uniprotCount = 0;\r
- for (jalviewSourceI source : selectedSources)\r
- {\r
- for (COORDINATES coords : source.getVersion().getCOORDINATES())\r
- {\r
- // TODO: match UniProt coord system canonically (?) - does\r
- // UniProt==uniprot==UNIPROT ?\r
- if (coords.getAuthority().toLowerCase().equals("uniprot"))\r
- {\r
- uniprotCount++;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- int refCount = 0;\r
- for (int i = 0; i < sequences.length; i++)\r
- {\r
- DBRefEntry[] dbref = sequences[i].getDBRef();\r
- if (dbref != null)\r
- {\r
- for (int j = 0; j < dbref.length; j++)\r
- {\r
- if (dbref[j].getSource().equals(\r
- jalview.datamodel.DBRefSource.UNIPROT))\r
- {\r
- refCount++;\r
- break;\r
- }\r
- }\r
- }\r
- }\r
-\r
- if (checkDbrefs && refCount < sequences.length && uniprotCount > 0)\r
- {\r
-\r
- int reply = JOptionPane.YES_OPTION;\r
- if (promptFetchDbrefs)\r
- {\r
- reply = JOptionPane\r
- .showInternalConfirmDialog(\r
- Desktop.desktop,\r
- "Do you want Jalview to find\n"\r
- + "Uniprot Accession ids for given sequence names?",\r
- "Find Uniprot Accession Ids",\r
- JOptionPane.YES_NO_OPTION,\r
- JOptionPane.QUESTION_MESSAGE);\r
- }\r
-\r
- if (reply == JOptionPane.YES_OPTION)\r
- {\r
- Thread thread = new Thread(new FetchDBRefs());\r
- thread.start();\r
- }\r
- else\r
- {\r
- _startFetching();\r
- }\r
- }\r
- else\r
- {\r
- _startFetching();\r
- }\r
-\r
- }\r
- private void _startFetching()\r
- {\r
- new Thread(new FetchSeqFeatures()).start();\r
- }\r
- class FetchSeqFeatures implements Runnable\r
- {\r
- public void run()\r
- {\r
- startFetching();\r
- setGuiFetchComplete();\r
- }\r
- }\r
- class FetchDBRefs implements Runnable\r
- {\r
- public void run()\r
- {\r
- new DBRefFetcher(sequences, af).fetchDBRefs(true);\r
- startFetching();\r
- setGuiFetchComplete();\r
- }\r
- }\r
-\r
- /**\r
- * Spawns Fetcher threads to add features to sequences in the dataset\r
- */\r
- void startFetching()\r
- {\r
- cancelled = false;\r
- startTime = System.currentTimeMillis();\r
- if (af != null)\r
- {\r
- af.setProgressBar("Fetching DAS Sequence Features", startTime);\r
- }\r
- if (sourceRegistry == null)\r
- {\r
- sourceRegistry = Cache.getDasSourceRegistry();\r
- }\r
- if (selectedSources == null || selectedSources.size() == 0)\r
- {\r
- try\r
- {\r
- jalviewSourceI[] sources = sourceRegistry.getSources().toArray(\r
- new jalviewSourceI[0]);\r
- String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",\r
- "uniprot");\r
- StringTokenizer st = new StringTokenizer(active, "\t");\r
- selectedSources = new Vector();\r
- String token;\r
- while (st.hasMoreTokens())\r
- {\r
- token = st.nextToken();\r
- for (int i = 0; i < sources.length; i++)\r
- {\r
- if (sources[i].getTitle().equals(token))\r
- {\r
- selectedSources.add(sources[i]);\r
- break;\r
- }\r
- }\r
- }\r
- } catch (Exception ex)\r
- {\r
- debug("Exception whilst setting default feature sources from registry and local preferences.",\r
- ex);\r
- }\r
- }\r
-\r
- if (selectedSources == null || selectedSources.size() == 0)\r
- {\r
- System.out.println("No DAS Sources active");\r
- cancelled = true;\r
- setGuiNoDassourceActive();\r
- return;\r
- }\r
-\r
- sourcesRemaining = selectedSources.size();\r
- FeaturesClientMultipleSources fc = new FeaturesClientMultipleSources();\r
- fc.setConnProps(sourceRegistry.getSessionHandler());\r
- // Now sending requests one at a time to each server\r
- ArrayList<jalviewSourceI> srcobj = new ArrayList<jalviewSourceI>();\r
- ArrayList<String> src = new ArrayList<String>();\r
- List<List<String>> ids = new ArrayList<List<String>>();\r
- List<List<DBRefEntry>> idobj = new ArrayList<List<DBRefEntry>>();\r
- List<Map<String, SequenceI>> sqset = new ArrayList<Map<String, SequenceI>>();\r
- for (jalviewSourceI _sr : selectedSources)\r
- {\r
-\r
- Map<String, SequenceI> slist = new HashMap<String, SequenceI>();\r
- List<DBRefEntry> idob = new ArrayList<DBRefEntry>();\r
- List<String> qset = new ArrayList<String>();\r
-\r
- for (SequenceI seq : sequences)\r
- {\r
- Object[] idset = nextSequence(_sr, seq);\r
- if (idset != null)\r
- {\r
- List<DBRefEntry> _idob = (List<DBRefEntry>) idset[0];\r
- List<String> _qset = (List<String>) idset[1];\r
- if (_idob.size() > 0)\r
- {\r
- // add sequence's ref for each id derived from it\r
- // (space inefficient, but most unambiguous)\r
- // could replace with hash with _qset values as keys.\r
- Iterator<DBRefEntry> dbobj = _idob.iterator();\r
- for (String q : _qset)\r
- {\r
- SequenceI osq = slist.get(q);\r
- DBRefEntry dr = dbobj.next();\r
- if (osq != null && osq != seq)\r
- {\r
- // skip - non-canonical query\r
- }\r
- else\r
- {\r
- idob.add(dr);\r
- qset.add(q);\r
- slist.put(q, seq);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- if (idob.size() > 0)\r
- {\r
- srcobj.add(_sr);\r
- src.add(_sr.getSourceURL());\r
- ids.add(qset);\r
- idobj.add(idob);\r
- sqset.add(slist);\r
- }\r
- }\r
- Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();\r
- Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<String, Map<List<String>, DasGFFAdapter>>();\r
- if (!useJDASMultiThread)\r
- {\r
- Iterator<String> sources=src.iterator();\r
- // iterate over each query for each source and do each one individually\r
- for (List<String> idl:ids)\r
- {\r
- String source=sources.next();\r
- FeaturesClient featuresc=new FeaturesClient(sourceRegistry.getSessionHandler().getConnectionPropertyProviderFor(source));\r
- for (String id:idl)\r
- {\r
- List<String> qid=Arrays.asList(new String[] { id});\r
- try {\r
- DasGFFAdapter dga=featuresc.fetchData(source, qid);\r
- Map<List<String>,DasGFFAdapter> ers=results.get(source);\r
- if (ers==null)\r
- {\r
- results.put(source, ers=new HashMap<List<String>,DasGFFAdapter>());\r
- }\r
- ers.put(qid, dga);\r
- } catch (Exception ex)\r
- {\r
- Map<List<String>,Exception> ers=errors.get(source);\r
- if (ers==null)\r
- {\r
- errors.put(source, ers=new HashMap<List<String>,Exception>());\r
- }\r
- ers.put(qid, ex);\r
- }\r
- }\r
- }\r
- } else {\r
- // pass them all at once\r
- fc.fetchData(src, ids, false, results, errors);\r
- fc.shutDown();\r
- while (!fc.isTerminated())\r
- {\r
- try\r
- {\r
- Thread.sleep(200);\r
- } catch (InterruptedException x)\r
- {\r
-\r
- }\r
- }\r
- }\r
- Iterator<List<String>> idset = ids.iterator();\r
- Iterator<List<DBRefEntry>> idobjset = idobj.iterator();\r
- Iterator<Map<String, SequenceI>> seqset = sqset.iterator();\r
- for (jalviewSourceI source : srcobj)\r
- {\r
- processResponse(seqset.next(), source, idset.next(), idobjset.next(),\r
- results.get(source.getSourceURL()),\r
- errors.get(source.getSourceURL()));\r
- }\r
- }\r
-\r
- private void processResponse(Map<String, SequenceI> sequencemap,\r
- jalviewSourceI jvsource, List<String> ids,\r
- List<DBRefEntry> idobj, Map<List<String>, DasGFFAdapter> results,\r
- Map<List<String>, Exception> errors)\r
- {\r
- Set<SequenceI> sequences = new HashSet<SequenceI>();\r
- String source = jvsource.getSourceURL();\r
- // process features\r
- DasGFFAdapter result = (results == null) ? null : results.get(ids);\r
- Exception error = (errors == null) ? null : errors.get(ids);\r
- if (result == null)\r
- {\r
- debug("das source " + source + " could not be contacted. "\r
- + (error == null ? "" : error.toString()));\r
- }\r
- else\r
- {\r
-\r
- GFFAdapter gff = result.getGFF();\r
- List<SEGMENT> segments = gff.getSegments();\r
- List<ERRORSEGMENT> errorsegs = gff.getErrorSegments();\r
- List<UNKNOWNFEATURE> unkfeats = gff.getUnknownFeatures();\r
- List<UNKNOWNSEGMENT> unksegs = gff.getUnknownSegments();\r
- debug("das source " + source + " returned " + gff.getTotal()\r
- + " responses. " + (errorsegs != null ? errorsegs.size() : 0)\r
- + " were incorrect segment queries, "\r
- + (unkfeats != null ? unkfeats.size() : 0)\r
- + " were unknown features "\r
- + (unksegs != null ? unksegs.size() : 0)\r
- + " were unknown segments and "\r
- + (segments != null ? segments.size() : 0)\r
- + " were segment responses.");\r
- Iterator<DBRefEntry> dbr = idobj.iterator();\r
- if (segments != null)\r
- {\r
- for (SEGMENT seg : segments)\r
- {\r
- String id = seg.getId();\r
- DBRefEntry dbref = idobj.get(ids.indexOf(id));\r
- SequenceI sequence = sequencemap.get(id);\r
- boolean added = false;\r
- sequences.add(sequence);\r
-\r
- for (FEATURE feat : seg.getFEATURE())\r
- {\r
- // standard DAS feature-> jalview sequence feature transformation\r
- SequenceFeature f = newSequenceFeature(feat, jvsource.getTitle());\r
- if (!parseSeqFeature(sequence, f, feat, jvsource))\r
- {\r
- if (dbref.getMap() != null && f.getBegin() > 0\r
- && f.getEnd() > 0)\r
- {\r
- debug("mapping from " + f.getBegin() + " - " + f.getEnd());\r
- SequenceFeature vf[] = null;\r
-\r
- try\r
- {\r
- vf = dbref.getMap().locateFeature(f);\r
- } catch (Exception ex)\r
- {\r
- Cache.log\r
- .info("Error in 'experimental' mapping of features. Please try to reproduce and then report info to jalview-discuss@jalview.org.");\r
- Cache.log.info("Mapping feature from " + f.getBegin()\r
- + " to " + f.getEnd() + " in dbref "\r
- + dbref.getAccessionId() + " in "\r
- + dbref.getSource());\r
- Cache.log.info("using das Source " + source);\r
- Cache.log.info("Exception", ex);\r
- }\r
-\r
- if (vf != null)\r
- {\r
- for (int v = 0; v < vf.length; v++)\r
- {\r
- debug("mapping to " + v + ": " + vf[v].getBegin()\r
- + " - " + vf[v].getEnd());\r
- sequence.addSequenceFeature(vf[v]);\r
- }\r
- }\r
- }\r
- else\r
- {\r
- sequence.addSequenceFeature(f);\r
- }\r
- }\r
- }\r
- }\r
- featuresAdded(sequences);\r
- }\r
- else\r
- {\r
- // System.out.println("No features found for " + seq.getName()\r
- // + " from: " + e.getDasSource().getNickname());\r
- }\r
- }\r
- }\r
-\r
- private void setGuiNoDassourceActive()\r
- {\r
-\r
- if (af != null)\r
- {\r
- af.setProgressBar("No DAS Sources Active", startTime);\r
- }\r
- if (getFeatSettings() != null)\r
- {\r
- fsettings.noDasSourceActive();\r
- }\r
- }\r
-\r
- /**\r
- * Update our fsettings dialog reference if we didn't have one when we were\r
- * first initialised.\r
- * \r
- * @return fsettings\r
- */\r
- private FeatureSettings getFeatSettings()\r
- {\r
- if (fsettings == null)\r
- {\r
- if (af != null)\r
- {\r
- fsettings = af.featureSettings;\r
- }\r
- }\r
- return fsettings;\r
- }\r
-\r
- public void cancel()\r
- {\r
- if (af != null)\r
- {\r
- af.setProgressBar("DAS Feature Fetching Cancelled", startTime);\r
- }\r
- cancelled = true;\r
- }\r
-\r
- int sourcesRemaining = 0;\r
-\r
- private void setGuiFetchComplete()\r
- {\r
-\r
- if (!cancelled && af != null)\r
- {\r
- // only update the progress bar if we've completed the fetch normally\r
- af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
- }\r
-\r
- if (af != null && af.featureSettings != null)\r
- {\r
- af.featureSettings.setTableData();\r
- }\r
-\r
- if (getFeatSettings() != null)\r
- {\r
- fsettings.complete();\r
- }\r
- }\r
-\r
- void featuresAdded(Set<SequenceI> seqs)\r
- {\r
- if (af == null)\r
- {\r
- // no gui to update with features.\r
- return;\r
- }\r
- af.getFeatureRenderer().featuresAdded();\r
-\r
- int start = af.getViewport().getStartSeq();\r
- int end = af.getViewport().getEndSeq();\r
- int index;\r
- for (index = start; index < end; index++)\r
- {\r
- for (SequenceI seq : seqs)\r
- {\r
- if (seq == af.getViewport().getAlignment().getSequenceAt(index)\r
- .getDatasetSequence())\r
- {\r
- af.alignPanel.paintAlignment(true);\r
- index = end;\r
- break;\r
- }\r
- }\r
- }\r
- }\r
-\r
- Object[] nextSequence(jalviewSourceI dasSource, SequenceI seq)\r
- {\r
- if (cancelled)\r
- return null;\r
- DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(\r
- seq.getDBRef(), new String[]\r
- {\r
- // jalview.datamodel.DBRefSource.PDB,\r
- jalview.datamodel.DBRefSource.UNIPROT,\r
- // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord\r
- // sys sources\r
- });\r
- // TODO: minimal list of DAS queries to make by querying with untyped ID if\r
- // distinct from any typed IDs\r
-\r
- List<DBRefEntry> ids = new ArrayList<DBRefEntry>();\r
- List<String> qstring = new ArrayList<String>();\r
- boolean dasCoordSysFound = false;\r
-\r
- if (uprefs != null)\r
- {\r
- // do any of these ids match the source's coordinate system ?\r
- for (int j = 0; !dasCoordSysFound && j < uprefs.length; j++)\r
- {\r
-\r
- for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())\r
- {\r
- if (jalview.util.DBRefUtils.isDasCoordinateSystem(\r
- csys.getAuthority(), uprefs[j]))\r
- {\r
- debug("Launched fetcher for coordinate system "\r
- + csys.getAuthority());\r
- // Will have to pass any mapping information to the fetcher\r
- // - the start/end for the DBRefEntry may not be the same as the\r
- // sequence's start/end\r
-\r
- System.out.println(seq.getName() + " "\r
- + (seq.getDatasetSequence() == null) + " "\r
- + csys.getUri());\r
-\r
- dasCoordSysFound = true; // break's out of the loop\r
- ids.add(uprefs[j]);\r
- qstring.add(uprefs[j].getAccessionId());\r
- }\r
- else\r
- System.out.println("IGNORE " + csys.getAuthority());\r
- }\r
- }\r
- }\r
-\r
- if (!dasCoordSysFound)\r
- {\r
- String id = null;\r
- // try and use the name as the sequence id\r
- if (seq.getName().indexOf("|") > -1)\r
- {\r
- id = seq.getName().substring(seq.getName().lastIndexOf("|") + 1);\r
- if (id.trim().length() < 4)\r
- {\r
- // hack - we regard a significant ID as being at least 4\r
- // non-whitespace characters\r
- id = seq.getName().substring(0, seq.getName().lastIndexOf("|"));\r
- if (id.indexOf("|") > -1)\r
- {\r
- id = id.substring(id.lastIndexOf("|") + 1);\r
- }\r
- }\r
- }\r
- else\r
- {\r
- id = seq.getName();\r
- }\r
- if (id != null)\r
- {\r
- DBRefEntry dbre = new DBRefEntry();\r
- dbre.setAccessionId(id);\r
- // Should try to call a general feature fetcher that\r
- // queries many sources with name to discover applicable ID references\r
- ids.add(dbre);\r
- qstring.add(dbre.getAccessionId());\r
- }\r
- }\r
-\r
- return new Object[]\r
- { ids, qstring };\r
- }\r
-\r
- /**\r
- * examine the given sequence feature to determine if it should actually be\r
- * turned into sequence annotation or database cross references rather than a\r
- * simple sequence feature.\r
- * \r
- * @param seq\r
- * the sequence to annotate\r
- * @param f\r
- * the jalview sequence feature generated from the DAS feature\r
- * @param map\r
- * the sequence feature attributes\r
- * @param source\r
- * the source that emitted the feature\r
- * @return true if feature was consumed as another kind of annotation.\r
- */\r
- protected boolean parseSeqFeature(SequenceI seq, SequenceFeature f,\r
- FEATURE feature, jalviewSourceI source)\r
- {\r
- SequenceI mseq = seq;\r
- while (seq.getDatasetSequence() != null)\r
- {\r
- seq = seq.getDatasetSequence();\r
- }\r
- if (f.getType() != null)\r
- {\r
- String type = f.getType();\r
- if (type.equalsIgnoreCase("protein_name"))\r
- {\r
- // parse name onto the alignment sequence or the dataset sequence.\r
- if (seq.getDescription() == null\r
- || seq.getDescription().trim().length() == 0)\r
- {\r
- // could look at the note series to pick out the first long name, for\r
- // the moment just use the whole description string\r
- seq.setDescription(f.getDescription());\r
- }\r
- if (mseq.getDescription() == null\r
- || mseq.getDescription().trim().length() == 0)\r
- {\r
- // could look at the note series to pick out the first long name, for\r
- // the moment just use the whole description string\r
- mseq.setDescription(f.getDescription());\r
- }\r
- return true;\r
- }\r
- // check if source has biosapiens or other sequence ontology label\r
- if (type.equalsIgnoreCase("DBXREF") || type.equalsIgnoreCase("DBREF"))\r
- {\r
- // try to parse the accession out\r
-\r
- DBRefEntry dbr = new DBRefEntry();\r
- dbr.setVersion(source.getTitle());\r
- StringTokenizer st = new StringTokenizer(f.getDescription(), ":");\r
- if (st.hasMoreTokens())\r
- {\r
- dbr.setSource(st.nextToken());\r
- }\r
- if (st.hasMoreTokens())\r
- {\r
- dbr.setAccessionId(st.nextToken());\r
- }\r
- seq.addDBRef(dbr);\r
-\r
- if (f.links != null && f.links.size() > 0)\r
- {\r
- // feature is also appended to enable links to be seen.\r
- // TODO: consider extending dbrefs to have their own links ?\r
- // TODO: new feature: extract dbref links from DAS servers and add the\r
- // URL pattern to the list of DB name associated links in the user's\r
- // preferences ?\r
- // for the moment - just fix up the existing feature so it displays\r
- // correctly.\r
- // f.setType(dbr.getSource());\r
- // f.setDescription();\r
- f.setValue("linkonly", Boolean.TRUE);\r
- // f.setDescription("");\r
- Vector newlinks = new Vector();\r
- Enumeration it = f.links.elements();\r
- while (it.hasMoreElements())\r
- {\r
- String elm;\r
- UrlLink urllink = new UrlLink(elm = (String) it.nextElement());\r
- if (urllink.isValid())\r
- {\r
- urllink.setLabel(f.getDescription());\r
- newlinks.addElement(urllink.toString());\r
- }\r
- else\r
- {\r
- // couldn't parse the link properly. Keep it anyway - just in\r
- // case.\r
- debug("couldn't parse link string - " + elm);\r
- newlinks.addElement(elm);\r
- }\r
- }\r
- f.links = newlinks;\r
- seq.addSequenceFeature(f);\r
- }\r
- return true;\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * creates a jalview sequence feature from a das feature document\r
- * \r
- * @param feat\r
- * @return sequence feature object created using dasfeature information\r
- */\r
- SequenceFeature newSequenceFeature(FEATURE feat, String nickname)\r
- {\r
- if (feat == null)\r
- {\r
- return null;\r
- }\r
- try\r
- {\r
- /**\r
- * Different qNames for a DAS Feature - are string keys to the HashMaps in\r
- * features "METHOD") || qName.equals("TYPE") || qName.equals("START") ||\r
- * qName.equals("END") || qName.equals("NOTE") || qName.equals("LINK") ||\r
- * qName.equals("SCORE")\r
- */\r
- String desc = new String();\r
- if (feat.getNOTE() != null)\r
- {\r
- for (String note : feat.getNOTE())\r
- {\r
- desc += (String) note;\r
- }\r
- }\r
-\r
- int start = 0, end = 0;\r
- float score = 0f;\r
-\r
- try\r
- {\r
- start = Integer.parseInt(feat.getSTART().toString());\r
- } catch (Exception ex)\r
- {\r
- }\r
- try\r
- {\r
- end = Integer.parseInt(feat.getEND().toString());\r
- } catch (Exception ex)\r
- {\r
- }\r
- try\r
- {\r
- Object scr = feat.getSCORE();\r
- if (scr != null)\r
- {\r
- score = (float) Double.parseDouble(scr.toString());\r
-\r
- }\r
- } catch (Exception ex)\r
- {\r
- }\r
-\r
- SequenceFeature f = new SequenceFeature(\r
- getTypeString(feat.getTYPE()), desc, start, end, score,\r
- nickname);\r
-\r
- if (feat.getLINK() != null)\r
- {\r
- for (LINK link : feat.getLINK())\r
- {\r
- // Do not put feature extent in link text for non-positional features\r
- if (f.begin == 0 && f.end == 0)\r
- {\r
- f.addLink(f.getType() + " " + link.getContent() + "|"\r
- + link.getHref());\r
- }\r
- else\r
- {\r
- f.addLink(f.getType() + " " + f.begin + "_" + f.end + " "\r
- + link.getContent() + "|" + link.getHref());\r
- }\r
- }\r
- }\r
-\r
- return f;\r
- } catch (Exception e)\r
- {\r
- System.out.println("ERRR " + e);\r
- e.printStackTrace();\r
- System.out.println("############");\r
- debug("Failed to parse " + feat.toString(), e);\r
- return null;\r
- }\r
- }\r
-\r
- private String getTypeString(TYPE type)\r
- {\r
- return type.getContent();\r
- }\r
-\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws;
+
+import jalview.bin.Cache;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.FeatureSettings;
+import jalview.gui.JvOptionPane;
+import jalview.util.DBRefUtils;
+import jalview.util.MessageManager;
+import jalview.util.UrlLink;
+import jalview.ws.dbsources.das.api.DasSourceRegistryI;
+import jalview.ws.dbsources.das.api.jalviewSourceI;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.biodas.jdas.client.FeaturesClient;
+import org.biodas.jdas.client.adapters.features.DasGFFAdapter;
+import org.biodas.jdas.client.adapters.features.DasGFFAdapter.GFFAdapter;
+import org.biodas.jdas.client.threads.FeaturesClientMultipleSources;
+import org.biodas.jdas.schema.features.ERRORSEGMENT;
+import org.biodas.jdas.schema.features.FEATURE;
+import org.biodas.jdas.schema.features.LINK;
+import org.biodas.jdas.schema.features.SEGMENT;
+import org.biodas.jdas.schema.features.TYPE;
+import org.biodas.jdas.schema.features.UNKNOWNFEATURE;
+import org.biodas.jdas.schema.features.UNKNOWNSEGMENT;
+import org.biodas.jdas.schema.sources.COORDINATES;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class DasSequenceFeatureFetcher
+{
+ SequenceI[] sequences;
+
+ AlignFrame af;
+
+ FeatureSettings fsettings;
+
+ StringBuffer sbuffer = new StringBuffer();
+
+ List<jalviewSourceI> selectedSources;
+
+ boolean cancelled = false;
+
+ private void debug(String mesg)
+ {
+ debug(mesg, null);
+ }
+
+ private void debug(String mesg, Exception e)
+ {
+ if (Cache.log != null)
+ {
+ Cache.log.debug(mesg, e);
+ }
+ else
+ {
+ System.err.println(mesg);
+ if (e != null)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ long startTime;
+
+ private DasSourceRegistryI sourceRegistry;
+
+ private boolean useJDASMultiThread = true;
+
+ /**
+ * Creates a new SequenceFeatureFetcher object. Uses default
+ *
+ * @param align
+ * DOCUMENT ME!
+ * @param ap
+ * DOCUMENT ME!
+ */
+ public DasSequenceFeatureFetcher(SequenceI[] sequences,
+ FeatureSettings fsettings, Vector selectedSources)
+ {
+ this(sequences, fsettings, selectedSources, true, true, true);
+ }
+
+ public DasSequenceFeatureFetcher(SequenceI[] oursequences,
+ FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,
+ boolean checkDbrefs, boolean promptFetchDbrefs)
+ {
+ this(oursequences, fsettings, selectedSources2, checkDbrefs,
+ promptFetchDbrefs, true);
+ }
+
+ public DasSequenceFeatureFetcher(SequenceI[] oursequences,
+ FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,
+ boolean checkDbrefs, boolean promptFetchDbrefs,
+ boolean useJDasMultiThread)
+ {
+ this.useJDASMultiThread = useJDasMultiThread;
+ this.selectedSources = new ArrayList<>();
+ // filter both sequences and sources to eliminate duplicates
+ for (jalviewSourceI src : selectedSources2)
+ {
+ if (!selectedSources.contains(src))
+ {
+ selectedSources.add(src);
+ }
+ ;
+ }
+ Vector sqs = new Vector();
+ for (int i = 0; i < oursequences.length; i++)
+ {
+ if (!sqs.contains(oursequences[i]))
+ {
+ sqs.addElement(oursequences[i]);
+ }
+ }
+ sequences = new SequenceI[sqs.size()];
+ for (int i = 0; i < sequences.length; i++)
+ {
+ sequences[i] = (SequenceI) sqs.elementAt(i);
+ }
+ if (fsettings != null)
+ {
+ this.fsettings = fsettings;
+ this.af = fsettings.af;
+ af.setShowSeqFeatures(true);
+ }
+ int uniprotCount = 0;
+ for (jalviewSourceI source : selectedSources)
+ {
+ for (COORDINATES coords : source.getVersion().getCOORDINATES())
+ {
+ // TODO: match UniProt coord system canonically (?) - does
+ // UniProt==uniprot==UNIPROT ?
+ if (coords.getAuthority().toLowerCase().equals("uniprot"))
+ {
+ uniprotCount++;
+ break;
+ }
+ }
+ }
+
+ int refCount = 0;
+ for (int i = 0; i < sequences.length; i++)
+ {
+ DBRefEntry[] dbref = sequences[i].getDBRefs();
+ if (dbref != null)
+ {
+ for (int j = 0; j < dbref.length; j++)
+ {
+ if (dbref[j].getSource().equals(DBRefSource.UNIPROT))
+ {
+ refCount++;
+ break;
+ }
+ }
+ }
+ }
+
+ if (checkDbrefs && refCount < sequences.length && uniprotCount > 0)
+ {
+
+ int reply = JvOptionPane.YES_OPTION;
+ if (promptFetchDbrefs)
+ {
+ reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
+ MessageManager.getString(
+ "info.you_want_jalview_to_find_uniprot_accessions"),
+ MessageManager
+ .getString("label.find_uniprot_accession_ids"),
+ JvOptionPane.YES_NO_OPTION, JvOptionPane.QUESTION_MESSAGE);
+ }
+
+ if (reply == JvOptionPane.YES_OPTION)
+ {
+ Thread thread = new Thread(new FetchDBRefs());
+ thread.start();
+ }
+ else
+ {
+ _startFetching();
+ }
+ }
+ else
+ {
+ _startFetching();
+ }
+
+ }
+
+ private void _startFetching()
+ {
+ running = true;
+ new Thread(new FetchSeqFeatures()).start();
+ }
+
+ class FetchSeqFeatures implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ startFetching();
+ setGuiFetchComplete();
+ }
+ }
+
+ class FetchDBRefs implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ running = true;
+ boolean isNucleotide = af.getViewport().getAlignment().isNucleotide();
+ new DBRefFetcher(sequences, af, null, af.featureSettings,
+ isNucleotide).fetchDBRefs(true);
+
+ startFetching();
+ setGuiFetchComplete();
+ }
+ }
+
+ /**
+ * Spawns Fetcher threads to add features to sequences in the dataset
+ */
+ void startFetching()
+ {
+ running = true;
+ cancelled = false;
+ startTime = System.currentTimeMillis();
+ if (af != null)
+ {
+ af.setProgressBar(MessageManager.getString(
+ "status.fetching_das_sequence_features"), startTime);
+ }
+ if (sourceRegistry == null)
+ {
+ sourceRegistry = Cache.getDasSourceRegistry();
+ }
+ if (selectedSources == null || selectedSources.size() == 0)
+ {
+ try
+ {
+ jalviewSourceI[] sources = sourceRegistry.getSources()
+ .toArray(new jalviewSourceI[0]);
+ String active = Cache.getDefault("DAS_ACTIVE_SOURCE", "uniprot");
+ StringTokenizer st = new StringTokenizer(active, "\t");
+ selectedSources = new Vector();
+ String token;
+ while (st.hasMoreTokens())
+ {
+ token = st.nextToken();
+ for (int i = 0; i < sources.length; i++)
+ {
+ if (sources[i].getTitle().equals(token))
+ {
+ selectedSources.add(sources[i]);
+ break;
+ }
+ }
+ }
+ } catch (Exception ex)
+ {
+ debug("Exception whilst setting default feature sources from registry and local preferences.",
+ ex);
+ }
+ }
+
+ if (selectedSources == null || selectedSources.size() == 0)
+ {
+ System.out.println("No DAS Sources active");
+ cancelled = true;
+ setGuiNoDassourceActive();
+ return;
+ }
+
+ sourcesRemaining = selectedSources.size();
+ FeaturesClientMultipleSources fc = new FeaturesClientMultipleSources();
+ fc.setConnProps(sourceRegistry.getSessionHandler());
+ // Now sending requests one at a time to each server
+ ArrayList<jalviewSourceI> srcobj = new ArrayList<>();
+ ArrayList<String> src = new ArrayList<>();
+ List<List<String>> ids = new ArrayList<>();
+ List<List<DBRefEntry>> idobj = new ArrayList<>();
+ List<Map<String, SequenceI>> sqset = new ArrayList<>();
+ for (jalviewSourceI _sr : selectedSources)
+ {
+
+ Map<String, SequenceI> slist = new HashMap<>();
+ List<DBRefEntry> idob = new ArrayList<>();
+ List<String> qset = new ArrayList<>();
+
+ for (SequenceI seq : sequences)
+ {
+ Object[] idset = nextSequence(_sr, seq);
+ if (idset != null)
+ {
+ List<DBRefEntry> _idob = (List<DBRefEntry>) idset[0];
+ List<String> _qset = (List<String>) idset[1];
+ if (_idob.size() > 0)
+ {
+ // add sequence's ref for each id derived from it
+ // (space inefficient, but most unambiguous)
+ // could replace with hash with _qset values as keys.
+ Iterator<DBRefEntry> dbobj = _idob.iterator();
+ for (String q : _qset)
+ {
+ SequenceI osq = slist.get(q);
+ DBRefEntry dr = dbobj.next();
+ if (osq != null && osq != seq)
+ {
+ // skip - non-canonical query
+ }
+ else
+ {
+ idob.add(dr);
+ qset.add(q);
+ slist.put(q, seq);
+ }
+ }
+ }
+ }
+ }
+ if (idob.size() > 0)
+ {
+ srcobj.add(_sr);
+ src.add(_sr.getSourceURL());
+ ids.add(qset);
+ idobj.add(idob);
+ sqset.add(slist);
+ }
+ }
+ Map<String, Map<List<String>, Exception>> errors = new HashMap<>();
+ Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<>();
+ if (!useJDASMultiThread)
+ {
+ Iterator<String> sources = src.iterator();
+ // iterate over each query for each source and do each one individually
+ for (List<String> idl : ids)
+ {
+ String source = sources.next();
+ FeaturesClient featuresc = new FeaturesClient(
+ sourceRegistry.getSessionHandler()
+ .getConnectionPropertyProviderFor(source));
+ for (String id : idl)
+ {
+ List<String> qid = Arrays.asList(new String[] { id });
+ try
+ {
+ DasGFFAdapter dga = featuresc.fetchData(source, qid);
+ Map<List<String>, DasGFFAdapter> ers = results.get(source);
+ if (ers == null)
+ {
+ results.put(source,
+ ers = new HashMap<>());
+ }
+ ers.put(qid, dga);
+ } catch (Exception ex)
+ {
+ Map<List<String>, Exception> ers = errors.get(source);
+ if (ers == null)
+ {
+ errors.put(source,
+ ers = new HashMap<>());
+ }
+ ers.put(qid, ex);
+ }
+ }
+ }
+ }
+ else
+ {
+ // pass them all at once
+ fc.fetchData(src, ids, false, results, errors);
+ fc.shutDown();
+ while (!fc.isTerminated())
+ {
+ try
+ {
+ Thread.sleep(200);
+ } catch (InterruptedException x)
+ {
+
+ }
+ }
+ }
+ Iterator<List<String>> idset = ids.iterator();
+ Iterator<List<DBRefEntry>> idobjset = idobj.iterator();
+ Iterator<Map<String, SequenceI>> seqset = sqset.iterator();
+ for (jalviewSourceI source : srcobj)
+ {
+ processResponse(seqset.next(), source, idset.next(), idobjset.next(),
+ results.get(source.getSourceURL()),
+ errors.get(source.getSourceURL()));
+ }
+ }
+
+ private void processResponse(Map<String, SequenceI> sequencemap,
+ jalviewSourceI jvsource, List<String> ids, List<DBRefEntry> idobj,
+ Map<List<String>, DasGFFAdapter> results,
+ Map<List<String>, Exception> errors)
+ {
+ Set<SequenceI> sequences = new HashSet<>();
+ String source = jvsource.getSourceURL();
+ // process features
+ DasGFFAdapter result = (results == null) ? null : results.get(ids);
+ Exception error = (errors == null) ? null : errors.get(ids);
+ if (result == null)
+ {
+ debug("das source " + source + " could not be contacted. "
+ + (error == null ? "" : error.toString()));
+ }
+ else
+ {
+
+ GFFAdapter gff = result.getGFF();
+ List<SEGMENT> segments = gff.getSegments();
+ List<ERRORSEGMENT> errorsegs = gff.getErrorSegments();
+ List<UNKNOWNFEATURE> unkfeats = gff.getUnknownFeatures();
+ List<UNKNOWNSEGMENT> unksegs = gff.getUnknownSegments();
+ debug("das source " + source + " returned " + gff.getTotal()
+ + " responses. " + (errorsegs != null ? errorsegs.size() : 0)
+ + " were incorrect segment queries, "
+ + (unkfeats != null ? unkfeats.size() : 0)
+ + " were unknown features "
+ + (unksegs != null ? unksegs.size() : 0)
+ + " were unknown segments and "
+ + (segments != null ? segments.size() : 0)
+ + " were segment responses.");
+ Iterator<DBRefEntry> dbr = idobj.iterator();
+ if (segments != null)
+ {
+ for (SEGMENT seg : segments)
+ {
+ String id = seg.getId();
+ if (ids.indexOf(id) == -1)
+ {
+ id = id.toUpperCase();
+ }
+ DBRefEntry dbref = idobj.get(ids.indexOf(id));
+ SequenceI sequence = sequencemap.get(id);
+ boolean added = false;
+ sequences.add(sequence);
+
+ for (FEATURE feat : seg.getFEATURE())
+ {
+ // standard DAS feature-> jalview sequence feature transformation
+ SequenceFeature f = newSequenceFeature(feat,
+ jvsource.getTitle());
+ if (!parseSeqFeature(sequence, f, feat, jvsource))
+ {
+ if (dbref.getMap() != null && f.getBegin() > 0
+ && f.getEnd() > 0)
+ {
+ debug("mapping from " + f.getBegin() + " - " + f.getEnd());
+ SequenceFeature vf[] = null;
+
+ try
+ {
+ vf = dbref.getMap().locateFeature(f);
+ } catch (Exception ex)
+ {
+ Cache.log.warn(
+ "Error in 'experimental' mapping of features. Please try to reproduce and then report info to jalview-discuss@jalview.org.");
+ Cache.log.warn("Mapping feature from " + f.getBegin()
+ + " to " + f.getEnd() + " in dbref "
+ + dbref.getAccessionId() + " in "
+ + dbref.getSource());
+ Cache.log.warn("using das Source " + source);
+ Cache.log.warn("Exception", ex);
+ }
+
+ if (vf != null)
+ {
+ for (int v = 0; v < vf.length; v++)
+ {
+ debug("mapping to " + v + ": " + vf[v].getBegin()
+ + " - " + vf[v].getEnd());
+ sequence.addSequenceFeature(vf[v]);
+ }
+ }
+ }
+ else
+ {
+ sequence.addSequenceFeature(f);
+ }
+ }
+ }
+ }
+ featuresAdded(sequences);
+ }
+ else
+ {
+ // System.out.println("No features found for " + seq.getName()
+ // + " from: " + e.getDasSource().getNickname());
+ }
+ }
+ }
+
+ private void setGuiNoDassourceActive()
+ {
+
+ if (af != null)
+ {
+ af.setProgressBar(
+ MessageManager.getString("status.no_das_sources_active"),
+ startTime);
+ }
+ if (getFeatSettings() != null)
+ {
+ fsettings.noDasSourceActive();
+ }
+ }
+
+ /**
+ * Update our fsettings dialog reference if we didn't have one when we were
+ * first initialised.
+ *
+ * @return fsettings
+ */
+ private FeatureSettings getFeatSettings()
+ {
+ if (fsettings == null)
+ {
+ if (af != null)
+ {
+ fsettings = af.featureSettings;
+ }
+ }
+ return fsettings;
+ }
+
+ public void cancel()
+ {
+ if (af != null)
+ {
+ af.setProgressBar(MessageManager.getString(
+ "status.das_feature_fetching_cancelled"), startTime);
+ }
+ cancelled = true;
+ }
+
+ int sourcesRemaining = 0;
+
+ private boolean running = false;
+
+ private void setGuiFetchComplete()
+ {
+ running = false;
+ if (!cancelled && af != null)
+ {
+ // only update the progress bar if we've completed the fetch normally
+ af.setProgressBar(MessageManager.getString(
+ "status.das_feature_fetching_complete"), startTime);
+ }
+
+ if (af != null && af.featureSettings != null)
+ {
+ af.featureSettings.discoverAllFeatureData();
+ }
+
+ if (getFeatSettings() != null)
+ {
+ fsettings.complete();
+ }
+ }
+
+ void featuresAdded(Set<SequenceI> seqs)
+ {
+ if (af == null)
+ {
+ // no gui to update with features.
+ return;
+ }
+ af.getFeatureRenderer().featuresAdded();
+
+ int start = af.getViewport().getRanges().getStartSeq();
+ int end = af.getViewport().getRanges().getEndSeq();
+ int index;
+ for (index = start; index < end; index++)
+ {
+ for (SequenceI seq : seqs)
+ {
+ if (seq == af.getViewport().getAlignment().getSequenceAt(index)
+ .getDatasetSequence())
+ {
+ af.alignPanel.paintAlignment(true, true);
+ index = end;
+ break;
+ }
+ }
+ }
+ }
+
+ Object[] nextSequence(jalviewSourceI dasSource, SequenceI seq)
+ {
+ if (cancelled)
+ {
+ return null;
+ }
+ DBRefEntry[] uprefs = DBRefUtils.selectRefs(seq.getDBRefs(),
+ new String[]
+ {
+ // jalview.datamodel.DBRefSource.PDB,
+ DBRefSource.UNIPROT,
+ // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord
+ // sys sources
+ });
+ // TODO: minimal list of DAS queries to make by querying with untyped ID if
+ // distinct from any typed IDs
+
+ List<DBRefEntry> ids = new ArrayList<>();
+ List<String> qstring = new ArrayList<>();
+ boolean dasCoordSysFound = false;
+
+ if (uprefs != null)
+ {
+ // do any of these ids match the source's coordinate system ?
+ for (int j = 0; !dasCoordSysFound && j < uprefs.length; j++)
+ {
+
+ for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())
+ {
+ if (DBRefUtils.isDasCoordinateSystem(csys.getAuthority(),
+ uprefs[j]))
+ {
+ debug("Launched fetcher for coordinate system "
+ + csys.getAuthority());
+ // Will have to pass any mapping information to the fetcher
+ // - the start/end for the DBRefEntry may not be the same as the
+ // sequence's start/end
+
+ System.out.println(
+ seq.getName() + " " + (seq.getDatasetSequence() == null)
+ + " " + csys.getUri());
+
+ dasCoordSysFound = true; // break's out of the loop
+ ids.add(uprefs[j]);
+ qstring.add(uprefs[j].getAccessionId());
+ }
+ else
+ {
+ System.out.println("IGNORE " + csys.getAuthority());
+ }
+ }
+ }
+ }
+
+ if (!dasCoordSysFound)
+ {
+ String id = null;
+ // try and use the name as the sequence id
+ if (seq.getName().indexOf("|") > -1)
+ {
+ id = seq.getName().substring(seq.getName().lastIndexOf("|") + 1);
+ if (id.trim().length() < 4)
+ {
+ // hack - we regard a significant ID as being at least 4
+ // non-whitespace characters
+ id = seq.getName().substring(0, seq.getName().lastIndexOf("|"));
+ if (id.indexOf("|") > -1)
+ {
+ id = id.substring(id.lastIndexOf("|") + 1);
+ }
+ }
+ }
+ else
+ {
+ id = seq.getName();
+ }
+ if (id != null)
+ {
+ DBRefEntry dbre = new DBRefEntry();
+ dbre.setAccessionId(id);
+ // Should try to call a general feature fetcher that
+ // queries many sources with name to discover applicable ID references
+ ids.add(dbre);
+ qstring.add(dbre.getAccessionId());
+ }
+ }
+
+ return new Object[] { ids, qstring };
+ }
+
+ /**
+ * examine the given sequence feature to determine if it should actually be
+ * turned into sequence annotation or database cross references rather than a
+ * simple sequence feature.
+ *
+ * @param seq
+ * the sequence to annotate
+ * @param f
+ * the jalview sequence feature generated from the DAS feature
+ * @param map
+ * the sequence feature attributes
+ * @param source
+ * the source that emitted the feature
+ * @return true if feature was consumed as another kind of annotation.
+ */
+ protected boolean parseSeqFeature(SequenceI seq, SequenceFeature f,
+ FEATURE feature, jalviewSourceI source)
+ {
+ SequenceI mseq = seq;
+ while (seq.getDatasetSequence() != null)
+ {
+ seq = seq.getDatasetSequence();
+ }
+ if (f.getType() != null)
+ {
+ String type = f.getType();
+ if (type.equalsIgnoreCase("protein_name"))
+ {
+ // parse name onto the alignment sequence or the dataset sequence.
+ if (seq.getDescription() == null
+ || seq.getDescription().trim().length() == 0)
+ {
+ // could look at the note series to pick out the first long name, for
+ // the moment just use the whole description string
+ seq.setDescription(f.getDescription());
+ }
+ if (mseq.getDescription() == null
+ || mseq.getDescription().trim().length() == 0)
+ {
+ // could look at the note series to pick out the first long name, for
+ // the moment just use the whole description string
+ mseq.setDescription(f.getDescription());
+ }
+ return true;
+ }
+ // check if source has biosapiens or other sequence ontology label
+ if (type.equalsIgnoreCase("DBXREF") || type.equalsIgnoreCase("DBREF"))
+ {
+ // try to parse the accession out
+
+ DBRefEntry dbr = new DBRefEntry();
+ dbr.setVersion(source.getTitle());
+ StringTokenizer st = new StringTokenizer(f.getDescription(), ":");
+ if (st.hasMoreTokens())
+ {
+ dbr.setSource(st.nextToken());
+ }
+ if (st.hasMoreTokens())
+ {
+ dbr.setAccessionId(st.nextToken());
+ }
+ seq.addDBRef(dbr);
+
+ if (f.links != null && f.links.size() > 0)
+ {
+ // feature is also appended to enable links to be seen.
+ // TODO: consider extending dbrefs to have their own links ?
+ // TODO: new feature: extract dbref links from DAS servers and add the
+ // URL pattern to the list of DB name associated links in the user's
+ // preferences ?
+ // for the moment - just fix up the existing feature so it displays
+ // correctly.
+ // f.setType(dbr.getSource());
+ // f.setDescription();
+ f.setValue("linkonly", Boolean.TRUE);
+ // f.setDescription("");
+ Vector newlinks = new Vector();
+ Enumeration it = f.links.elements();
+ while (it.hasMoreElements())
+ {
+ String elm;
+ UrlLink urllink = new UrlLink(elm = (String) it.nextElement());
+ if (urllink.isValid())
+ {
+ urllink.setLabel(f.getDescription());
+ newlinks.addElement(urllink.toString());
+ }
+ else
+ {
+ // couldn't parse the link properly. Keep it anyway - just in
+ // case.
+ debug("couldn't parse link string - " + elm);
+ newlinks.addElement(elm);
+ }
+ }
+ f.links = newlinks;
+ seq.addSequenceFeature(f);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * creates a jalview sequence feature from a das feature document
+ *
+ * @param feat
+ * @return sequence feature object created using dasfeature information
+ */
+ SequenceFeature newSequenceFeature(FEATURE feat, String nickname)
+ {
+ if (feat == null)
+ {
+ return null;
+ }
+ try
+ {
+ /**
+ * Different qNames for a DAS Feature - are string keys to the HashMaps in
+ * features "METHOD") || qName.equals("TYPE") || qName.equals("START") ||
+ * qName.equals("END") || qName.equals("NOTE") || qName.equals("LINK") ||
+ * qName.equals("SCORE")
+ */
+ String desc = new String();
+ if (feat.getNOTE() != null)
+ {
+ for (String note : feat.getNOTE())
+ {
+ desc += note;
+ }
+ }
+
+ int start = 0, end = 0;
+ float score = 0f;
+
+ try
+ {
+ start = Integer.parseInt(feat.getSTART().toString());
+ } catch (Exception ex)
+ {
+ }
+ try
+ {
+ end = Integer.parseInt(feat.getEND().toString());
+ } catch (Exception ex)
+ {
+ }
+ try
+ {
+ Object scr = feat.getSCORE();
+ if (scr != null)
+ {
+ score = (float) Double.parseDouble(scr.toString());
+
+ }
+ } catch (Exception ex)
+ {
+ }
+
+ SequenceFeature f = new SequenceFeature(getTypeString(feat.getTYPE()),
+ desc, start, end, score, nickname);
+
+ if (feat.getLINK() != null)
+ {
+ for (LINK link : feat.getLINK())
+ {
+ // Do not put feature extent in link text for non-positional features
+ if (f.begin == 0 && f.end == 0)
+ {
+ f.addLink(f.getType() + " " + link.getContent() + "|"
+ + link.getHref());
+ }
+ else
+ {
+ f.addLink(f.getType() + " " + f.begin + "_" + f.end + " "
+ + link.getContent() + "|" + link.getHref());
+ }
+ }
+ }
+
+ return f;
+ } catch (Exception e)
+ {
+ System.out.println("ERRR " + e);
+ e.printStackTrace();
+ System.out.println("############");
+ debug("Failed to parse " + feat.toString(), e);
+ return null;
+ }
+ }
+
+ private String getTypeString(TYPE type)
+ {
+ return type.getContent();
+ }
+
+ public boolean isRunning()
+ {
+ return running;
+ }
+
+}