View Javadoc

1   package org.robsite.extension.rss;
2   
3   import java.awt.event.ActionEvent;
4   import java.awt.event.ActionListener;
5   import java.awt.event.MouseAdapter;
6   import java.awt.event.MouseEvent;
7   import java.awt.event.MouseListener;
8   
9   import java.io.InputStream;
10  
11  import java.net.URL;
12  
13  import javax.swing.ImageIcon;
14  import javax.swing.JLabel;
15  import javax.swing.SwingUtilities;
16  import javax.swing.Timer;
17  
18  import oracle.ide.Ide;
19  import oracle.ide.controls.StatusBarControl;
20  import oracle.ide.net.URLFactory;
21  import oracle.ide.util.Assert;
22  
23  import org.robsite.extension.rss.model.Channel;
24  import org.robsite.extension.rss.model.Channels;
25  import org.robsite.extension.rss.model.DirectoryParser;
26  
27  /***
28   * The runnable that periodically checks for new news.
29   * 
30   * @author brian_duff@sourceforge.net
31   * @version $Revision: 1.1.1.1 $
32   */
33  final class NewsCheckRunnable implements Runnable, ActionListener
34  {
35    private boolean _isRunning;
36  
37    private final NewsFeedExtension _extension;
38    
39    private final ResHelper _res = new ResHelper( "NewsChecker." );
40  
41    NewsCheckRunnable( NewsFeedExtension extension )
42    {
43      _extension = extension;
44      _isRunning = true;
45    }
46    
47    public synchronized void stop()
48    {
49      _isRunning = false;
50      notify();
51    }
52    
53    /***
54     * Force an immediate update of all channels.
55     */
56    public synchronized void forceUpdate()
57    {
58      notify();
59    }
60    
61    /***
62     * Called on a timer tick.
63     * 
64     * @param ae the timer action
65     */
66    public synchronized void actionPerformed( ActionEvent ae )
67    {
68      forceUpdate();
69    }
70    
71    private synchronized boolean isRunning()
72    {
73      return _isRunning;
74    }
75  
76    public void run()
77    {
78      while ( isRunning() )
79      {
80        // Go to sleep until the timer notifies us to wake up or forceUpdate()
81        // is called.
82        synchronized( this )
83        {
84          try
85          {
86            wait();
87          }
88          catch ( InterruptedException ie )
89          {
90            stop();
91            return;
92          }
93        }
94        
95        // Check that we're still actually running, i.e. that stop() was not
96        // called.
97        if ( !isRunning() )
98        {
99          return;
100       }
101       
102       boolean newItems = checkForNews();
103       
104       // If the news dockable window is not visible, show the status bar
105       // notification message.
106       if ( _extension.getNewsDockable() == null && newItems )
107       {
108         showStatusBarMessage();
109       }
110     }
111   }
112   
113   static void checkDirectory( NewsFeedPreferences prefs )
114     throws Exception
115   {
116     URL url = URLFactory.newURL( prefs.getDirectoryURL() );
117     InputStream is = url.openStream();
118     DirectoryParser dirParser = new DirectoryParser();
119     dirParser.parse( is, prefs.getChannels() );
120   }
121   
122   private boolean checkForNews()
123   {
124     boolean newUnreadItems = false;
125     boolean hadFailures = false;
126     try
127     {
128       setWindowBusy( true );
129       
130       SwingUtilities.invokeLater( new Runnable() 
131       {
132         public void run()
133         {
134           Ide.getStatusBar().setText( _res.getRes( "CheckingNews" ) );
135         }
136       } );
137       
138       HTTPUtil.setHTTPTimeout( 
139         NewsFeedExtension.get().getPreferences().getHTTPTimeout() );
140       Channels channels = NewsFeedExtension.get().getChannels();
141       
142       // First, check for channels.
143       setWindowStatus( _res.getRes( "CheckingForChannels" ) );
144       try
145       {
146         checkDirectory( NewsFeedExtension.get().getPreferences() );
147         setWindowStatus( "" );        
148       }
149       catch ( Exception e )
150       {
151         hadFailures = true;
152         setWindowStatus( _res.getRes( "FailedToGetChannels" ) );
153         e.printStackTrace();
154         sleep( 2000 );
155       }
156 
157           
158       for ( int i=0; i < channels.getSubscribedChannels().size(); i++ )
159       {
160         // If we're stopped part-way through the loop, bail out early.
161         if ( !isRunning() ) return false;
162         final Channel c = (Channel) channels.getSubscribedChannels().get( i );
163         try
164         {
165           setWindowStatus( _res.getRes( "CheckingChannel", String.valueOf( c ) ) );
166           if ( channels.checkChannel( i ) > 0 )
167           {
168             newUnreadItems = true;
169           }
170           setWindowStatus( "" );
171         }
172         catch ( Exception e )
173         {
174           hadFailures = true;
175           setWindowStatus( _res.getRes( "FailedToCheck", c.getURL() ) );
176           
177           e.printStackTrace();
178           
179           // Back off for a small delay so the user has time to see the 
180           // status message.
181           sleep( 2000 );          
182         }
183         
184 
185       }
186             
187     }
188     catch ( RuntimeException re )
189     {
190       Assert.println( "Runtime Exception during news check" );
191       re.printStackTrace();
192     }
193     finally
194     {
195       setWindowBusy( false );
196       
197       SwingUtilities.invokeLater( new Runnable() 
198       {
199         public void run()
200         {
201           Ide.getStatusBar().setText( "" );
202         }
203       } );      
204       HTTPUtil.resetHTTPTimeout();
205       if ( hadFailures )
206       {
207         setWindowStatus( _res.getRes( "FailedToConnect" ) );
208       }
209     }
210     return newUnreadItems;
211   }
212   
213   private void showStatusBarMessage()
214   {
215     SwingUtilities.invokeLater( new Runnable() 
216     {
217       public void run()
218       {
219         Ide.getStatusBar().setText( _res.getRes( "GotNewNews" )  );
220         final JLabel l = new JLabel();
221         l.setIcon( new ImageIcon( NewsCheckRunnable.class.getResource( "xml.gif" )) );
222         l.setText( _res.getRes( "ClickToRead" ) );
223         
224         final MouseListener labelListener = new MouseAdapter() {
225           public void mouseClicked( MouseEvent me )
226           {
227             if ( me.getButton() == MouseEvent.BUTTON1 )
228             {
229               try
230               {
231                 Commands.getAction( Commands.VIEW_NEWS_DOCKABLE ).performAction();
232                 ((StatusBarControl)Ide.getStatusBar()).remove( l );
233                 l.removeMouseListener( this );
234               }
235               catch ( Exception e ) {}
236             }
237           }
238         };
239         l.addMouseListener( labelListener );
240         
241         ((StatusBarControl)Ide.getStatusBar()).add( l );
242         Timer t = new Timer( 
243           1000 * _extension.getPreferences().getStatusMessageDuration(), 
244         new ActionListener() 
245         {
246           public void actionPerformed( ActionEvent ae )
247           {
248             ((StatusBarControl)Ide.getStatusBar()).remove( l );
249             l.removeMouseListener( labelListener );
250           }
251         });
252         t.setRepeats( false );
253         t.start();
254       }
255     } );
256   }
257   
258   private void sleep( int ms )
259   {
260     try
261     {
262       Thread.sleep( ms );
263     }
264     catch ( InterruptedException ie )
265     {
266       
267     }
268   }
269   
270   private void setWindowBusy( final boolean isBusy )
271   {
272     if ( _extension.getNewsDockable() != null )
273     {
274       SwingUtilities.invokeLater( new Runnable() 
275       {
276         public void run()
277         {
278           _extension.getNewsDockable().getPanel().setBusy( isBusy );
279         }
280       } );
281     }
282   }
283   
284   private void setWindowStatus( final String text )
285   {
286     if ( _extension.getNewsDockable() != null )
287     {
288       SwingUtilities.invokeLater( new Runnable() 
289       {
290         public void run()
291         {
292           _extension.getNewsDockable().getPanel().setStatusText( text );
293         }
294       } );
295     }
296   }
297 }