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         }