KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jnlp > sample > servlet > ResourceCatalog


1 /*
2  * @(#)ResourceCatalog.java 1.6 05/11/17
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 package jnlp.sample.servlet;
38 import java.util.HashMap JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.io.File JavaDoc;
42 import java.io.BufferedInputStream JavaDoc;
43 import javax.servlet.ServletContext JavaDoc;
44 import javax.xml.parsers.*;
45 import org.xml.sax.*;
46 import org.w3c.dom.*;
47 import jnlp.sample.util.VersionString;
48 import jnlp.sample.util.VersionID;
49
50 public class ResourceCatalog {
51     public static final String JavaDoc VERSION_XML_FILENAME = "version.xml";
52     
53     private Logger _log = null;
54     private ServletContext JavaDoc _servletContext = null;
55     
56     private HashMap JavaDoc _entries;
57     
58     /** Class to contain the information we know
59      * about a specific directory
60      */

61     static private class PathEntries {
62     /* Version-based entries at this particular path */
63     private List JavaDoc _versionXmlList;
64     private List JavaDoc _directoryList;
65     private List JavaDoc _platformList;
66     /* Last time this entry was updated */
67     private long _lastModified; // Last modified time of entry;
68

69     public PathEntries(List JavaDoc versionXmlList, List JavaDoc directoryList, List JavaDoc platformList, long lastModified) {
70         _versionXmlList = versionXmlList;
71         _directoryList = directoryList;
72         _platformList = platformList;
73         _lastModified = lastModified;
74     }
75     
76     
77     public void setDirectoryList(List JavaDoc dirList) {
78         _directoryList = dirList;
79     }
80
81     public List JavaDoc getVersionXmlList() { return _versionXmlList; }
82     public List JavaDoc getDirectoryList() { return _directoryList; }
83     public List JavaDoc getPlatformList() { return _platformList; }
84     
85     public long getLastModified() { return _lastModified; }
86     }
87     
88     public ResourceCatalog(ServletContext JavaDoc servletContext, Logger log) {
89     _entries = new HashMap JavaDoc();
90     _servletContext = servletContext;
91     _log = log;
92     }
93     
94     
95     public JnlpResource lookupResource(DownloadRequest dreq) throws ErrorResponseException {
96     // Split request up into path and name
97
String JavaDoc path = dreq.getPath();
98     String JavaDoc name = null;
99     String JavaDoc dir = null;
100     int idx = path.lastIndexOf('/');
101     if (idx == -1) {
102         name = path;
103     } else {
104         name = path.substring(idx + 1); // Exclude '/'
105
dir = path.substring(0, idx + 1); // Include '/'
106
}
107     
108     // Lookup up already parsed entries, and san directory for entries if neccesary
109
PathEntries pentries = (PathEntries)_entries.get(dir);
110     JnlpResource xmlVersionResPath = new JnlpResource(_servletContext, dir + VERSION_XML_FILENAME);
111     if (pentries == null || (xmlVersionResPath.exists() && xmlVersionResPath.getLastModified() > pentries.getLastModified())) {
112         _log.addInformational("servlet.log.scandir", dir);
113         List JavaDoc dirList = scanDirectory(dir, dreq);
114         // Scan XML file
115
List JavaDoc versionList = new ArrayList JavaDoc();
116         List JavaDoc platformList = new ArrayList JavaDoc();
117         parseVersionXML(versionList, platformList, dir, xmlVersionResPath);
118         pentries = new PathEntries(versionList, dirList, platformList, xmlVersionResPath.getLastModified());
119         _entries.put(dir, pentries);
120     }
121     
122     // Search for a match
123
JnlpResource[] result = new JnlpResource[1];
124     
125     if (dreq.isPlatformRequest()) {
126         int sts = findMatch(pentries.getPlatformList(), name, dreq, result);
127         if (sts != DownloadResponse.STS_00_OK) {
128         throw new ErrorResponseException(DownloadResponse.getJnlpErrorResponse(sts));
129         }
130     } else {
131         // First lookup in versions.xml file
132
int sts1 = findMatch(pentries.getVersionXmlList(), name, dreq, result);
133         if (sts1 != DownloadResponse.STS_00_OK) {
134         // Then lookup in directory
135
int sts2 = findMatch(pentries.getDirectoryList(), name, dreq, result);
136         if (sts2 != DownloadResponse.STS_00_OK) {
137
138             // fix for 4450104
139
// try rescan and see if it helps
140
pentries.setDirectoryList(scanDirectory(dir, dreq));
141             sts2 = findMatch(pentries.getDirectoryList(), name, dreq, result);
142             // try again after rescanning directory
143
if (sts2 != DownloadResponse.STS_00_OK) {
144             // Throw the most specific error code
145
throw new ErrorResponseException(DownloadResponse.getJnlpErrorResponse(Math.max(sts1, sts2)));
146             }
147         }
148         }
149     }
150     return result[0];
151     }
152     
153     /** This method finds the best match, or return the best error code. The
154      * result parameter must be an array with room for one element.
155      *
156      * If a match is found, the method returns DownloadResponse.STS_00_OK
157      * If one or more entries matches on: name, version-id, os, arch, and locale,
158      * then the one with the highest version-id is set in the result[0] field.
159      *
160      * If a match is not found, it returns an error code, either: ERR_10_NO_RESOURCE,
161      * ERR_11_NO_VERSION, ERR_20_UNSUP_OS, ERR_21_UNSUP_ARCH, ERR_22_UNSUP_LOCALE,
162      * ERR_23_UNSUP_JRE.
163      *
164      */

165     public int findMatch(List JavaDoc list, String JavaDoc name, DownloadRequest dreq, JnlpResource[] result) {
166     if (list == null) return DownloadResponse.ERR_10_NO_RESOURCE;
167     // Setup return values
168
VersionID bestVersionId = null;
169     int error = DownloadResponse.ERR_10_NO_RESOURCE;
170     VersionString vs = new VersionString(dreq.getVersion());
171     // Iterate through entries
172
for(int i = 0; i < list.size(); i++) {
173         JnlpResource respath = (JnlpResource)list.get(i);
174         VersionID vid = new VersionID(respath.getVersionId());
175         int sts = matchEntry(name, vs, dreq, respath, vid);
176         if (sts == DownloadResponse.STS_00_OK) {
177         if (result[0] == null || vid.isGreaterThan(bestVersionId)) {
178             result[0] = respath;
179             bestVersionId = vid;
180         }
181         } else {
182         error = Math.max(error, sts);
183         }
184     }
185     return (result[0] != null) ? DownloadResponse.STS_00_OK : error;
186     }
187     
188     public int matchEntry(String JavaDoc name, VersionString vs, DownloadRequest dreq, JnlpResource jnlpres, VersionID vid) {
189     if (!name.equals(jnlpres.getName())) {
190         return DownloadResponse.ERR_10_NO_RESOURCE;
191     }
192     if (!vs.contains(vid)) {
193         return DownloadResponse.ERR_11_NO_VERSION;
194     }
195     if (!prefixMatchLists(jnlpres.getOSList(), dreq.getOS())) {
196         return DownloadResponse.ERR_20_UNSUP_OS;
197     }
198     if (!prefixMatchLists(jnlpres.getArchList(), dreq.getArch())) {
199         return DownloadResponse.ERR_21_UNSUP_ARCH;
200     }
201     if (!prefixMatchLists(jnlpres.getLocaleList(), dreq.getLocale())) {
202         return DownloadResponse.ERR_22_UNSUP_LOCALE;
203     }
204     return DownloadResponse.STS_00_OK;
205     }
206
207        
208     private static boolean prefixMatchStringList(String JavaDoc[] prefixList, String JavaDoc target) {
209         // No prefixes matches everything
210
if (prefixList == null) return true;
211     // No target, but a prefix list does not match anything
212
if (target == null) return false;
213         for(int i = 0; i < prefixList.length; i++) {
214             if (target.startsWith(prefixList[i])) return true;
215         }
216         return false;
217     }
218     
219     /* Return true if at least one of the strings in 'prefixes' are a prefix
220      * to at least one of the 'keys'.
221      */

222     public boolean prefixMatchLists(String JavaDoc[] prefixes, String JavaDoc[] keys) {
223     // The prefixes are part of the server resources. If none is given,
224
// everything matches
225
if (prefixes == null) return true;
226     // If no os keyes was given, and the server resource is keyed of this,
227
// then return false.
228
if (keys == null) return false;
229     // Check for a match on a key
230
for(int i = 0; i < keys.length; i++) {
231         if (prefixMatchStringList(prefixes, keys[i])) return true;
232     }
233     return false;
234     }
235     
236     /** This method scans the directory pointed to by the
237      * given path and creates a list of ResourcePath elements
238      * that contains information about all the entries
239      *
240      * The version-based information is encoded in the file name
241      * given the following format:
242      *
243      * entry ::= <name> __ ( <options> ). <ext>
244      * options ::= <option> ( __ <options> )?
245      * option ::= V<version-id>
246      * | O<os>
247      * | A<arch>
248      * | L<locale>
249      *
250      */

251
252
253     private String JavaDoc jnlpGetPath(DownloadRequest dreq) {
254     // fix for 4474021
255
// try to manuually generate the filename
256
// extract file name
257
String JavaDoc path = dreq.getPath();
258     String JavaDoc filename = path.substring(path.lastIndexOf("/") + 1);
259     path = path.substring(0, path.lastIndexOf("/") + 1);
260     String JavaDoc name = filename;
261     String JavaDoc ext = null;
262     
263     if (filename.lastIndexOf(".") != -1) {
264         ext = filename.substring(filename.lastIndexOf(".") + 1);
265         
266         filename = filename.substring(0, filename.lastIndexOf("."));
267         
268     }
269     if (dreq.getVersion() != null) {
270         filename += "__V" + dreq.getVersion();
271     }
272     
273     String JavaDoc[] temp = dreq.getOS();
274     
275     if (temp != null) {
276         for (int i=0; i<temp.length; i++) {
277         filename += "__O" + temp[i];
278         }
279     }
280     
281     temp = dreq.getArch();
282     
283     if (temp != null) {
284         for (int i=0; i<temp.length; i++) {
285         filename += "__A" + temp[i];
286         }
287     }
288     temp = dreq.getLocale();
289     
290     if (temp != null) {
291         for (int i=0; i<temp.length; i++) {
292         filename += "__L" + temp[i];
293         }
294     }
295     
296     if (ext != null) {
297         filename += "." + ext;
298     }
299     
300     path += filename;
301     
302     return path;
303     }
304
305     public List JavaDoc scanDirectory(String JavaDoc dirPath, DownloadRequest dreq) {
306     ArrayList JavaDoc list = new ArrayList JavaDoc();
307
308     // fix for 4474021
309
if (_servletContext.getRealPath(dirPath) == null) {
310         String JavaDoc path = jnlpGetPath(dreq);
311       
312         String JavaDoc name = dreq.getPath().substring(path.lastIndexOf("/") + 1);
313     
314         JnlpResource jnlpres = new JnlpResource(_servletContext, name, dreq.getVersion(), dreq.getOS(), dreq.getArch(), dreq.getLocale(), path, dreq.getVersion());
315
316         // the file does not exist
317
if (jnlpres.getResource() == null) return null;
318
319         list.add(jnlpres);
320         return list;
321     }
322     File JavaDoc dir = new File JavaDoc(_servletContext.getRealPath(dirPath));
323     _log.addDebug("File directory: " + dir);
324     if (dir.exists() && dir.isDirectory()) {
325         File JavaDoc[] entries = dir.listFiles();
326         for(int i = 0; i < entries.length; i++) {
327         JnlpResource jnlpres = parseFileEntry(dirPath, entries[i].getName());
328         if (jnlpres != null) {
329             if (_log.isDebugLevel()) {
330             _log.addDebug("Read file resource: " + jnlpres);
331             }
332             list.add(jnlpres);
333         }
334         }
335     }
336     return list;
337     }
338     
339     private JnlpResource parseFileEntry(String JavaDoc dir, String JavaDoc filename) {
340     int idx = filename .indexOf("__");
341     if (idx == -1) return null;
342     
343     // Cut out name
344
String JavaDoc name = filename.substring(0, idx);
345     String JavaDoc rest = filename.substring(idx);
346     
347     // Cut out extension
348
idx = rest.lastIndexOf('.');
349     String JavaDoc extension = "";
350     if (idx != -1 ) {
351         extension = rest.substring(idx);
352         rest = rest .substring(0, idx);
353     }
354     
355     // Parse options
356
String JavaDoc versionId = null;
357     ArrayList JavaDoc osList = new ArrayList JavaDoc();
358     ArrayList JavaDoc archList = new ArrayList JavaDoc();
359     ArrayList JavaDoc localeList = new ArrayList JavaDoc();
360     while(rest.length() > 0) {
361         /* Must start with __ at this point */
362         if (!rest.startsWith("__")) return null;
363         rest = rest.substring(2);
364         // Get option and argument
365
char option = rest.charAt(0);
366         idx = rest.indexOf("__");
367         String JavaDoc arg = null;
368         if (idx == -1) {
369         arg = rest.substring(1);
370         rest = "";
371         } else {
372         arg = rest.substring(1, idx);
373         rest = rest.substring(idx);
374         }
375         switch(option) {
376         case 'V': versionId = arg; break;
377         case 'O': osList.add(arg); break;
378         case 'A': archList.add(arg); break;
379         case 'L': localeList.add(arg); break;
380         default: return null; // error
381
}
382     }
383     
384     return new JnlpResource(_servletContext,
385                 name + extension, /* Resource name in URL request */
386                 versionId,
387                 listToStrings(osList),
388                 listToStrings(archList),
389                 listToStrings(localeList),
390                 dir + filename, /* Resource name in WAR file */
391                 versionId);
392     }
393     
394     private String JavaDoc[] listToStrings(List JavaDoc list) {
395     if (list.size() == 0) return null;
396     return (String JavaDoc[])list.toArray(new String JavaDoc[list.size()]);
397     }
398     
399     // Returns false if parsing failed
400
private void parseVersionXML(final List JavaDoc versionList, final List JavaDoc platformList,
401                  final String JavaDoc dir, final JnlpResource versionRes) {
402     if (!versionRes.exists()) return;
403                 
404     // Parse XML into a more understandable format
405
XMLNode root = null;
406     try {
407         DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
408         DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
409         Document doc = docBuilder.parse(new BufferedInputStream JavaDoc(versionRes.getResource().openStream()));
410         doc.getDocumentElement().normalize();
411         
412         // Convert document into an XMLNode structure, since we already got utility methods
413
// to handle these. We should really use the data-binding stuff here - but that will come
414
// later
415
//
416
root = XMLParsing.convert(doc.getDocumentElement());
417     } catch (SAXParseException err) {
418         _log.addWarning("servlet.log.warning.xml.parsing",
419                 versionRes.getPath(),
420                 Integer.toString(err.getLineNumber()),
421                 err.getMessage());
422         return;
423     } catch (Throwable JavaDoc t) {
424         _log.addWarning("servlet.log.warning.xml.reading", versionRes.getPath(), t);
425         return;
426     }
427     
428     // Check that root element is a <jnlp> tag
429
if (!root.getName().equals("jnlp-versions")) {
430         _log.addWarning("servlet.log.warning.xml.missing-jnlp", versionRes.getPath());
431         return;
432     }
433     
434     // Visit all <resource> elements
435
XMLParsing.visitElements(root, "<resource>", new XMLParsing.ElementVisitor() {
436             public void visitElement(XMLNode node) {
437             XMLNode pattern = XMLParsing.findElementPath(node, "<pattern>");
438             if (pattern == null) {
439                 _log.addWarning("servlet.log.warning.xml.missing-pattern", versionRes.getPath());
440             } else {
441                 // Parse pattern
442
String JavaDoc name = XMLParsing.getElementContent(pattern , "<name>", "");
443                 String JavaDoc versionId = XMLParsing.getElementContent(pattern , "<version-id>");
444                 String JavaDoc[] os = XMLParsing.getMultiElementContent(pattern, "<os>");
445                 String JavaDoc[] arch = XMLParsing.getMultiElementContent(pattern, "<arch>");
446                 String JavaDoc[] locale = XMLParsing.getMultiElementContent(pattern, "<locale>");
447                 // Get return request
448
String JavaDoc file = XMLParsing.getElementContent(node, "<file>");
449                 if (versionId == null || file == null) {
450                 _log.addWarning("servlet.log.warning.xml.missing-elems", versionRes.getPath());
451                 } else {
452                 JnlpResource res = new JnlpResource(_servletContext,
453                                     name,
454                                     versionId,
455                                     os,
456                                     arch,
457                                     locale,
458                                     dir + file,
459                                     versionId);
460                 if (res.exists()) {
461                     versionList.add(res);
462                     if (_log.isDebugLevel()) {
463                     _log.addDebug("Read resource: " + res);
464                     }
465                 } else {
466                     _log.addWarning("servlet.log.warning.missing-file", file, versionRes.getPath());
467                 }
468                 }
469             }
470             }
471         });
472     
473     // Visit all <resource> elements
474
XMLParsing.visitElements(root, "<platform>", new XMLParsing.ElementVisitor() {
475             public void visitElement(XMLNode node) {
476             XMLNode pattern = XMLParsing.findElementPath(node, "<pattern>");
477             if (pattern == null) {
478                 _log.addWarning("servlet.log.warning.xml.missing-pattern", versionRes.getPath());
479             } else {
480                 // Parse pattern
481
String JavaDoc name = XMLParsing.getElementContent(pattern , "<name>", "");
482                 String JavaDoc versionId = XMLParsing.getElementContent(pattern , "<version-id>");
483                 String JavaDoc[] os = XMLParsing.getMultiElementContent(pattern, "<os>");
484                 String JavaDoc[] arch = XMLParsing.getMultiElementContent(pattern, "<arch>");
485                 String JavaDoc[] locale = XMLParsing.getMultiElementContent(pattern, "<locale>");
486                 // Get return request
487
String JavaDoc file = XMLParsing.getElementContent(node, "<file>");
488                 String JavaDoc productId = XMLParsing.getElementContent(node, "<product-version-id>");
489                 
490                 if (versionId == null || file == null || productId == null) {
491                 _log.addWarning("servlet.log.warning.xml.missing-elems2", versionRes.getPath());
492                 } else {
493                 JnlpResource res = new JnlpResource(_servletContext,
494                                     name,
495                                     versionId,
496                                     os,
497                                     arch,
498                                     locale,
499                                     dir + file,
500                                     productId);
501                 if (res.exists()) {
502                     platformList.add(res);
503                     if (_log.isDebugLevel()) {
504                     _log.addDebug("Read platform resource: " + res);
505                     }
506                 } else {
507                     _log.addWarning("servlet.log.warning.missing-file", file, versionRes.getPath());
508                 }
509                 }
510             }
511             }
512         });
513     }
514 }
515
516
517
Popular Tags