KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > activation > registries > MailcapFile


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)MailcapFile.java 1.23 05/11/16
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.activation.registries;
29
30 import java.io.*;
31 import java.util.*;
32
33 public class MailcapFile {
34
35     /**
36      * A Map indexed by MIME type (string) that references
37      * a Map of commands for each type. The comand Map
38      * is indexed by the command name and references a List of
39      * class names (strings) for each command.
40      */

41     private Map type_hash = new HashMap();
42
43     /**
44      * Another Map like above, but for fallback entries.
45      */

46     private Map fallback_hash = new HashMap();
47
48     /**
49      * A Map indexed by MIME type (string) that references
50      * a List of native commands (string) corresponding to the type.
51      */

52     private Map native_commands = new HashMap();
53
54     private static boolean addReverse = false;
55
56     static {
57     try {
58         addReverse = Boolean.getBoolean("javax.activation.addreverse");
59     } catch (Throwable JavaDoc t) {
60         // ignore any errors
61
}
62     }
63
64     /**
65      * The constructor that takes a filename as an argument.
66      *
67      * @param new_fname The file name of the mailcap file.
68      */

69     public MailcapFile(String JavaDoc new_fname) throws IOException {
70     if (LogSupport.isLoggable())
71         LogSupport.log("new MailcapFile: file " + new_fname);
72     FileReader reader = null;
73     try {
74         reader = new FileReader(new_fname);
75         parse(new BufferedReader(reader));
76     } finally {
77         if (reader != null) {
78         try {
79             reader.close();
80         } catch (IOException ex) { }
81         }
82     }
83     }
84
85     /**
86      * The constructor that takes an input stream as an argument.
87      *
88      * @param is the input stream
89      */

90     public MailcapFile(InputStream is) throws IOException {
91     if (LogSupport.isLoggable())
92         LogSupport.log("new MailcapFile: InputStream");
93     parse(new BufferedReader(new InputStreamReader(is, "iso-8859-1")));
94     }
95
96     /**
97      * Mailcap file default constructor.
98      */

99     public MailcapFile() {
100     if (LogSupport.isLoggable())
101         LogSupport.log("new MailcapFile: default");
102     }
103
104     /**
105      * Get the Map of MailcapEntries based on the MIME type.
106      *
107      * <p>
108      * <strong>Semantics:</strong> First check for the literal mime type,
109      * if that fails looks for wildcard <type>/\* and return that. Return the
110      * list of all that hit.
111      */

112     public Map getMailcapList(String JavaDoc mime_type) {
113     Map search_result = null;
114     Map wildcard_result = null;
115
116     // first try the literal
117
search_result = (Map)type_hash.get(mime_type);
118
119     // ok, now try the wildcard
120
int separator = mime_type.indexOf('/');
121     String JavaDoc subtype = mime_type.substring(separator + 1);
122     if (!subtype.equals("*")) {
123         String JavaDoc type = mime_type.substring(0, separator + 1) + "*";
124         wildcard_result = (Map)type_hash.get(type);
125
126         if (wildcard_result != null) { // damn, we have to merge!!!
127
if (search_result != null)
128             search_result =
129             mergeResults(search_result, wildcard_result);
130         else
131             search_result = wildcard_result;
132         }
133     }
134     return search_result;
135     }
136
137     /**
138      * Get the Map of fallback MailcapEntries based on the MIME type.
139      *
140      * <p>
141      * <strong>Semantics:</strong> First check for the literal mime type,
142      * if that fails looks for wildcard <type>/\* and return that. Return the
143      * list of all that hit.
144      */

145     public Map getMailcapFallbackList(String JavaDoc mime_type) {
146     Map search_result = null;
147     Map wildcard_result = null;
148
149     // first try the literal
150
search_result = (Map)fallback_hash.get(mime_type);
151
152     // ok, now try the wildcard
153
int separator = mime_type.indexOf('/');
154     String JavaDoc subtype = mime_type.substring(separator + 1);
155     if (!subtype.equals("*")) {
156         String JavaDoc type = mime_type.substring(0, separator + 1) + "*";
157         wildcard_result = (Map)fallback_hash.get(type);
158
159         if (wildcard_result != null) { // damn, we have to merge!!!
160
if (search_result != null)
161             search_result =
162             mergeResults(search_result, wildcard_result);
163         else
164             search_result = wildcard_result;
165         }
166     }
167     return search_result;
168     }
169
170     /**
171      * Return all the MIME types known to this mailcap file.
172      */

173     public String JavaDoc[] getMimeTypes() {
174     Set types = new HashSet(type_hash.keySet());
175     types.addAll(fallback_hash.keySet());
176     types.addAll(native_commands.keySet());
177     String JavaDoc[] mts = new String JavaDoc[types.size()];
178     mts = (String JavaDoc[])types.toArray(mts);
179     return mts;
180     }
181
182     /**
183      * Return all the native comands for the given MIME type.
184      */

185     public String JavaDoc[] getNativeCommands(String JavaDoc mime_type) {
186     String JavaDoc[] cmds = null;
187     List v = (List)native_commands.get(mime_type.toLowerCase());
188     if (v != null) {
189         cmds = new String JavaDoc[v.size()];
190         cmds = (String JavaDoc[])v.toArray(cmds);
191     }
192     return cmds;
193     }
194
195     /**
196      * Merge the first hash into the second.
197      * This merge will only effect the hashtable that is
198      * returned, we don't want to touch the one passed in since
199      * its integrity must be maintained.
200      */

201     private Map mergeResults(Map first, Map second) {
202     Iterator verb_enum = second.keySet().iterator();
203     Map clonedHash = new HashMap(first);
204
205     // iterate through the verbs in the second map
206
while (verb_enum.hasNext()) {
207         String JavaDoc verb = (String JavaDoc)verb_enum.next();
208         List cmdVector = (List)clonedHash.get(verb);
209         if (cmdVector == null) {
210         clonedHash.put(verb, second.get(verb));
211         } else {
212         // merge the two
213
List oldV = (List)second.get(verb);
214         cmdVector = new ArrayList(cmdVector);
215         cmdVector.addAll(oldV);
216         clonedHash.put(verb, cmdVector);
217         }
218     }
219     return clonedHash;
220     }
221
222     /**
223      * appendToMailcap: Append to this Mailcap DB, use the mailcap
224      * format:
225      * Comment == "# <i>comment string</i>
226      * Entry == "mimetype; javabeanclass<nl>
227      *
228      * Example:
229      * # this is a comment
230      * image/gif jaf.viewers.ImageViewer
231      */

232     public void appendToMailcap(String JavaDoc mail_cap) {
233     if (LogSupport.isLoggable())
234         LogSupport.log("appendToMailcap: " + mail_cap);
235     try {
236         parse(new StringReader(mail_cap));
237     } catch (IOException ex) {
238         // can't happen
239
}
240     }
241
242     /**
243      * parse file into a hash table of MC Type Entry Obj
244      */

245     private void parse(Reader reader) throws IOException {
246     BufferedReader buf_reader = new BufferedReader(reader);
247     String JavaDoc line = null;
248     String JavaDoc continued = null;
249
250     while ((line = buf_reader.readLine()) != null) {
251         // LogSupport.log("parsing line: " + line);
252

253         line = line.trim();
254
255         try {
256         if (line.charAt(0) == '#')
257             continue;
258         if (line.charAt(line.length() - 1) == '\\') {
259             if (continued != null)
260             continued += line.substring(0, line.length() - 1);
261             else
262             continued = line.substring(0, line.length() - 1);
263         } else if (continued != null) {
264             // handle the two strings
265
continued = continued + line;
266             // LogSupport.log("parse: " + continued);
267
try {
268             parseLine(continued);
269             } catch (MailcapParseException e) {
270             //e.printStackTrace();
271
}
272             continued = null;
273         }
274         else {
275             // LogSupport.log("parse: " + line);
276
try {
277             parseLine(line);
278             // LogSupport.log("hash.size = " + type_hash.size());
279
} catch (MailcapParseException e) {
280             //e.printStackTrace();
281
}
282         }
283         } catch (StringIndexOutOfBoundsException JavaDoc e) {}
284     }
285     }
286
287     /**
288      * A routine to parse individual entries in a Mailcap file.
289      *
290      * Note that this routine does not handle line continuations.
291      * They should have been handled prior to calling this routine.
292      */

293     protected void parseLine(String JavaDoc mailcapEntry)
294                 throws MailcapParseException, IOException {
295     MailcapTokenizer tokenizer = new MailcapTokenizer(mailcapEntry);
296     tokenizer.setIsAutoquoting(false);
297
298     if (LogSupport.isLoggable())
299         LogSupport.log("parse: " + mailcapEntry);
300     // parse the primary type
301
int currentToken = tokenizer.nextToken();
302     if (currentToken != MailcapTokenizer.STRING_TOKEN) {
303         reportParseError(MailcapTokenizer.STRING_TOKEN, currentToken,
304                     tokenizer.getCurrentTokenValue());
305     }
306     String JavaDoc primaryType = tokenizer.getCurrentTokenValue().toLowerCase();
307     String JavaDoc subType = "*";
308
309     // parse the '/' between primary and sub
310
// if it's not present that's ok, we just don't have a subtype
311
currentToken = tokenizer.nextToken();
312     if ((currentToken != MailcapTokenizer.SLASH_TOKEN) &&
313             (currentToken != MailcapTokenizer.SEMICOLON_TOKEN)) {
314         reportParseError(MailcapTokenizer.SLASH_TOKEN,
315                 MailcapTokenizer.SEMICOLON_TOKEN, currentToken,
316                 tokenizer.getCurrentTokenValue());
317     }
318
319     // only need to look for a sub type if we got a '/'
320
if (currentToken == MailcapTokenizer.SLASH_TOKEN) {
321         // parse the sub type
322
currentToken = tokenizer.nextToken();
323         if (currentToken != MailcapTokenizer.STRING_TOKEN) {
324         reportParseError(MailcapTokenizer.STRING_TOKEN,
325                 currentToken, tokenizer.getCurrentTokenValue());
326         }
327         subType = tokenizer.getCurrentTokenValue().toLowerCase();
328
329         // get the next token to simplify the next step
330
currentToken = tokenizer.nextToken();
331     }
332
333     String JavaDoc mimeType = primaryType + "/" + subType;
334
335     if (LogSupport.isLoggable())
336         LogSupport.log(" Type: " + mimeType);
337
338     // now setup the commands hashtable
339
Map commands = new LinkedHashMap(); // keep commands in order found
340

341     // parse the ';' that separates the type from the parameters
342
if (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) {
343         reportParseError(MailcapTokenizer.SEMICOLON_TOKEN,
344                 currentToken, tokenizer.getCurrentTokenValue());
345     }
346     // eat it
347

348     // parse the required view command
349
tokenizer.setIsAutoquoting(true);
350     currentToken = tokenizer.nextToken();
351     tokenizer.setIsAutoquoting(false);
352     if ((currentToken != MailcapTokenizer.STRING_TOKEN) &&
353             (currentToken != MailcapTokenizer.SEMICOLON_TOKEN)) {
354         reportParseError(MailcapTokenizer.STRING_TOKEN,
355                 MailcapTokenizer.SEMICOLON_TOKEN, currentToken,
356                 tokenizer.getCurrentTokenValue());
357     }
358
359     if (currentToken == MailcapTokenizer.STRING_TOKEN) {
360         // have a native comand, save the entire mailcap entry
361
//String nativeCommand = tokenizer.getCurrentTokenValue();
362
List v = (List)native_commands.get(mimeType);
363         if (v == null) {
364         v = new ArrayList();
365         v.add(mailcapEntry);
366         native_commands.put(mimeType, v);
367         } else {
368         // XXX - check for duplicates?
369
v.add(mailcapEntry);
370         }
371     }
372
373     // only have to get the next token if the current one isn't a ';'
374
if (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) {
375         currentToken = tokenizer.nextToken();
376     }
377
378     // look for a ';' which will indicate whether
379
// a parameter list is present or not
380
if (currentToken == MailcapTokenizer.SEMICOLON_TOKEN) {
381         boolean isFallback = false;
382         do {
383         // eat the ';'
384

385         // parse the parameter name
386
currentToken = tokenizer.nextToken();
387         if (currentToken != MailcapTokenizer.STRING_TOKEN) {
388             reportParseError(MailcapTokenizer.STRING_TOKEN,
389                 currentToken, tokenizer.getCurrentTokenValue());
390         }
391         String JavaDoc paramName =
392             tokenizer.getCurrentTokenValue().toLowerCase();
393
394         // parse the '=' which separates the name from the value
395
currentToken = tokenizer.nextToken();
396         if ((currentToken != MailcapTokenizer.EQUALS_TOKEN) &&
397             (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) &&
398             (currentToken != MailcapTokenizer.EOI_TOKEN)) {
399             reportParseError(MailcapTokenizer.EQUALS_TOKEN,
400                 MailcapTokenizer.SEMICOLON_TOKEN,
401                 MailcapTokenizer.EOI_TOKEN,
402                 currentToken, tokenizer.getCurrentTokenValue());
403         }
404
405         // we only have a useful command if it is named
406
if (currentToken == MailcapTokenizer.EQUALS_TOKEN) {
407             // eat it
408

409             // parse the parameter value (which is autoquoted)
410
tokenizer.setIsAutoquoting(true);
411             currentToken = tokenizer.nextToken();
412             tokenizer.setIsAutoquoting(false);
413             if (currentToken != MailcapTokenizer.STRING_TOKEN) {
414             reportParseError(MailcapTokenizer.STRING_TOKEN,
415             currentToken, tokenizer.getCurrentTokenValue());
416             }
417             String JavaDoc paramValue =
418                 tokenizer.getCurrentTokenValue();
419
420             // add the class to the list iff it is one we care about
421
if (paramName.startsWith("x-java-")) {
422             String JavaDoc commandName = paramName.substring(7);
423             // 7 == "x-java-".length
424

425             if (commandName.equals("fallback-entry") &&
426                 paramValue.equalsIgnoreCase("true")) {
427                 isFallback = true;
428             } else {
429
430                 // setup the class entry list
431
if (LogSupport.isLoggable())
432                 LogSupport.log(" Command: " + commandName +
433                             ", Class: " + paramValue);
434                 List classes = (List)commands.get(commandName);
435                 if (classes == null) {
436                 classes = new ArrayList();
437                 commands.put(commandName, classes);
438                 }
439                 if (addReverse)
440                 classes.add(0, paramValue);
441                 else
442                 classes.add(paramValue);
443             }
444             }
445
446             // set up the next iteration
447
currentToken = tokenizer.nextToken();
448         }
449         } while (currentToken == MailcapTokenizer.SEMICOLON_TOKEN);
450
451         Map masterHash = isFallback ? fallback_hash : type_hash;
452         Map curcommands =
453         (Map)masterHash.get(mimeType);
454         if (curcommands == null) {
455         masterHash.put(mimeType, commands);
456         } else {
457         if (LogSupport.isLoggable())
458             LogSupport.log("Merging commands for type " + mimeType);
459         // have to merge current and new commands
460
// first, merge list of classes for commands already known
461
Iterator cn = curcommands.keySet().iterator();
462         while (cn.hasNext()) {
463             String JavaDoc cmdName = (String JavaDoc)cn.next();
464             List ccv = (List)curcommands.get(cmdName);
465             List cv = (List)commands.get(cmdName);
466             if (cv == null)
467             continue;
468             // add everything in cv to ccv, if it's not already there
469
Iterator cvn = cv.iterator();
470             while (cvn.hasNext()) {
471             String JavaDoc clazz = (String JavaDoc)cvn.next();
472             if (!ccv.contains(clazz))
473                 if (addReverse)
474                 ccv.add(0, clazz);
475                 else
476                 ccv.add(clazz);
477             }
478         }
479         // now, add commands not previously known
480
cn = commands.keySet().iterator();
481         while (cn.hasNext()) {
482             String JavaDoc cmdName = (String JavaDoc)cn.next();
483             if (curcommands.containsKey(cmdName))
484             continue;
485             List cv = (List)commands.get(cmdName);
486             curcommands.put(cmdName, cv);
487         }
488         }
489     } else if (currentToken != MailcapTokenizer.EOI_TOKEN) {
490         reportParseError(MailcapTokenizer.EOI_TOKEN,
491         MailcapTokenizer.SEMICOLON_TOKEN,
492         currentToken, tokenizer.getCurrentTokenValue());
493     }
494      }
495
496      protected static void reportParseError(int expectedToken, int actualToken,
497         String JavaDoc actualTokenValue) throws MailcapParseException {
498         throw new MailcapParseException("Encountered a " +
499         MailcapTokenizer.nameForToken(actualToken) + " token (" +
500         actualTokenValue + ") while expecting a " +
501         MailcapTokenizer.nameForToken(expectedToken) + " token.");
502      }
503
504      protected static void reportParseError(int expectedToken,
505     int otherExpectedToken, int actualToken, String JavaDoc actualTokenValue)
506                     throws MailcapParseException {
507         throw new MailcapParseException("Encountered a " +
508         MailcapTokenizer.nameForToken(actualToken) + " token (" +
509         actualTokenValue + ") while expecting a " +
510         MailcapTokenizer.nameForToken(expectedToken) + " or a " +
511         MailcapTokenizer.nameForToken(otherExpectedToken) + " token.");
512      }
513
514      protected static void reportParseError(int expectedToken,
515         int otherExpectedToken, int anotherExpectedToken, int actualToken,
516         String JavaDoc actualTokenValue) throws MailcapParseException {
517     if (LogSupport.isLoggable())
518         LogSupport.log("PARSE ERROR: " + "Encountered a " +
519         MailcapTokenizer.nameForToken(actualToken) + " token (" +
520         actualTokenValue + ") while expecting a " +
521         MailcapTokenizer.nameForToken(expectedToken) + ", a " +
522         MailcapTokenizer.nameForToken(otherExpectedToken) + ", or a " +
523         MailcapTokenizer.nameForToken(anotherExpectedToken) + " token.");
524         throw new MailcapParseException("Encountered a " +
525         MailcapTokenizer.nameForToken(actualToken) + " token (" +
526         actualTokenValue + ") while expecting a " +
527         MailcapTokenizer.nameForToken(expectedToken) + ", a " +
528         MailcapTokenizer.nameForToken(otherExpectedToken) + ", or a " +
529         MailcapTokenizer.nameForToken(anotherExpectedToken) + " token.");
530      }
531
532      /** for debugging
533      public static void main(String[] args) throws Exception {
534         Map masterHash = new HashMap();
535         for (int i = 0; i < args.length; ++i) {
536         System.out.println("Entry " + i + ": " + args[i]);
537         parseLine(args[i], masterHash);
538         }
539
540         Enumeration types = masterHash.keys();
541         while (types.hasMoreElements()) {
542         String key = (String)types.nextElement();
543         System.out.println("MIME Type: " + key);
544
545         Map commandHash = (Map)masterHash.get(key);
546         Enumeration commands = commandHash.keys();
547         while (commands.hasMoreElements()) {
548         String command = (String)commands.nextElement();
549         System.out.println(" Command: " + command);
550
551         Vector classes = (Vector)commandHash.get(command);
552         for (int i = 0; i < classes.size(); ++i) {
553             System.out.println(" Class: " +
554                         (String)classes.elementAt(i));
555         }
556         }
557
558         System.out.println("");
559     }
560     }
561     */

562 }
563
Popular Tags