001 package com.croftsoft.core.lang.classloader; 002 003 import java.io.*; 004 import java.lang.reflect.*; 005 import java.net.*; 006 import java.util.*; 007 008 /********************************************************************* 009 * <P> 010 * @version 011 * 1998-05-30 012 * @author 013 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 014 *********************************************************************/ 015 016 public class CacheClassLoader extends NetClassLoader 017 ////////////////////////////////////////////////////////////////////// 018 ////////////////////////////////////////////////////////////////////// 019 { 020 021 /** A list of pathnames of cached files keyed by remote URL name. */ 022 protected Hashtable cacheHashtable = new Hashtable ( ); 023 024 protected File cacheDir; 025 026 ////////////////////////////////////////////////////////////////////// 027 ////////////////////////////////////////////////////////////////////// 028 029 /********************************************************************* 030 * Loads a remote class and launches its main() method. 031 * 032 * @param 033 * Command-line arguments: 034 * <OL> 035 * <LI> The URL name for the codebase. 036 * <LI> The name of the class with the "main(args)" method. 037 * <LI> The name of the local persistent resource cache directory. 038 * <LI> Subsequent arguments to be passed to the invoked main method. 039 * </OL> 040 * Example 041 *********************************************************************/ 042 public static void main ( String [ ] args ) 043 throws Exception 044 ////////////////////////////////////////////////////////////////////// 045 { 046 String [ ] shiftedArgs = new String [ args.length - 3 ]; 047 for ( int i = 3; i < args.length; i++ ) 048 { 049 shiftedArgs [ i - 3 ] = args [ i ]; 050 } 051 052 launchMain ( args [ 0 ], args [ 1 ], args [ 2 ], shiftedArgs ); 053 } 054 055 /********************************************************************* 056 * Loads a remote class and launches its main() method. 057 *********************************************************************/ 058 public static void launchMain ( 059 String codebaseURLName, 060 String mainClassName, 061 String cacheDirName, 062 String [ ] args ) 063 throws ClassNotFoundException, 064 IllegalAccessException, 065 MalformedURLException 066 ////////////////////////////////////////////////////////////////////// 067 { 068 URL codebaseURL = new URL ( codebaseURLName ); 069 File cacheDir = new File ( cacheDirName ); 070 CacheClassLoader cacheClassLoader 071 = new CacheClassLoader ( codebaseURL, cacheDir ); 072 Class c = cacheClassLoader.loadClass ( mainClassName ); 073 cacheClassLoader.invokeMain ( c, args ); 074 } 075 076 /********************************************************************* 077 * Ex: "http://www.mysticmayhem.com/lib/", 078 * "C:\jcache\www.mysticmayhem.com\" 079 *********************************************************************/ 080 public CacheClassLoader ( URL codebaseURL, File cacheDir ) 081 ////////////////////////////////////////////////////////////////////// 082 { 083 super ( codebaseURL ); 084 085 if ( !cacheDir.exists ( ) ) 086 { 087 throw new IllegalArgumentException ( "directory \"" + cacheDir 088 + "\" does not exist" ); 089 } 090 if ( !cacheDir.isDirectory ( ) ) 091 { 092 throw new IllegalArgumentException ( "cacheDir \"" + cacheDir 093 + "\" must be a directory" ); 094 } 095 this.cacheDir = cacheDir; 096 } 097 098 /********************************************************************* 099 *********************************************************************/ 100 public synchronized InputStream getResourceAsStream ( String name ) 101 ////////////////////////////////////////////////////////////////////// 102 { 103 InputStream inputStream = null; 104 BufferedInputStream in = null; 105 BufferedOutputStream out = null; 106 107 try 108 { 109 URL url = getResource ( name ); 110 String remoteName = url.toExternalForm ( ); 111 String localName = ( String ) cacheHashtable.get ( remoteName ); 112 if ( localName != null ) 113 { 114 System.out.println ( "Retrieving \"" + localName + "\"..." ); 115 return new FileInputStream ( localName ); 116 } 117 118 String host = url.getHost ( ); 119 String prot = url.getProtocol ( ); 120 int port = url.getPort ( ); 121 122 File cacheFile = new File ( cacheDir, prot + File.separator 123 + host + File.separator + "port" 124 + ( port == -1 ? "" : Integer.toString ( port ) ) 125 + File.separator + name ); 126 cacheFile = new File ( cacheFile.getCanonicalPath ( ) ); 127 localName = cacheFile.getCanonicalPath ( ); 128 129 System.out.println ( "Comparing \"" + localName + "\"..." ); 130 URLConnection urlConnection = url.openConnection ( ); 131 if ( cacheFile.exists ( ) ) 132 { 133 urlConnection.setIfModifiedSince ( 134 cacheFile.lastModified ( ) ); 135 } 136 137 if ( urlConnection instanceof HttpURLConnection ) 138 { 139 HttpURLConnection httpURLConnection 140 = ( HttpURLConnection ) urlConnection; 141 142 httpURLConnection.setFollowRedirects ( true ); 143 httpURLConnection.setRequestMethod ( "GET" ); 144 145 int responseCode = httpURLConnection.getResponseCode ( ); 146 System.out.println ( 147 httpURLConnection.getResponseMessage ( ) 148 + ", " + httpURLConnection.getContentLength ( ) + " bytes" 149 + ", " + new Date ( httpURLConnection.getDate ( ) ) 150 + ", " + new Date ( httpURLConnection.getLastModified ( ) ) ); 151 if ( responseCode != HttpURLConnection.HTTP_OK ) 152 { 153 return null; 154 } 155 } 156 157 inputStream = urlConnection.getInputStream ( ); 158 if ( inputStream == null ) return null; 159 160 if ( cacheFile.exists ( ) ) 161 { 162 long lastModified = urlConnection.getLastModified ( ); 163 // long date = urlConnection.getDate ( ); 164 // long remoteDelta = date - lastModified; 165 // long cacheDelta 166 // = new Date ( ).getTime ( ) - cacheFile.lastModified ( ); 167 // long length = urlConnection.getContentLength ( ); 168 169 // if ( ( date > 0 ) 170 // && ( lastModified > 0 ) 171 // && ( length > -1 ) 172 // && ( length == cacheFile.length ( ) ) 173 // && ( remoteDelta >= cacheDelta ) ) 174 175 if ( ( lastModified > 0 ) 176 && ( lastModified < cacheFile.lastModified ( ) ) ) 177 { 178 inputStream.close ( ); 179 cacheHashtable.put ( remoteName, localName ); 180 System.out.println ( "Retrieving \"" + localName + "\"..." ); 181 return new FileInputStream ( cacheFile ); 182 } 183 } 184 185 File parentFile = new File ( cacheFile.getParent ( ) ); 186 parentFile.mkdirs ( ); 187 188 localName = cacheFile.getCanonicalPath ( ); 189 System.out.println ( "CACHING \"" + localName + "\"..." ); 190 191 in = new BufferedInputStream ( inputStream ); 192 out = new BufferedOutputStream ( new FileOutputStream ( 193 cacheFile ) ); 194 195 int i; 196 while ( ( i = in.read ( ) ) > -1 ) out.write ( i ); 197 198 out.close ( ); 199 in.close ( ); 200 201 cacheHashtable.put ( remoteName, localName ); 202 203 System.out.println ( "Retrieving \"" + localName + "\"..." ); 204 return new FileInputStream ( localName ); 205 } 206 catch ( Exception ex ) 207 { 208 try { inputStream.close ( ); } catch ( Exception ex1 ) { } 209 try { in.close ( ); } catch ( Exception ex1 ) { } 210 try { out.close ( ); } catch ( Exception ex1 ) { } 211 ex.printStackTrace ( ); 212 return null; 213 } 214 } 215 216 ////////////////////////////////////////////////////////////////////// 217 ////////////////////////////////////////////////////////////////////// 218 }