View Javadoc

1   /*
2    * Copyright 2004 Sun Microsystems, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  
18  package com.sun.syndication.fetcher.impl;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.URLConnection;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.Iterator;
26  import java.util.Properties;
27  import java.util.Set;
28  
29  import com.sun.syndication.feed.synd.SyndFeed;
30  import com.sun.syndication.fetcher.FeedFetcher;
31  import com.sun.syndication.fetcher.FetcherEvent;
32  import com.sun.syndication.fetcher.FetcherException;
33  import com.sun.syndication.fetcher.FetcherListener;
34  
35  
36  public abstract class AbstractFeedFetcher implements FeedFetcher {
37  	private final Set fetcherEventListeners;
38  	private String userAgent;
39  	private boolean usingDeltaEncoding;	
40      
41  	public AbstractFeedFetcher() {
42  		fetcherEventListeners = Collections.synchronizedSet(new HashSet());
43  		
44  		Properties props = new Properties(System.getProperties());
45  		String resourceName = "fetcher.properties";
46  		
47  		try {
48  			InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resourceName);
49  			if (inputStream == null) {
50  			    inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
51  			}			
52  			if (inputStream != null) {
53  				props.load(inputStream);
54  				System.getProperties().putAll(props);
55  				inputStream.close();
56  			} else {
57  				System.err.println("Could not find " + resourceName + " on classpath");
58  			}
59  		} catch (IOException e) {
60  			// do nothing - we don't want to fail just because we could not find the version
61  			System.err.println("Error reading " + resourceName + " from classpath: " + e.getMessage());
62  		}		
63  		
64  		
65  		setUserAgent(DEFAULT_USER_AGENT + " Ver: " + System.getProperty("rome.fetcher.version", "UNKNOWN"));
66  	}
67  
68  	/***
69  	 * @return the User-Agent currently being sent to servers
70  	 */
71  	public synchronized String getUserAgent() {
72  		return userAgent;
73  	}
74  
75  	/***
76  	 * @param string The User-Agent to sent to servers
77  	 */
78  	public synchronized void setUserAgent(String string) {
79  		userAgent = string;
80  	}
81  
82  	/***
83  	 * @param eventType The event type to fire
84  	 * @param connection the current connection
85  	 */
86  	protected void fireEvent(String eventType, URLConnection connection) {	    
87  		fireEvent(eventType, connection.getURL().toExternalForm(), null);
88  	}
89  	
90  	
91  	/***
92  	 * @param eventType The event type to fire
93  	 * @param connection the current connection
94  	 * @param feed The feed to pass to the event
95  	 */
96  	protected void fireEvent(String eventType, URLConnection connection, SyndFeed feed) {	    
97  		fireEvent(eventType, connection.getURL().toExternalForm(), feed);
98  	}
99  
100 	/***
101 	 * @param eventType The event type to fire
102 	 * @param urlStr the current url as a string
103 	 */
104 	protected void fireEvent(String eventType, String urlStr) {
105 	    fireEvent(eventType, urlStr, null);
106 	}	
107 	
108 	/***
109 	 * @param eventType The event type to fire
110 	 * @param urlStr the current url as a string
111 	 * @param feed The feed to pass to the event
112 	 */
113 	protected void fireEvent(String eventType, String urlStr, SyndFeed feed) {
114 		FetcherEvent fetcherEvent = new FetcherEvent(this, urlStr, eventType, feed);
115 		synchronized(fetcherEventListeners) {
116 			Iterator iter = fetcherEventListeners.iterator();
117 			while ( iter.hasNext()) {
118 				FetcherListener fetcherEventListener = (FetcherListener) iter.next();
119 				fetcherEventListener.fetcherEvent(fetcherEvent);							
120 			}					
121 		}
122 	}	
123 	
124 	/***
125 	 * @see com.sun.syndication.fetcher.FeedFetcher#addFetcherEventListener(com.sun.syndication.fetcher.FetcherListener)
126 	 */
127 	public void addFetcherEventListener(FetcherListener listener) {
128 		if (listener != null) {
129 			fetcherEventListeners.add(listener);		
130 		}	
131 		
132 	}
133 
134 	/***
135 	 * @see com.sun.syndication.fetcher.FeedFetcher#removeFetcherEventListener(com.sun.syndication.fetcher.FetcherListener)
136 	 */
137 	public void removeFetcherEventListener(FetcherListener listener) {
138 		if (listener != null) {
139 			fetcherEventListeners.remove(listener);		
140 		}		
141 	}
142 
143     /***
144      * @return Returns the useDeltaEncoding.
145      */
146     public synchronized boolean isUsingDeltaEncoding() {
147         return usingDeltaEncoding;
148     }
149     /***
150      * @param useDeltaEncoding The useDeltaEncoding to set.
151      */
152     public synchronized void setUsingDeltaEncoding(boolean useDeltaEncoding) {
153         this.usingDeltaEncoding = useDeltaEncoding;
154     }		
155 	
156 	/***
157 	 * <p>Handles HTTP error codes.</p>
158 	 *
159 	 * @param responseCode the HTTP response code
160 	 * @throws FetcherException if response code is in the range 400 to 599 inclusive
161 	 */
162 	protected void handleErrorCodes(int responseCode) throws FetcherException {
163 		// Handle 2xx codes as OK, so ignore them here
164 		// 3xx codes are handled by the HttpURLConnection class
165 	    if (responseCode == 403) {
166 	        // Authentication is required
167 	        throwAuthenticationError(responseCode);
168 	    } else if (responseCode >= 400 && responseCode < 500) {
169 			throw4XXError(responseCode);
170 		} else if (responseCode >= 500 && responseCode < 600) {
171 			throw new FetcherException(responseCode, "The server encounted an error. HTTP Response code was:" + responseCode);
172 		}
173 	}
174 	
175 	protected void throw4XXError(int responseCode) throws FetcherException {
176 		throw new FetcherException(responseCode, "The requested resource could not be found. HTTP Response code was:" + responseCode);
177 	}
178 
179 	protected void throwAuthenticationError(int responseCode) throws FetcherException {
180 		throw new FetcherException(responseCode, "Authentication required for that resource. HTTP Response code was:" + responseCode);
181 	}
182 	
183 	/***
184 	 * <p>Combine the entries in two feeds into a single feed.</p>
185 	 * 
186 	 * <p>The returned feed will have the same data as the newFeed parameter, with 
187 	 * the entries from originalFeed appended to the end of its entries.</p>
188 	 * 
189 	 * @param originalFeed
190 	 * @param newFeed
191 	 * @return
192 	 */
193 	public static SyndFeed combineFeeds(SyndFeed originalFeed, SyndFeed newFeed) {
194 	    SyndFeed result;
195         try {
196             result = (SyndFeed) newFeed.clone();
197             
198             result.getEntries().addAll(result.getEntries().size(), originalFeed.getEntries());
199             
200             return result;
201         } catch (CloneNotSupportedException e) {
202             IllegalArgumentException iae = new IllegalArgumentException("Cannot clone feed");
203             iae.initCause(e);
204             throw iae;
205         }        
206 	}
207 	
208 }