KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > appserver > server > httpPresentation > PresentationLoader


1
2 /*
3  * Enhydra Java Application Server Project
4  *
5  * The contents of this file are subject to the Enhydra Public License
6  * Version 1.1 (the "License"); you may not use this file except in
7  * compliance with the License. You may obtain a copy of the License on
8  * the Enhydra web site ( http://www.enhydra.org/ ).
9  *
10  * Software distributed under the License is distributed on an "AS IS"
11  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
12  * the License for the specific terms governing rights and limitations
13  * under the License.
14  *
15  * The Initial Developer of the Enhydra Application Server is Lutris
16  * Technologies, Inc. The Enhydra Application Server and portions created
17  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
18  * All Rights Reserved.
19  *
20  * Contributor(s):
21  *
22  * $Id: PresentationLoader.java,v 1.2 2005/03/24 10:51:16 slobodan Exp $
23  */

24
25
26
27
28
29 package com.lutris.appserver.server.httpPresentation;
30
31 //import com.lutris.http.*;
32
import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.util.Hashtable JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36
37 import com.lutris.logging.LogChannel;
38 import com.lutris.logging.Logger;
39
40 /**
41  * Loader for presentation objects and resources associated with an
42  * application. It also manages a cache of resources.
43  *
44  * @version $Revision: 1.2 $
45  * @author Mark Diekhans
46  * @since 1.8
47  * @see HttpPresentationManager
48  */

49 class PresentationLoader {
50     /**
51      * Prefix added to the file name portion of the URL. The
52      * resulting names is used to search for classes and
53      * files on the class path.
54      */

55     private final String JavaDoc presentationPrefix;
56
57     /**
58      * Mime type converter.
59      */

60     private Mime mime;
61
62     /**
63      * Class loader for the application's classes.
64      */

65     private ClassLoader JavaDoc appClassLoader;
66
67     /**
68      * Cache for loaded objects. If null, presentation classes are not cached.
69      */

70     private Hashtable JavaDoc presObjCache;
71
72     /**
73      * Cache for resource presentation objects. If null, resource presentation
74      * classes are not cached.
75      */

76     private Hashtable JavaDoc resourceObjCache;
77
78     /**
79      * Applications log channel. No logging is done if null.
80      */

81     private LogChannel logChannel;
82
83     /**
84      * Is DEBUG1 logging enabled?
85      */

86     private boolean debug1LoggingEnabled;
87
88     /**
89      * Constructor.
90      *
91      * @param appPresentationPrefix Prefix added to the file name portion
92      * of the URL. The resulting names is used to search for classes and
93      * files on the class path.
94      * @param applicationClassLoader The class loader to use for the application.
95      * @param cacheClasses Enables or disables caching of presentation object
96      * classes in memory.
97      * @param cacheFiles Enables or disables caching of files (html, gif, etc)
98      * that are servered as part of the application.
99      * @param presLogChannel Log channel for the presentation. Maybe null.
100      */

101     protected PresentationLoader(String JavaDoc appPresentationPrefix,
102                                  ClassLoader JavaDoc applicationClassLoader,
103                                  boolean cacheClasses,
104                                  boolean cacheFiles,
105                                  LogChannel presLogChannel)
106             throws HttpPresentationException {
107     logChannel = presLogChannel;
108     if (logChannel != null) {
109         debug1LoggingEnabled = logChannel.isEnabled(Logger.DEBUG1);
110         }
111         appClassLoader = applicationClassLoader;
112         presentationPrefix = cleanUrlPath(appPresentationPrefix);
113         mime = new Mime();
114         if (cacheClasses) {
115             presObjCache = new Hashtable JavaDoc();
116         }
117         if (cacheFiles) {
118             resourceObjCache = new Hashtable JavaDoc();
119         }
120     }
121
122     /**
123      * Clean up a path name taken from a URL, removing such uglyness
124      * as `./', `//', `//' and `\'. Strips off leading and trailing
125      * `/' and `\'. Uses `/', since this is really a URL, not a file path.
126      *
127      * Includes bug fix submitted by Ben Warren
128      */

129     private String JavaDoc cleanUrlPath(String JavaDoc urlPath)
130             throws HttpPresentationException {
131         // Tokenize on `/' and `\', but drop leading and training spaces,
132
// since they sometimes get dragged in from broken config files.
133

134         // Do a quick scan through the string to look to look for anything
135
// that is amiss. The idea is to avoid calling the string tokenizer
136
// unless we have to. If there is nothing to do then this quick test
137
// make this routine about 4 times faster.
138
int i=0;
139         int len = urlPath.length();
140
141
142         if (len != 0 && urlPath.charAt(0)=='/') { //FIX - add 'len != 0'test.
143
// This is pretty common and quick to handle here.
144
urlPath = urlPath.substring(1);
145           len--;
146         }
147
148         if (len !=0 ) {//FIX - move above block outside this test.
149

150             // if we start or end with a '/' then we are ugly.
151
// otherwsie scan through the string looking for '\' or "./" or "//"
152
boolean uglyness = (urlPath.charAt(0) == '/' || urlPath.charAt(len-1) == '/');
153             while (!uglyness && i < len) {
154                 char c = urlPath.charAt(i);
155                 if (c =='\\') {
156                     uglyness = true;
157                 }
158                 else if (c=='/' && i > 0 ) {
159                     char c0 = urlPath.charAt(i-1);
160                     uglyness = ( c0 == '.' || c0 == '/');
161                 }
162                 i++;
163             }
164
165             if (!uglyness) {
166                 return urlPath;
167             }
168         }
169         // end quick test.
170

171         // The quick test found a problem...
172

173         StringTokenizer JavaDoc tokens =
174             new StringTokenizer JavaDoc(urlPath.trim(), "/\\", false);
175         StringBuffer JavaDoc newPath = new StringBuffer JavaDoc();
176
177
178         // Loop through path elements, dropping uninteresting parts
179
// of the name.
180
while (tokens.hasMoreTokens()) {
181             String JavaDoc name = tokens.nextToken();
182             if (!(name.equals("/") || name.equals("\\")
183                   || name.equals(".") || name.equals(""))) {
184                 if (newPath.length() > 0) {
185                     newPath.append('/');
186                 }
187                 newPath.append(name);
188             }
189         }
190         return newPath.toString();
191     }
192
193
194     /**
195      * Concert a URL path name to class names. If the path appears invalid, a
196      * bogus class (but reasonable looking) name will be generated which will
197      * lead to an error when loading.
198      */

199     private String JavaDoc convertToClassName(String JavaDoc urlPath) {
200         String JavaDoc className = urlPath;
201         int idx, start, end;
202
203         // Drop MIME extension
204
idx = className.lastIndexOf('.');
205         if (idx > 0) {
206             className = className.substring(0, idx);
207         }
208
209         // Convert the URL separator to `.'. Note `\' is not a legal
210
// URL separator
211
className = className.replace('/','.');
212
213         // Drop leading or training `.'
214
start = 0;
215         end = className.length()-1;
216         if (className.charAt(start) == '.') {
217             start++;
218         }
219         if (className.charAt(end) == '.') {
220             end--;
221         }
222         if (start >= end) {
223             // Bad name; put it back so it generates a better error.
224
start = 0;
225             end = className.length()-1;
226         }
227
228         return className.substring(start, end+1);
229     }
230
231     /**
232      * Load a presentation object by searching the applications class path.
233      *
234      * @param urlPath The path to the presentation object extracted from
235      * the URL. It will converted to a class name.
236      * @exception ClassNotFoundException if this loader or the system loader
237      * can not find or successfully load the class.
238      */

239     private synchronized HttpPresentation loadPresentationObject(String JavaDoc urlPath)
240             throws ClassNotFoundException JavaDoc, IllegalAccessException JavaDoc,
241             InstantiationException JavaDoc {
242         String JavaDoc className = convertToClassName(urlPath);
243
244         Class JavaDoc classObj = null;
245     if (presObjCache != null) {
246             classObj = (Class JavaDoc)presObjCache.get(className);
247     }
248
249         if (classObj == null) {
250             // Load class, instantiate object and add to cache.
251
if (appClassLoader != null) {
252                 classObj = appClassLoader.loadClass(className);
253             } else {
254                 //FIXME: not needed when our own class loader is working.
255
classObj = Class.forName(className);
256             }
257         if (presObjCache != null) {
258                 presObjCache.put(className, classObj);
259         }
260         }
261         return (HttpPresentation)classObj.newInstance();
262     }
263
264     /**
265      * Load create a static file presentation for a standard file.
266      * The class loader is used as find and open the file.
267      */

268     private HttpPresentation loadResourcePresentation(String JavaDoc urlPath,String JavaDoc mimeType)
269         throws ClassNotFoundException JavaDoc, IllegalAccessException JavaDoc,
270                InstantiationException JavaDoc, HttpPresentationException,
271                FilePresentationException, IOException JavaDoc {
272         HttpPresentation resourceObj;
273
274         if (resourceObjCache != null) {
275             resourceObj = (HttpPresentation)resourceObjCache.get(urlPath);
276             if (resourceObj == null) {
277                 resourceObj = new CachedFilePresentation(appClassLoader,
278                                                          urlPath, mimeType);
279                 resourceObjCache.put(urlPath, resourceObj);
280             }
281         } else {
282             resourceObj = new CopyFilePresentation(appClassLoader,
283                                                    urlPath, mimeType);
284         }
285         return resourceObj;
286     }
287
288     /**
289      * Determine if a request URL references a presentation object.
290      *
291      * @param request The request for the presentation.
292      * @return true if the URL has a presentation object MIME type.
293      */

294     protected boolean isPresentationRequest(HttpPresentationRequest request)
295             throws HttpPresentationException {
296         return mime.getType(request.getPresentationObjectPath()).equals("object/presentation");
297     }
298
299     /**
300      * Load a presentation object or create a presentation object to
301      * deliver a file.
302      */

303     protected HttpPresentation loadPresentation(String JavaDoc urlPath)
304             throws ClassNotFoundException JavaDoc, IllegalAccessException JavaDoc,
305             InstantiationException JavaDoc, HttpPresentationException,
306             FilePresentationException, IOException JavaDoc {
307         HttpPresentation presObj;
308         String JavaDoc presPath;
309         String JavaDoc mimeType = mime.getType(urlPath);
310
311         try {
312             if (mimeType.equals("object/presentation")) {
313                 presPath = presentationPrefix + "/" + cleanUrlPath(urlPath);
314         if (debug1LoggingEnabled) {
315             logChannel.write(Logger.DEBUG1, "loadPresentationObject: " + urlPath);
316                 }
317                 presObj = loadPresentationObject(presPath);
318             } else {
319         if (debug1LoggingEnabled) {
320             logChannel.write(Logger.DEBUG1, "loadPresentationObject: "
321                      + urlPath + " " + mimeType);
322                 }
323                 /*
324                  * If a class is getting loaded by the client; don't use the
325                  * presentation prefix. Class must be requested by full
326                  * class name.
327                  */

328                 if (mimeType.equals("application/java-vm")
329                     || mimeType.equals("application/java-archive")) {
330                     presPath = cleanUrlPath(urlPath);
331                 } else {
332                     presPath = presentationPrefix + "/" + cleanUrlPath(urlPath);
333                 }
334                 presObj = loadResourcePresentation(presPath,mimeType);
335             }
336         } catch (ClassNotFoundException JavaDoc except) {
337         if (debug1LoggingEnabled) {
338         logChannel.write(Logger.DEBUG1, " not found: " + urlPath);
339             }
340             throw except;
341         }
342         return presObj;
343     }
344
345     /**
346      * Determine if the PO cache is enabled.
347      *
348      * @return <code>true</code> is the cache is enabled.
349      */

350     protected boolean isPOCacheEnabled() {
351         return (presObjCache != null);
352     }
353
354     /**
355      * Return the number of entries in the PO cache.
356      *
357      * @return the number of entries in the cache or 0 is disabled.
358      */

359     protected int sizeofPOCache() {
360         if (presObjCache != null) {
361             return presObjCache.size();
362         } else {
363             return 0;
364         }
365     }
366
367     /**
368      * Determine if the file resource class cache is enabled.
369      *
370      * @return <code>true</code> is the cache is enabled.
371      */

372     protected boolean isResourceCacheEnabled() {
373         return (resourceObjCache != null);
374     }
375
376     /**
377      * Return the number of entries in the resource cache.
378      *
379      * @return the number of entries in the cache or 0 is disabled.
380      */

381     protected int sizeofResourceCache() {
382         if (resourceObjCache != null) return resourceObjCache.size();
383     else return 0;
384     }
385
386     /**
387      * Get a file associated with the application. The file is located
388      * in the same manner as presentation objects are located. That is,
389      * prepending the <CODE>presentationPrefix</CODE> to the specified
390      * path and searching the class path for a directory or JAR containing
391      * the file.
392      *
393      * @param appfileName The file name relative to the
394      * to the application's <CODE>presentationPrefix</CODE>.
395      * @return An input stream associated with the file.
396      * @exception IOException If the file can not be found or opened.
397      */

398     protected InputStream JavaDoc getAppFileAsStream(String JavaDoc appFileName)
399             throws IOException JavaDoc, HttpPresentationException {
400         String JavaDoc path = presentationPrefix + "/" + cleanUrlPath(appFileName);
401         InputStream JavaDoc input = appClassLoader.getResourceAsStream(path);
402         if (input == null) {
403             throw new HttpPresentationException("File \"" + appFileName + "\" not found on application class path");
404         }
405         return input;
406     }
407
408     /**
409      * Flush the presentation object and resource caches.
410      */

411     protected void flushCache() {
412         if (presObjCache != null) {
413             presObjCache = new Hashtable JavaDoc();
414         }
415         if (resourceObjCache != null) {
416             resourceObjCache = new Hashtable JavaDoc();
417         }
418     }
419
420     /**
421      * Returns the mime type for the URL path.
422      *
423      * @param urlPath the URL path.
424      */

425     protected String JavaDoc getMimeType(String JavaDoc urlPath) {
426         return mime.getType(urlPath);
427     }
428
429     /** Add a new mime type to extension mapping. */
430     public void addMimeType(String JavaDoc mimeType, String JavaDoc extension) {
431         mime.addType(mimeType, extension);
432     }
433
434
435     /**
436      * Get the application class loader.
437      *
438      * @return The application class loader.
439      */

440     protected ClassLoader JavaDoc getAppClassLoader() {
441         return appClassLoader;
442     }
443 }
444
Popular Tags