001 /* 002 * Copyright 1999,2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.apache.commons.feedparser.network; 018 019 import java.net.URL; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.Iterator; 023 024 import org.apache.log4j.Logger; 025 026 /** 027 * Get a ResourceRequest for a given URL. The request is handled based on the 028 * URL. 029 * 030 * @author <a href="mailto:burton@openprivacy.org">Kevin A. Burton</a> 031 * @version $Id: ResourceRequestFactory.java 373622 2006-01-30 22:53:00Z mvdb $ 032 */ 033 public class ResourceRequestFactory { 034 035 private static Logger log = Logger.getLogger( ResourceRequestFactory.class.getName() ); 036 037 /** 038 * Specified in java.security to indicate the caching policy for successful 039 * name lookups from the name service.. The value is specified as as integer 040 * to indicate the number of seconds to cache the successful lookup. 041 * 042 * 043 * sun.net.inetaddr.ttl: 044 * 045 * This is a sun private system property which corresponds to 046 * networkaddress.cache.ttl. It takes the same value and has the same meaning, 047 * but can be set as a command-line option. However, the preferred way is to 048 * use the security property mentioned above. 049 * 050 * A value of -1 indicates "cache forever". 051 */ 052 public static int NETWORKADDRESS_CACHE_TTL = 5 * 60; 053 054 /** 055 * These properties specify the default connect and read timeout (resp.) for 056 * the protocol handler used by java.net.URLConnection. 057 * 058 * sun.net.client.defaultConnectTimeout specifies the timeout (in 059 * milliseconds) to establish the connection to the host. For example for 060 * http connections it is the timeout when establishing the connection to 061 * the http server. For ftp connection it is the timeout when establishing 062 * the connection to ftp servers. 063 * 064 * sun.net.client.defaultReadTimeout specifies the timeout (in milliseconds) 065 * when reading from input stream when a connection is established to a 066 * resource. 067 */ 068 public static int DEFAULT_CONNECT_TIMEOUT = 1 * 60 * 1000; 069 070 public static int DEFAULT_READ_TIMEOUT = DEFAULT_CONNECT_TIMEOUT; 071 072 /** 073 * Specify the maximum number of redirects to use. 074 */ 075 public static int DEFAULT_MAX_REDIRECTS = 5; 076 077 //FIXME: (should this be a linked list?) 078 private static ArrayList listeners = new ArrayList( 30 ); 079 080 private static HashMap schemeMap = null; 081 082 private static boolean transparentHTCacheEnabled = false; 083 084 /** 085 * When offline we either throw an exception or return content from the 086 * cache directly. This can be used to run code that does not depend on the 087 * network. 088 */ 089 private static boolean offline = false; 090 091 public static ResourceRequest getResourceRequest( String resource, 092 long ifModifiedSince ) throws NetworkException { 093 094 return getResourceRequest( resource, ifModifiedSince, null ); 095 096 } 097 098 /** 099 * 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 }