~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/javahelp/jhMaster/JavaHelp/src/new/javax/help/.svn/text-base/FlatMap.java.svn-base

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * @(#)FlatMap.java     1.36 06/10/30
 
3
 * 
 
4
 * Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
 
5
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
6
 * 
 
7
 * This code is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License version 2 only, as
 
9
 * published by the Free Software Foundation.  Sun designates this
 
10
 * particular file as subject to the "Classpath" exception as provided
 
11
 * by Sun in the LICENSE file that accompanied this code.
 
12
 * 
 
13
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
15
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
16
 * version 2 for more details (a copy is included in the LICENSE file that
 
17
 * accompanied this code).
 
18
 * 
 
19
 * You should have received a copy of the GNU General Public License version
 
20
 * 2 along with this work; if not, write to the Free Software Foundation,
 
21
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
22
 * 
 
23
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 
24
 * CA 95054 USA or visit www.sun.com if you need additional information or
 
25
 * have any questions.
 
26
 */
 
27
 
 
28
package javax.help;
 
29
 
 
30
import java.net.URL;
 
31
import java.net.URLConnection;
 
32
import java.net.MalformedURLException;
 
33
import java.util.*;
 
34
import java.io.*;
 
35
import java.beans.*;
 
36
import javax.help.event.*;
 
37
import javax.help.Map.ID;
 
38
import com.sun.java.help.impl.*;
 
39
 
 
40
/**
 
41
 * A FlatMap is a simple implementation of a Map.  It is used to represent a
 
42
 * Map for a single file.
 
43
 *
 
44
 * @author Eduardo Pelegri-Llopart
 
45
 * @version     1.18    01/22/99
 
46
 */
 
47
public class FlatMap implements Map, Serializable {
 
48
    private URL base;           // URL to this map
 
49
    private ResourceBundle resource; // the resource
 
50
    private HelpSet helpset;    // the top HelpSet
 
51
 
 
52
    /**
 
53
     * PublicID (known to this XML processor) to the DTD for version 1.0 of the Map
 
54
     */
 
55
    public static final String publicIDString =
 
56
        "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN";
 
57
 
 
58
    /**
 
59
     * PublicID (known to this XML processor) to the DTD for version 1.0 of the Map
 
60
     */
 
61
    public static final String publicIDString_V2 =
 
62
        "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 2.0//EN";
 
63
 
 
64
  /**
 
65
     * Create a FlatMap from a given URL.
 
66
     *
 
67
    * @param source The URL that is the source for all references in this Map.
 
68
    * @param hs The HelpSet providing "context" for this Map.
 
69
    * @throws IllegalArgumentException if hs doesn't have nested HelpSets.
 
70
     */
 
71
    public FlatMap(URL base, HelpSet hs) throws IOException {
 
72
        debug("Creating FlatMap for: "+base);
 
73
 
 
74
        // Verify that this helpset indeed does not have nested HelpSets.
 
75
        for (Enumeration e = hs.getHelpSets();
 
76
             e.hasMoreElements(); ) {
 
77
            throw new IllegalArgumentException
 
78
                ("Cannot create - HelpSet is not flat");
 
79
        }
 
80
 
 
81
        //      InputStream is = base.openStream();
 
82
        //      resource = new MapResourceBundle(is);
 
83
        resource = new FlatMapResourceBundle(base);
 
84
        this.base = base;
 
85
        this.helpset = hs;
 
86
    }
 
87
 
 
88
    /**
 
89
     * The HelpSet for this Map.
 
90
     */
 
91
    public HelpSet getHelpSet() {
 
92
        return helpset;
 
93
    }
 
94
 
 
95
    /**
 
96
     * Determines whether the given ID is valid. If hs is null
 
97
     * it is ignored.
 
98
     * 
 
99
     * @param id The String ID.
 
100
     * @param hs The HelpSet against which to resolve the string.
 
101
     * @return True if id is valid, false if not valid.
 
102
     */
 
103
 
 
104
    public boolean isValidID(String id, HelpSet hs) {
 
105
        debug("isValidID "+id);
 
106
 
 
107
        try {
 
108
            String tmp = resource.getString(id);
 
109
        } catch (MissingResourceException e) {
 
110
            return false;
 
111
        }
 
112
        return true;
 
113
    }
 
114
 
 
115
    /**
 
116
     * Gets an enumeration of all the IDs in a Map.
 
117
     *
 
118
     * @return An enumeration of all the IDs in a Map.
 
119
     */
 
120
    public Enumeration getAllIDs() {
 
121
        return new FlatEnumeration(resource.getKeys(), helpset);
 
122
    }
 
123
 
 
124
    /**
 
125
     * Gets the URL that corresponds to a given ID in the map.
 
126
     *
 
127
     * @param iden The iden to get the URL for. If iden is null it is
 
128
     * treated as an unresolved ID and will return null.
 
129
     * @return URL The matching URL.  Null if this map cannot solve the ID
 
130
     * @exception MalformedURLException if the URLspecification found  is malformed
 
131
     */
 
132
    public URL getURLFromID(ID iden) throws MalformedURLException {
 
133
        debug("getURLFromID("+iden+")");
 
134
 
 
135
        String id = iden.id;
 
136
        HelpSet hs = iden.hs;
 
137
        if (id == null) {
 
138
            return null;
 
139
        }
 
140
        String tmp = null;
 
141
        try {
 
142
            tmp = resource.getString(id);
 
143
            URL back = new URL(base, tmp);
 
144
            return back;
 
145
        } catch (MissingResourceException e) {
 
146
            return null;
 
147
        }
 
148
    }
 
149
 
 
150
    /**
 
151
     * Determines if the URL corresponds to an ID in the Map.
 
152
     *
 
153
     * @param url The URL to check on.
 
154
     * @return true If this is an ID, otherwise false.
 
155
     */
 
156
    public boolean isID(URL url) {
 
157
        URL tmp;
 
158
        for (Enumeration e = resource.getKeys() ; e.hasMoreElements() ;) {
 
159
            try {
 
160
                String key = (String) e.nextElement();
 
161
                tmp = new URL(base, (String) resource.getObject(key));
 
162
                // sameFile() ignores the anchor! - epll
 
163
                if (url.sameFile(tmp) == true) {
 
164
                    return true;
 
165
                }
 
166
            } catch (Exception ex) {
 
167
            }
 
168
        }
 
169
        return false;
 
170
    }
 
171
 
 
172
 
 
173
    /**
 
174
     * Gets the ID for this URL.
 
175
     * 
 
176
     * @param url The URL to get the ID for.
 
177
     * @return The id (Map.ID) or null if URL is not an ID.
 
178
     */
 
179
    public ID getIDFromURL(URL url) {
 
180
        String tmp;
 
181
        URL tmpURL;
 
182
        if (url == null) return null;
 
183
        String urlString = url.toExternalForm();
 
184
        for (Enumeration e = resource.getKeys() ; e.hasMoreElements() ;) {
 
185
            String key = (String) e.nextElement();
 
186
            try {
 
187
                tmp = resource.getString(key);
 
188
                tmpURL = new URL(base, tmp);
 
189
 
 
190
                // Sometimes tmp will be null because not all keys are ids
 
191
                if (tmpURL == null) continue;
 
192
                String tmpString = tmpURL.toExternalForm();
 
193
                if (urlString.compareTo(tmpString) == 0) {
 
194
                    return ID.create(key, helpset);
 
195
                }
 
196
            } catch (Exception ex) {
 
197
            }
 
198
        }
 
199
        return null;
 
200
    }
 
201
 
 
202
    /**
 
203
     * Determines the ID that is "closest" to this URL (with a given anchor).
 
204
     *
 
205
     * The definition of this is up to the implementation of Map.  In particular,
 
206
     * it may be the same as getIDFromURL().
 
207
     *
 
208
     * @param url A URL
 
209
     * @return The closest ID in this map to the given URL
 
210
     */
 
211
    public ID getClosestID(URL url) {
 
212
        return getIDFromURL(url);
 
213
    }
 
214
 
 
215
 
 
216
    /**
 
217
     * Determines the IDs related to this URL.
 
218
     *
 
219
     * @param URL The URL to compare the Map IDs to.
 
220
     * @return Enumeration of Map.IDs
 
221
     */
 
222
    public Enumeration getIDs(URL url) {
 
223
        String tmp=null;
 
224
        URL tmpURL=null;
 
225
        Vector ids = new Vector();
 
226
        for (Enumeration e = resource.getKeys() ; e.hasMoreElements() ;) {
 
227
            String key = (String) e.nextElement();
 
228
            try {
 
229
                tmp = resource.getString(key);
 
230
                tmpURL = new URL(base, tmp);
 
231
                if (url.sameFile(tmpURL) == true) {
 
232
                    ids.addElement(key);
 
233
                }
 
234
            } catch (Exception ex) {
 
235
            }
 
236
        }
 
237
        return new FlatEnumeration(ids.elements(), helpset);
 
238
    }
 
239
 
 
240
    private static class FlatEnumeration implements Enumeration {
 
241
        private Enumeration e;
 
242
        private HelpSet hs;
 
243
 
 
244
        public FlatEnumeration(Enumeration e, HelpSet hs) {
 
245
            this.e = e;
 
246
            this.hs = hs;
 
247
        }
 
248
 
 
249
        public boolean hasMoreElements() {
 
250
            return e.hasMoreElements();
 
251
        }
 
252
 
 
253
        public Object nextElement() {
 
254
            Object back = null;
 
255
            try {
 
256
                back = ID.create((String) e.nextElement(), hs);
 
257
            } catch (Exception ex) {
 
258
            }
 
259
            return back;
 
260
        }
 
261
    }
 
262
 
 
263
 
 
264
    /**
 
265
     * FlatMapResourceBundle is a ResourceBundle but unlike most 
 
266
     * ResourceBundles it is not locale-based and is loaded via the
 
267
     * constructor, not getBundle.
 
268
     */
 
269
    protected class FlatMapResourceBundle extends ResourceBundle 
 
270
        implements ParserListener, Serializable  
 
271
    {
 
272
 
 
273
        private Hashtable lookup = null;
 
274
        private boolean startedmap;
 
275
        private URL source;
 
276
 
 
277
        /**
 
278
         * Creates the FlatMap from the data.
 
279
         */
 
280
        public FlatMapResourceBundle(URL url) {
 
281
            source = url;
 
282
            Reader src;
 
283
            try {
 
284
                URLConnection uc = url.openConnection();
 
285
                src = XmlReader.createReader(uc);
 
286
                parse(src);
 
287
                src.close();
 
288
            } catch (Exception e) {
 
289
                reportMessage("Exception caught while parsing "+url+" "+
 
290
                                   e.toString(), false);
 
291
            }
 
292
            parsingEnded();
 
293
            for (Enumeration e = lookup.keys() ; e.hasMoreElements() ;) {
 
294
                String key1 = (String) e.nextElement();
 
295
                String url1 = (String) lookup.get(key1);
 
296
            }
 
297
        }
 
298
 
 
299
        /**
 
300
         * Overrides ResourceBundle, same semantics.
 
301
         */
 
302
        public final Object handleGetObject(String key) {
 
303
            return lookup.get(key); // this class ignores locales
 
304
        }
 
305
 
 
306
        /**
 
307
         * Implements ResourceBundle.getKeys.
 
308
         */
 
309
        public Enumeration getKeys() {
 
310
            return lookup.keys();
 
311
        }
 
312
 
 
313
        /**
 
314
         * Parses a reader into a MutableTreeNode
 
315
         * Only one of these at a time.
 
316
         */
 
317
        synchronized void parse(Reader src)
 
318
            throws IOException 
 
319
        {
 
320
            lookup = new Hashtable(10);
 
321
 
 
322
            Parser parser = new Parser(src); // the XML parser instance
 
323
            parser.addParserListener(this);
 
324
            parser.parse();
 
325
        }
 
326
 
 
327
        /**
 
328
         *  A tag was parsed.
 
329
         */
 
330
        public void tagFound(ParserEvent e) {
 
331
            Locale locale = null;
 
332
            Tag tag = e.getTag();
 
333
            FlatMap.debug("TagFound: "+tag.name);
 
334
            TagProperties attr = tag.atts;
 
335
 
 
336
            // Nothing tricky about mapID it doesn't have any hierarchy to it.
 
337
            if (tag.name.equals("mapID")) {
 
338
                if (!startedmap) {
 
339
                    parsingError("map.invalidMapFormat");
 
340
                }
 
341
 
 
342
                String target = null;
 
343
                String url = null;
 
344
                if (attr != null) {
 
345
                    target = attr.getProperty("target");
 
346
                    url = attr.getProperty("url");
 
347
                }
 
348
                if (target == null || url == null) {
 
349
                    reportMessage("Failure in mapID Creation;", true);
 
350
                    reportMessage("  target: "+ target, true);
 
351
                    reportMessage("  url: "+ url, true);
 
352
                    return;
 
353
                }
 
354
                lookup.put(target, url);
 
355
                return;
 
356
            } else if (tag.name.equals("map")) {
 
357
                if (!tag.isEnd) {
 
358
                    if (attr != null) {
 
359
                        String version = attr.getProperty("version");
 
360
                        if (version != null && 
 
361
                            (version.compareTo("1.0") != 0 &&
 
362
                             version.compareTo("2.0") != 0)) {
 
363
                            parsingError("map.unknownVersion", version);
 
364
                        }
 
365
                    }
 
366
                    if (startedmap) {
 
367
                        parsingError("map.invalidMapFormat");
 
368
                    }
 
369
                    startedmap = true;
 
370
                } else {
 
371
                    if (startedmap) {
 
372
                        startedmap = false;
 
373
                    }
 
374
                }
 
375
                return;
 
376
            }
 
377
        }
 
378
 
 
379
        /**
 
380
         *  A PI was parsed.  This method is not intended to be of general use.
 
381
         */
 
382
        public void piFound(ParserEvent e) {
 
383
            // ignore
 
384
        }
 
385
 
 
386
        /**
 
387
         *  A DOCTYPE was parsed.  This method is not intended to be of general use.
 
388
         */
 
389
        public void doctypeFound(ParserEvent e) {
 
390
            String publicID = e.getPublicId();
 
391
            if (publicID == null ||
 
392
                (publicID.compareTo(publicIDString) != 0 &&
 
393
                 publicID.compareTo(publicIDString_V2) != 0)) {
 
394
                parsingError("map.wrongPublicID", publicID);
 
395
            }
 
396
        }
 
397
 
 
398
        /**
 
399
         * A continous block of text was parsed.
 
400
         */
 
401
        public void textFound(ParserEvent e) {
 
402
            // At the current time I don't care about text. All the text is
 
403
            // within the attributes in the tag
 
404
        }
 
405
 
 
406
        // The remaing events from Parser are ignored
 
407
        public void commentFound(ParserEvent e) {}
 
408
 
 
409
        public void errorFound(ParserEvent e){
 
410
            reportMessage(e.getText(), false);
 
411
        }
 
412
 
 
413
 
 
414
        private Vector messages = new Vector();
 
415
        private boolean validParse = true;
 
416
 
 
417
        /**
 
418
         * Reports an error message.
 
419
         */
 
420
        public void reportMessage(String msg, boolean validParse) {
 
421
            messages.addElement(msg);
 
422
            this.validParse = this.validParse && validParse;
 
423
        }
 
424
 
 
425
        /**
 
426
         * Enumerates all the error messages.
 
427
         */
 
428
        public Enumeration listMessages() {
 
429
            return messages.elements();
 
430
        }
 
431
 
 
432
        /**
 
433
         * Parsing has ended.  We are given a last chance to do something
 
434
         * to the HelpSet
 
435
         */
 
436
        private void parsingEnded() {
 
437
            if (! validParse) {
 
438
                if (lookup != null) {
 
439
                    lookup.clear();
 
440
                }
 
441
 
 
442
                // A parse with problems...
 
443
                FlatMap.debug("Parsing failed for "+source);
 
444
 
 
445
                for (Enumeration e = messages.elements();
 
446
                     e.hasMoreElements();) {
 
447
                    String msg = (String) e.nextElement();
 
448
 
 
449
                    FlatMap.debug(msg);
 
450
                }
 
451
            } else {
 
452
                // little memory clean up
 
453
                source = null;
 
454
            }
 
455
        }
 
456
 
 
457
        // Convenience methods
 
458
        private void parsingError(String key) {
 
459
            String s = HelpUtilities.getText(key);
 
460
            reportMessage(s, false); // tree will be wrong
 
461
        }
 
462
 
 
463
        private void parsingError(String key, String s) {
 
464
            String msg = HelpUtilities.getText(key, s);
 
465
            reportMessage(msg, false); // tree will be wrong
 
466
        }
 
467
 
 
468
    }
 
469
 
 
470
    /**
 
471
     * For printf debugging...
 
472
     */
 
473
    private static final boolean debug = false;
 
474
    private static void debug(String str) {
 
475
        if (debug) {
 
476
            System.out.println("FlatMap: " + str);
 
477
        }
 
478
    }
 
479
 
 
480
}