1 /*
2 * Copyright 1999,2004 The Apache Software Foundation.
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 package org.apache.commons.feedparser.network;
18
19 import java.net.URL;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.Iterator;
23
24 import org.apache.log4j.Logger;
25
26 /**
27 * Get a ResourceRequest for a given URL. The request is handled based on the
28 * URL.
29 *
30 * @author <a href="mailto:burton@openprivacy.org">Kevin A. Burton</a>
31 * @version $Id: ResourceRequestFactory.java 373622 2006-01-30 22:53:00Z mvdb $
32 */
33 public class ResourceRequestFactory {
34
35 private static Logger log = Logger.getLogger( ResourceRequestFactory.class.getName() );
36
37 /**
38 * Specified in java.security to indicate the caching policy for successful
39 * name lookups from the name service.. The value is specified as as integer
40 * to indicate the number of seconds to cache the successful lookup.
41 *
42 *
43 * sun.net.inetaddr.ttl:
44 *
45 * This is a sun private system property which corresponds to
46 * networkaddress.cache.ttl. It takes the same value and has the same meaning,
47 * but can be set as a command-line option. However, the preferred way is to
48 * use the security property mentioned above.
49 *
50 * A value of -1 indicates "cache forever".
51 */
52 public static int NETWORKADDRESS_CACHE_TTL = 5 * 60;
53
54 /**
55 * These properties specify the default connect and read timeout (resp.) for
56 * the protocol handler used by java.net.URLConnection.
57 *
58 * sun.net.client.defaultConnectTimeout specifies the timeout (in
59 * milliseconds) to establish the connection to the host. For example for
60 * http connections it is the timeout when establishing the connection to
61 * the http server. For ftp connection it is the timeout when establishing
62 * the connection to ftp servers.
63 *
64 * sun.net.client.defaultReadTimeout specifies the timeout (in milliseconds)
65 * when reading from input stream when a connection is established to a
66 * resource.
67 */
68 public static int DEFAULT_CONNECT_TIMEOUT = 1 * 60 * 1000;
69
70 public static int DEFAULT_READ_TIMEOUT = DEFAULT_CONNECT_TIMEOUT;
71
72 /**
73 * Specify the maximum number of redirects to use.
74 */
75 public static int DEFAULT_MAX_REDIRECTS = 5;
76
77 //FIXME: (should this be a linked list?)
78 private static ArrayList listeners = new ArrayList( 30 );
79
80 private static HashMap schemeMap = null;
81
82 private static boolean transparentHTCacheEnabled = false;
83
84 /**
85 * When offline we either throw an exception or return content from the
86 * cache directly. This can be used to run code that does not depend on the
87 * network.
88 */
89 private static boolean offline = false;
90
91 public static ResourceRequest getResourceRequest( String resource,
92 long ifModifiedSince ) throws NetworkException {
93
94 return getResourceRequest( resource, ifModifiedSince, null );
95
96 }
97
98 /**
99 * Get a ResourceRequest for the protocol represented in the resource URL.
100 * It is important that we use a ResourceRequest implementation that supports
101 * fetching the URL.
102 *
103 *
104 */
105 public static ResourceRequest getResourceRequest( String resource,
106 long ifModifiedSince,
107 String etag ) throws NetworkException {
108
109 //log.debug( resource );
110
111 //make sure we are initialized correctly.
112 ResourceRequestFactory.init();
113
114 //make sure we have an index..
115
116 int schemeIndex = resource.indexOf( ":" );
117
118 if ( schemeIndex == -1 )
119 throw new NetworkException( "Unknown scheme: '" + resource + "'" );
120
121 String scheme = resource.substring( 0, schemeIndex );
122
123 if ( scheme == null || scheme.equals( "" ) )
124 throw new MalformedResourceException( "Not supported: " + resource );
125
126 Class clazz = (Class)schemeMap.get( scheme );
127
128 if ( clazz == null ) {
129 throw new MalformedResourceException( "Scheme not supported: " + scheme );
130 }
131
132 try {
133
134 ResourceRequest request = (ResourceRequest)clazz.newInstance();
135
136 request.setResource( resource );
137
138 //setup resource request options.
139 request.setIfModifiedSince( ifModifiedSince );
140
141 //set the etag... when its null nothing will happen
142 request.setEtag( etag );
143
144 request.init();
145
146 return request;
147
148 } catch ( Throwable t ) {
149 throw new NetworkException( t );
150 }
151
152 }
153
154 /**
155 *
156 * @see #getResourceRequest( String )
157 *
158 */
159 public static ResourceRequest getResourceRequest( String resource ) throws NetworkException {
160 return getResourceRequest( resource, -1 );
161 }
162
163 /**
164 *
165 * @see #getResourceRequest( String )
166 *
167 */
168 public static ResourceRequest getResourceRequest( URL resource ) throws NetworkException {
169 return getResourceRequest( resource.toString() );
170 }
171
172 /**
173 * Add an event listener to this instance of the factory. This provides a
174 * mechanism to give default listeners to each new ResourceRequest.
175 *
176 *
177 */
178 public static void addEventListener( NetworkEventListener listener ) {
179
180 listeners.add( listener );
181
182 }
183
184 /**
185 * Get all event listeners.
186 *
187 *
188 */
189 public static Iterator getNetworkEventListeners() {
190
191 return listeners.iterator();
192
193 }
194
195 /**
196 * Make sure the factory is initialized. Called once per JVM instance.
197 *
198 *
199 */
200 private synchronized static void init() {
201
202 //set the authenticator to use
203
204 //FIXME: remove this until we figure out how to do proxy authentication.
205 //java.net.Authenticator.setDefault ( new Authenticator() );
206
207 // A full list of properties is available here:
208
209 // http://java.sun.com/j2se/1.4.2/docs/guide/net/properties.html
210
211 System.setProperty( "sun.net.inetaddr.ttl",
212 Integer.toString( NETWORKADDRESS_CACHE_TTL ) );
213
214 System.setProperty( "networkaddress.cache.ttl",
215 Integer.toString( NETWORKADDRESS_CACHE_TTL ) );
216
217 System.setProperty( "sun.net.client.defaultReadTimeout",
218 Integer.toString( DEFAULT_READ_TIMEOUT ) );
219
220 System.setProperty( "sun.net.client.defaultConnectTimeout",
221 Integer.toString( DEFAULT_CONNECT_TIMEOUT ) );
222
223 System.setProperty( "http.maxRedirects",
224 Integer.toString( DEFAULT_MAX_REDIRECTS ) );
225
226 if ( schemeMap == null ) {
227
228 schemeMap = new HashMap();
229
230 schemeMap.put( "file", URLResourceRequest.class );
231 schemeMap.put( "http", URLResourceRequest.class );
232 schemeMap.put( "https", URLResourceRequest.class );
233 schemeMap.put( BlockingResourceRequest.SCHEME, BlockingResourceRequest.class );
234
235 }
236
237 }
238
239 /**
240 * Return true if we support fetching content with the given scheme.
241 * Examples would be "http" and "file"
242 *
243 *
244 */
245 public static boolean isSupportedScheme( String scheme ) {
246
247 return schemeMap.get( scheme ) != null;
248
249 }
250
251 /**
252 * When the transparent HTCache is enabled we will keep content local
253 * similar to the Mozilla cache and return the cached copy and use
254 * if-Modified-Since when necessary.
255 *
256 *
257 */
258 public static void setTransparentHTCacheEnabled( boolean enabled ) {
259 transparentHTCacheEnabled = enabled;
260 }
261
262 /**
263 * Return true if we can enable the htcache.
264 *
265 *
266 */
267 public static boolean isTransparentHTCacheEnabled() {
268 return transparentHTCacheEnabled;
269 }
270
271 /**
272 * Enable/disable offline operation.
273 *
274 *
275 */
276 public static void setOffline( boolean offline ) {
277 ResourceRequestFactory.offline = offline;
278 }
279
280 /**
281 *
282 *
283 *
284 */
285 public static boolean isOffline() {
286 return offline;
287 }
288
289 }