merge from 2_4_Release branch
[jalview.git] / src / org / biojava / dasobert / das / FeatureThread.java
1 /*
2  *                    BioJava development code
3  *
4  * This code may be freely distributed and modified under the
5  * terms of the GNU Lesser General Public Licence.  This should
6  * be distributed with the code.  If you do not have a copy,
7  * see:
8  *
9  *      http://www.gnu.org/copyleft/lesser.html
10  *
11  * Copyright for this code is held jointly by the individual
12  * authors.  These should be listed in @author doc comments.
13  *
14  * For more information on the BioJava project and its aims,
15  * or to join the biojava-l mailing list, visit the home page
16  * at:
17  *
18  *      http://www.biojava.org/
19  *
20  * Created on 21.09.2004
21  * @author Andreas Prlic
22  *
23  */
24
25 package org.biojava.dasobert.das;
26
27 import java.net.*;
28 import java.util.*;
29 import java.util.logging.*;
30
31 import org.biojava.dasobert.dasregistry.*;
32 import org.biojava.dasobert.eventmodel.*;
33
34 /**
35  * a thread that connects to a DAS - Feature service and gets the features
36  * 
37  * @author Andreas Prlic
38  */
39
40 public class FeatureThread implements Runnable
41 {
42
43   /**
44    * number of times the client tries to reconnect to the server if a "come back
45    * later" is returned. the server should provide a reasonable estimation how
46    * long it will take him to create results. if this number of requests is
47    * still not successfull, give up.
48    */
49   public static int MAX_COME_BACK_ITERATIONS = 5;
50
51   public static int MAX_NR_FEATURES = 300;
52
53   static Logger logger = Logger.getLogger("org.biojava.spice");
54
55   Das1Source dasSource;
56
57   String ac;
58
59   List featureListeners;
60
61   Thread thread;
62
63   public FeatureThread(String accessionCode, Das1Source dasSource)
64   {
65     this.dasSource = dasSource;
66     this.ac = accessionCode;
67     featureListeners = new ArrayList();
68   }
69
70   public void addFeatureListener(FeatureListener li)
71   {
72     featureListeners.add(li);
73   }
74
75   public void clearFeatureListeners()
76   {
77     featureListeners.clear();
78   }
79
80   public synchronized void stop()
81   {
82     thread = null;
83     notify();
84   }
85
86   public void run()
87   {
88     Thread me = Thread.currentThread();
89     while (thread == me)
90     {
91       String url = dasSource.getUrl();
92       String queryString = url + "features?segment=" + ac;
93       URL cmd = null;
94       try
95       {
96         cmd = new URL(queryString);
97       } catch (MalformedURLException e)
98       {
99         logger.warning("got MalformedURL from das source " + dasSource);
100         e.printStackTrace();
101
102       }
103
104       logger.info("requesting features from " + cmd);
105       DAS_FeatureRetrieve ftmp = new DAS_FeatureRetrieve(cmd);
106
107       int comeBackLater = ftmp.getComeBackLater();
108       int securityCounter = 0;
109       while ((thread == me) && (comeBackLater > 0))
110       {
111         securityCounter++;
112         if (securityCounter >= MAX_COME_BACK_ITERATIONS)
113         {
114           comeBackLater = -1;
115           break;
116
117         }
118         notifyComeBackLater(comeBackLater);
119         // server is still calculating - asks us to come back later
120         try
121         {
122           wait(comeBackLater);
123         } catch (InterruptedException e)
124         {
125           comeBackLater = -1;
126           break;
127         }
128
129         ftmp.reload();
130         comeBackLater = ftmp.getComeBackLater();
131       }
132
133       if (!(thread == me))
134       {
135         break;
136       }
137
138       List features = ftmp.get_features();
139       String version = ftmp.getVersion();
140
141       // a fallback mechanism to prevent DAS sources from bringing down spice
142       if (features.size() > MAX_NR_FEATURES)
143       {
144         logger
145                 .warning("DAS source returned more than " + MAX_NR_FEATURES
146                         + "features. "
147                         + " throwing away excess features at " + cmd);
148         features = features.subList(0, MAX_NR_FEATURES);
149       }
150
151       // notify FeatureListeners
152       Map[] feats = (Map[]) features.toArray(new Map[features.size()]);
153       notifyFeatureListeners(feats, version);
154
155       break;
156
157     }
158     thread = null;
159
160   }
161
162   public void start()
163   {
164     thread = new Thread(this);
165     thread.start();
166   }
167
168   private void notifyFeatureListeners(Map[] feats, String version)
169   {
170     logger.finest("FeatureThread found " + feats.length + " features");
171     FeatureEvent fevent = new FeatureEvent(feats, dasSource, version);
172     Iterator fiter = featureListeners.iterator();
173     while (fiter.hasNext())
174     {
175       FeatureListener fi = (FeatureListener) fiter.next();
176       fi.newFeatures(fevent);
177     }
178   }
179
180   /**
181    * the Annotation server requested to be queried again in a while
182    * 
183    * @param comeBackLater
184    */
185   private void notifyComeBackLater(int comeBackLater)
186   {
187     FeatureEvent event = new FeatureEvent(new HashMap[0], dasSource, "");
188     event.setComeBackLater(comeBackLater);
189     Iterator fiter = featureListeners.iterator();
190     while (fiter.hasNext())
191     {
192       FeatureListener fi = (FeatureListener) fiter.next();
193       fi.comeBackLater(event);
194     }
195
196   }
197
198 }