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="http://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 }