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.io.InputStreamReader;
23  import java.net.HttpURLConnection;
24  import java.net.URL;
25  import java.util.zip.GZIPInputStream;
26  
27  import org.apache.commons.httpclient.Header;
28  import org.apache.commons.httpclient.HttpClient;
29  import org.apache.commons.httpclient.HttpException;
30  import org.apache.commons.httpclient.HttpMethod;
31  import org.apache.commons.httpclient.methods.GetMethod;
32  
33  import com.sun.syndication.feed.synd.SyndFeed;
34  import com.sun.syndication.fetcher.FetcherEvent;
35  import com.sun.syndication.fetcher.FetcherException;
36  import com.sun.syndication.io.FeedException;
37  import com.sun.syndication.io.SyndFeedInput;
38  
39  /***
40   * @author Nick Lothian
41   */
42  public class HttpClientFeedFetcher extends AbstractFeedFetcher {
43  	private FeedFetcherCache feedInfoCache;
44  	
45  	public HttpClientFeedFetcher() {
46  		super();
47  	}
48  
49  	
50  	/***
51  	 * @param cache
52  	 */
53  	public HttpClientFeedFetcher(FeedFetcherCache cache) {
54  		this();
55  		this.feedInfoCache = cache;
56  	}
57  
58  	/***
59  	 * @see com.sun.syndication.fetcher.FeedFetcher#retrieveFeed(java.net.URL)
60  	 */
61  	public SyndFeed retrieveFeed(URL feedUrl) throws IllegalArgumentException, IOException, FeedException, FetcherException {
62  		if (feedUrl == null) {
63  			throw new IllegalArgumentException("null is not a valid URL");
64  		}
65  		// TODO Fix this
66  		//System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
67  		HttpClient client = new HttpClient();		
68  		
69  		
70  		System.setProperty("httpclient.useragent", getUserAgent());
71  		String urlStr = feedUrl.toString();
72  		if (feedInfoCache != null) {
73  			// get the feed info from the cache
74  			SyndFeedInfo syndFeedInfo = feedInfoCache.getFeedInfo(feedUrl);
75  			if (syndFeedInfo == null) {
76  				// this feed is not in the cache
77  								
78  				// retrieve feed
79  				HttpMethod method = new GetMethod(urlStr);
80  				try {
81  					syndFeedInfo = new SyndFeedInfo();
82  					
83  					// this may be different to feedURL because of 3XX redirects
84  					syndFeedInfo.setUrl(new URL(urlStr));
85  					syndFeedInfo.setId(feedUrl.toString());
86  					
87  					SyndFeed feed = retrieveFeed(null, client, urlStr, method);					
88  					
89  					syndFeedInfo.setSyndFeed(feed);
90  					
91  					Header lastModifiedHeader = method.getResponseHeader("Last-Modified");
92  					if (lastModifiedHeader != null) {
93  					    syndFeedInfo.setLastModified(lastModifiedHeader.getValue());
94  					}
95  					
96  					Header eTagHeader = method.getResponseHeader("ETag");
97  					if (eTagHeader != null) {
98  					    syndFeedInfo.setETag(eTagHeader.getValue());
99  					}
100 					
101 					feedInfoCache.setFeedInfo(new URL(urlStr), syndFeedInfo);
102 										
103 					return feed;
104 				} finally {
105 					method.releaseConnection();
106 				}
107 			} else {
108 				// feed is in cache
109 				HttpMethod method = new GetMethod(urlStr);
110 				try {
111 				    
112 				    SyndFeed feed = retrieveFeed(syndFeedInfo, client, urlStr, method);
113 				    
114 				    return feed;
115 
116 				} finally {
117 					method.releaseConnection();
118 				}				    
119 			}		
120 		} else {
121 		    // cache is not in use		    
122 			HttpMethod method = new GetMethod(urlStr);
123 			try {
124 				return retrieveFeed(null, client, urlStr, method);
125 			} finally {
126 				method.releaseConnection();
127 			}
128 		}
129 	}
130 
131 
132 	/***
133 	 * @param client
134 	 * @param urlStr
135 	 * @param method
136 	 * @return
137 	 * @throws IOException
138 	 * @throws HttpException
139 	 * @throws FetcherException
140 	 * @throws FeedException
141 	 */
142 	private SyndFeed retrieveFeed(SyndFeedInfo syndFeedInfo, HttpClient client, String urlStr, HttpMethod method) throws IOException, HttpException, FetcherException, FeedException {
143 	    if (syndFeedInfo != null) {
144 		    method.setRequestHeader("If-None-Match", syndFeedInfo.getETag());
145 		    
146 		    if (syndFeedInfo.getLastModified() instanceof String) {
147 		        method.setRequestHeader("If-Modified-Since", (String)syndFeedInfo.getLastModified());
148 		    }
149 	    }
150 	    
151 	    method.setFollowRedirects(true);			
152 		
153 		int statusCode = client.executeMethod(method);
154 		fireEvent(FetcherEvent.EVENT_TYPE_FEED_POLLED, urlStr);
155 		
156 		handleErrorCodes(statusCode);
157 		if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED && syndFeedInfo != null) {
158 		    fireEvent(FetcherEvent.EVENT_TYPE_FEED_UNCHANGED, urlStr);
159 		    return syndFeedInfo.getSyndFeed();
160 		}
161 		
162 		fireEvent(FetcherEvent.EVENT_TYPE_FEED_RETRIEVED, urlStr);			
163 		
164 		InputStream stream = null;
165 		if ((method.getResponseHeader("Content-Encoding") != null) && ("gzip".equals(method.getResponseHeader("Content-Encoding").getValue()))) {		
166 		    stream = new GZIPInputStream(method.getResponseBodyAsStream());
167 		} else {
168 		    stream = method.getResponseBodyAsStream();
169 		}		
170 		try {				
171 			InputStreamReader reader = new InputStreamReader(stream);
172 			SyndFeedInput input = new SyndFeedInput();
173 			SyndFeed feed = input.build(reader);
174 							
175 			return feed;
176 			
177 		} finally {
178 		    if (stream != null) {
179 		        stream.close();
180 		    }
181 			
182 		}
183 	}
184 }