Fix #759.
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.news / src / net / sourceforge / phpeclipse / news / Channel.java
1 package net.sourceforge.phpeclipse.news;
2
3 import java.io.InputStream;
4 import java.io.PushbackInputStream;
5 import java.net.URL;
6 import java.net.URLConnection;
7 import java.util.ArrayList;
8 import java.util.HashSet;
9
10 import javax.xml.parsers.DocumentBuilder;
11 import javax.xml.parsers.DocumentBuilderFactory;
12
13 import org.eclipse.core.runtime.Preferences;
14 import org.w3c.dom.Document;
15 import org.w3c.dom.Element;
16 import org.w3c.dom.NodeList;
17 import org.xml.sax.InputSource;
18
19 /**
20  * @author jnegre - http://www.jnegre.org/
21  *
22  * (c)Copyright 2002 J�r�me N�gre
23  * 
24  */
25 public class Channel {
26
27     private final String url;
28     private final String title;
29
30     private boolean refreshing = false;
31     private String errorMessage = null;
32     private boolean unread = false;
33     
34     private ArrayList items = new ArrayList();
35     private HashSet readUids = null;
36
37     /**
38      * Constructor for Channel.
39      */
40     public Channel(String title, String url) {
41         this(title, url, null);
42     }
43
44     public Channel(String title, String url, HashSet readUids) {
45         this.title = title;
46         this.url = url;
47         this.readUids = readUids;
48     }
49
50
51     public void update() {
52         update(Plugin.getDefault().getPluginPreferences());
53     }
54
55
56     public void update(Preferences prefs) {
57             ArrayList newItems = new ArrayList();
58             String newErrorMessage = null;
59         try {
60             
61             URLConnection conn = new URL(url).openConnection();
62             conn.setRequestProperty("User-Agent", Plugin.userAgent);
63             if(prefs.getBoolean(Plugin.FORCE_CACHE_PREFERENCE)) {
64                 conn.setRequestProperty("Pragma", "no-cache");
65                         conn.setRequestProperty("Cache-Control", "no-cache");
66             }
67             InputStream stream = conn.getInputStream();
68             
69             /* workaround a bug of crimson (it seems to ignore the encoding
70              * if it does not get it the first time it reads bytes from
71              * the stream. We use a PushbackInputStream to be sure that the
72              * encoding declaration is in the buffer)
73              */
74             PushbackInputStream pbStream = new PushbackInputStream(stream,64);
75             byte[] buffer = new byte[64];
76             int pos = 0;
77             while(pos != 64) {
78                 pos += pbStream.read(buffer, pos, 64-pos);
79             }
80             pbStream.unread(buffer);
81             //end workaround
82             
83             DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
84             InputSource inputSource = new InputSource(pbStream);
85             Document doc = parser.parse(inputSource);
86             pbStream.close();
87             NodeList itemNodes = doc.getElementsByTagName("item");
88             for (int i = 0; i < itemNodes.getLength(); i++) {
89                 Item aNewItem = new Item(this, (Element) itemNodes.item(i));
90                 if(aNewItem.isBanned()) continue;
91                 if(readUids!=null && readUids.remove(aNewItem.getUID())) {
92                         aNewItem.setReadFlag(true);
93                 }
94                 int indexOld = items.indexOf(aNewItem);
95                 if(indexOld != -1) {
96                     newItems.add(items.get(indexOld));
97                 } else {
98                     newItems.add(aNewItem);
99                 }
100                 
101             }
102             this.readUids = null;
103         } catch(Exception e) {
104             newErrorMessage = e.toString();
105             Plugin.logInfo("Error in channel update",e);
106         }
107         
108         synchronized(this) {
109             this.errorMessage = newErrorMessage;
110             if(newErrorMessage == null) {
111                 this.items = newItems;
112                 computeUnRead();
113             }
114         }
115     }
116
117     /**
118      * Returns the url.
119      * @return String
120      */
121     public String getUrl() {
122         return url;
123     }
124
125     /**
126      * Returns the errorMessage.
127      * @return String
128      */
129     public synchronized String getErrorMessage() {
130         return errorMessage;
131     }
132
133     /**
134      * Returns the items.
135      * @return ArrayList
136      */
137     public synchronized ArrayList getItems() {
138         return new ArrayList(items);
139     }
140
141     /**
142      * @see java.lang.Object#toString()
143      */
144     public String toString() {
145         return "Channel at "+url;
146     }
147
148     /**
149      * Returns the title.
150      * @return String
151      */
152     public String getTitle() {
153         return title;
154     }
155
156     /**
157      * Returns the refreshing.
158      * @return boolean
159      */
160     public boolean isRefreshing() {
161         return refreshing;
162     }
163
164     /**
165      * Sets the refreshing.
166      * @param refreshing The refreshing to set
167      */
168     public void setRefreshing(boolean refreshing) {
169         this.refreshing = refreshing;
170     }
171
172     /**
173      * Returns the unread.
174      * @return boolean
175      */
176     public boolean isUnread() {
177         return unread;
178     }
179
180     public synchronized void computeUnRead() {
181         this.unread = false;
182         for (int i = 0; i < items.size(); i++) {
183             this.unread = this.unread || !((Item)items.get(i)).isReadFlag();
184         }
185     }
186     
187     public String getUID() {
188         return "CHA" + url;
189     }
190
191 }