Source code: org/merlotxml/util/xml/DTDCache.java
1 /*
2 ====================================================================
3 Copyright (c) 1999-2000 ChannelPoint, Inc.. All rights reserved.
4 ====================================================================
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistribution of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12
13 2. Redistribution in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16
17 3. All advertising materials mentioning features or use of this
18 software must display the following acknowledgment: "This product
19 includes software developed by ChannelPoint, Inc. for use in the
20 Merlot XML Editor (http://www.merlotxml.org/)."
21
22 4. Any names trademarked by ChannelPoint, Inc. must not be used to
23 endorse or promote products derived from this software without prior
24 written permission. For written permission, please contact
25 legal@channelpoint.com.
26
27 5. Products derived from this software may not be called "Merlot"
28 nor may "Merlot" appear in their names without prior written
29 permission of ChannelPoint, Inc.
30
31 6. Redistribution of any form whatsoever must retain the following
32 acknowledgment: "This product includes software developed by
33 ChannelPoint, Inc. for use in the Merlot XML Editor
34 (http://www.merlotxml.org/)."
35
36 THIS SOFTWARE IS PROVIDED BY CHANNELPOINT, INC. "AS IS" AND ANY EXPRESSED OR
37 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
39 EVENT SHALL CHANNELPOINT, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
40 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 ====================================================================
47
48 For more information on ChannelPoint, Inc. please see http://www.channelpoint.com.
49 For information on the Merlot project, please see
50 http://www.merlotxml.org/.
51 */
52
53 package org.merlotxml.util.xml;
54
55 import java.util.*;
56 import java.io.*;
57 import java.net.*;
58
59 import com.ibm.xml.parser.DTD;
60
61 import org.xml.sax.InputSource;
62 import org.xml.sax.SAXException;
63 import org.xml.sax.EntityResolver;
64
65 import org.merlotxml.util.FileUtil;
66 import org.merlotxml.util.xml.xml4j.DTDDocumentImpl;
67
68 import org.merlotxml.merlot.plugin.*;
69
70
71 /**
72 * This singleton class is responsible for loading and caching
73 * all DTD's required by the system. This manager can load DTD's from the filesystem,
74 * URL's, and zip/jar files (not currently implemented).
75 * <P>
76 * Apps should use this class to retrieve all their DTD's for valid documents (non-validating
77 * apps usually ignore the DTD anyway, so they don't really need to use this, but if they do
78 * get a DTD, it might be a good idea to call into this class.
79 * <P>
80 * Here's an example of getting a dtd:<br>
81 * <tt>DTDCacheEntry dtdentry = DTDCache.getSharedInstance().findDTD(publicId, systemId);</tt>
82 * <br>
83 * where <tt>publicId</tt> is the DOCTYPE's given public identifier (can be null), and <tt>systemId</tt>
84 * is a system designator (file path or URL)
85 * <P>
86 * This can also cache DTD's from other entity resolvers via the
87 * <A href="#resolveDTD">resolveDTD</a> method.
88 *
89 * @author Kelly A. Campbell
90 * @author Frank Blecha
91 * @version $Id: DTDCache.java,v 1.4 2002/11/05 13:43:32 flament Exp $
92 *
93 */
94 public class DTDCache
95 {
96 /**
97 * key is the public id, val is a DTDCacheEntry, e.g. (publicId, DTDCacheEntry)
98 */
99 protected Map _publicIdCache;
100
101 /**
102 * key is the system id, val is a DTDCacheEntry, e.g. (systemId, DTDCacheEntry)
103 */
104 protected Map _systemIdCache;
105
106 /**
107 * key is the file path (including a ! and the path within a jar), val is a DTDCacheEntry
108 */
109 protected Map _filepathCache;
110
111 /**
112 * List of unique dtd entries. key is the dtd entry, value is not used (null)
113 */
114 protected Map _dtdEntries;
115
116 /**
117 * Properties for getting dtd path, etc. from
118 */
119 protected Properties _properties;
120
121
122
123 /**
124 * singleton instance
125 */
126 protected static DTDCache _instance;
127 /**
128 * synch object for creating the instance
129 */
130 protected static final Object _synchronizer = new Object();
131
132
133 /**
134 url prefix to know we're working with a local file
135 */
136 protected static final String FILE_PROTOCOL_NAME = "file:";
137
138
139 protected DTDCache ()
140 {
141 _publicIdCache = new HashMap();
142 _systemIdCache = new HashMap();
143 _filepathCache = new HashMap();
144 _dtdEntries = new HashMap();
145
146 }
147
148 /**
149 * gets the singleton instance.
150 */
151 public static DTDCache getSharedInstance()
152 {
153 if (_instance == null) {
154 synchronized(_synchronizer) {
155 if (_instance == null) {
156 _instance = new DTDCache();
157 }
158 }
159 }
160 return _instance;
161 }
162
163 /**
164 * set the properties. should really only be called once by some app initializer
165 */
166 public void setProperties(Properties props)
167 {
168 _properties = props;
169 }
170
171
172 /**
173 @param systemID ba
174
175 @return DTDCacheEntry null if we're unable to find the entry, otherwise the entry
176
177 @author Frank Blecha
178 */
179 protected DTDCacheEntry findCacheEntryBySystemID(String systemID)
180 {
181 DTDCacheEntry entry = null;
182 entry = (DTDCacheEntry)_systemIdCache.get(systemID);
183 if (entry != null) {
184 debug("found cached DTD: systemId="+systemID);
185 checkCacheEntryTimestamp(entry);
186 }
187 return entry;
188 }
189
190
191 /**
192 @param publicID
193 @param systemID
194 @return DTDCacheEntry the cache entry or null if we
195 couldn't find it or encoutered an error
196
197 @author Frank Blecha
198 */
199 protected DTDCacheEntry setupCacheEntryFromFile(String publicID, String systemID)
200 {
201 DTDCacheEntry entry = null;
202 try {
203 File dtdFile = new File(systemID);
204 entry = new DTDCacheEntry(publicID,systemID);
205 entry.setTimestamp( dtdFile.lastModified() );
206 entry.setFilePath( dtdFile.getCanonicalPath() );
207 }
208 catch(IOException iex) {
209
210 }
211 return entry;
212 }
213
214
215 /**
216 @param publicID
217 @param systemID
218 @return DTDCacheEntry
219 @author Frank Blecha
220 */
221 protected DTDCacheEntry setupCacheEntryFromClassLoader(String publicID, String systemID)
222 {
223 DTDCacheEntry entry = new DTDCacheEntry(publicID, systemID);
224 // ok? set the timestamp to never reload
225 entry.setTimestamp(0);
226 String dtdFile = "blahblahblah";//replace this with something meaningful later - fb3
227 entry.setFilePath(this.getClass().toString() + ":"+ dtdFile);
228 return entry;
229 }
230
231 /*=$*/
232 protected DTDCacheEntry setupCacheEntryFromPlugins(String publicID, String systemID)
233 {
234 DTDCacheEntry entry = new DTDCacheEntry(publicID, systemID);
235 entry.setTimestamp(0); // ok? set the timestamp to never reload
236 entry.setFilePath(systemID);
237 return entry;
238 }
239 /*=$*/
240
241 /**
242 @param publicId
243 @param systemId
244 @return DTDCacheEntry the cache entry or null if we cannot set it up correctly.
245 @author Frank Blecha
246 */
247 protected DTDCacheEntry setupCacheEntryFromURL(String publicID, String systemID)
248 {
249 DTDCacheEntry ret = null;
250 try {
251 URL dtdURL = new URL(systemID);
252 URLConnection connection = dtdURL.openConnection();
253 ret = new DTDCacheEntry(publicID, systemID);
254 ret.setFilePath( dtdURL.toString() );
255 ret.setTimestamp( connection.getExpiration() );
256 if( ret.getTimestamp() < System.currentTimeMillis() ) {
257 /* camk comments:
258
259 ok, they don't want us to cache it...we will anyway.
260 Use the modified time as the timestamp
261 */
262 ret.setTimestamp( connection.getLastModified() );
263 }
264 }
265 catch(IOException iex) {
266 ret = null;
267 }
268
269 return ret;
270 }
271
272
273 /**
274 see if the systemID exists as-is (is the absolute path embedded in the xml?)
275
276 @param dtdFile - the file we're trying to locate
277 @return InputStream - the InputStream from dtdFile or null if we can't find it
278 @author Frank Blecha
279 */
280 protected InputStream findDTDFromFile( String systemID )
281 {
282 InputStream ret = null;
283 try {
284 File dtdFile = new File(systemID);
285
286 /*
287 we may modify the systemID if it's not prepended
288 with FILE_PROTOCOL_NAME
289 */
290 String modifiedSystemID = systemID;
291
292 if( dtdFile.exists() ) {
293 if( ! systemID.startsWith( FILE_PROTOCOL_NAME ) ) {
294 modifiedSystemID = FILE_PROTOCOL_NAME + systemID;
295 }
296 ret = new FileInputStream( dtdFile );
297 }
298 }
299 catch(IOException iex) {
300 ret = null;
301 }
302 return ret;
303 }
304
305
306 /**
307 @author Frank Blecha
308 */
309 protected InputStream findDTDFromFile( String systemID, String fileLocation)
310 {
311 InputStream ret = null;
312
313 try {
314 File f = new File(fileLocation);
315 String parent = f.getParent();
316 if (parent != null) {
317 File dtdFile = new File(parent,systemID);
318 if (dtdFile.exists() && dtdFile.canRead()) {
319 ret = new FileInputStream(dtdFile);
320 }
321 }
322 }
323 catch (IOException iex) {
324 ret = null;
325 }
326 return ret;
327 }
328
329
330
331 /**
332 @param publicID
333 @param systemID
334 @return InputStream the InputStream for the DTD, or null we can't find it.
335 @author Frank Blecha
336 */
337 protected InputStream findDTDFromURL(String publicID, String systemID)
338 {
339 InputStream ret = null;
340 try {
341 URL dtdURL = new URL( systemID );
342 URLConnection connection = dtdURL.openConnection();
343 ret = connection.getInputStream();
344 }
345 catch(IOException iex) {
346 //set ret to null, which is enough of an error indicator
347 ret = null;
348 }
349 return ret;
350 }
351
352 /**
353 @param publicID
354 @param systemID
355 @return InputStream stream to read the dtd, or null if an error was encountered
356 @author Frank Blecha
357 */
358 protected InputStream findDTDFromClassLoader( String publicID, String systemID)
359 {
360 InputStream ret = null;
361 if ( null != getDTDPath() ) {
362
363 StringTokenizer st =
364 new StringTokenizer( getDTDPath(),
365 System.getProperty("path.separator")
366 );
367
368 while (st.hasMoreTokens()) {
369 // try the file
370 File dtdFile = new File( st.nextToken() + "/" + formatFileName(systemID) );
371 try {
372 ret = FileUtil.getInputStream(dtdFile, this.getClass());
373 break;
374 }
375 catch (FileNotFoundException e) {}
376 }//end while
377 }
378 return ret;
379 }
380
381 /*=$*/
382 protected InputStream findDTDFromPlugins( String publicID, String systemID) {
383 //System.out.println("findDTDFromPlugins("+publicID+","+systemID+")");
384
385 // delete "./"
386 if (systemID.length() <= 2) {
387 return null;
388 } else {
389 if (systemID.substring(0,2).equals("./")) {
390 systemID = systemID.substring(2);
391 }
392
393 List plugins = GD_PluginManager.getInstance().getPlugins();
394 Iterator it = plugins.iterator();
395 InputStream is = null;
396 while ((it.hasNext()) && (is == null)) {
397 PluginConfig pc = (PluginConfig) it.next();
398 is = pc.getClassLoader().getResourceAsStream("dtd/"+systemID);
399 }
400 return is;
401 }
402 }
403
404 /*=$*/
405
406 /**
407 @param publicID
408 @param systemID
409 @return InputStream the stream to read the dtd from, or null
410 if we got an error
411
412 @author Frank Blecha
413 */
414 protected InputStream findDTDFromDTDPath( String publicID, String systemID)
415 {
416 InputStream ret = null;
417 try {
418 if ( null != getDTDPath() ) {
419 StringTokenizer st =
420 new StringTokenizer( getDTDPath(),
421 System.getProperty("path.separator")
422 );
423 while (st.hasMoreTokens()) {
424 File dtdFile = new File( st.nextToken() + "/"
425 + formatFileName(systemID) );
426 if (dtdFile.exists()) {
427 ret = new FileInputStream(dtdFile);
428 break;
429 }
430 }//end while
431 }
432 }
433 catch(IOException iex) {
434 ret = null;
435 }
436 return ret;
437 }
438
439
440
441 /**
442 * Finds a dtd given a system identifier. If it cannot be found, null is returned
443 @param publicId
444 @param systemId can be a URL, and absolute filepath, or a filepath relative to the current document
445 @param fileLocation the location of the file which includes the given DTD
446 */
447 public DTDCacheEntry findDTDbySystemId(String publicId, String systemId, String fileLocation)
448 {
449 try {
450 InputStream is = null;
451 String modifiedSystemID = systemId;
452 DTDCacheEntry entry = null;
453 File dtdFile = null;
454
455 if( (entry = findCacheEntryBySystemID(systemId)) != null ) {
456 return entry;
457 }
458 else if( (is = findDTDFromFile( systemId)) != null ) {
459 entry = setupCacheEntryFromFile(publicId, systemId);
460 }
461 else if( (is = findDTDFromURL( publicId, systemId) ) != null ) {
462 entry = setupCacheEntryFromURL(publicId, systemId);
463 }
464 else if ( (is = findDTDFromFile( systemId, fileLocation)) != null ) {
465 entry = setupCacheEntryFromFile( publicId, systemId);
466 }
467 else if( (is = findDTDFromDTDPath( publicId, systemId) ) != null ) {
468 entry = setupCacheEntryFromFile( publicId, systemId);
469 modifiedSystemID = formatFileName( systemId );
470 }
471 else if( (is = findDTDFromClassLoader(publicId, systemId) ) != null ) {
472 entry = setupCacheEntryFromClassLoader(publicId, systemId);
473 modifiedSystemID = formatFileName( systemId );
474 }
475 else if ( (is = findDTDFromPlugins(publicId, systemId) ) != null) {
476 entry = setupCacheEntryFromPlugins(publicId, systemId);
477 }
478
479
480 if (entry == null || is == null) {
481 // debug("DTD SYSTEMID='"+systemId+"' NOT FOUND");
482 // new Exception().printStackTrace();
483
484 return null;
485 }
486
487
488 /* camk comments:
489 XXX this is lame and uses the xml4j parser directly instead
490 of through the DOMLiason... needs extrapolated and
491 insulated a bit
492
493 more than likely, someone else (like an entity resolver)
494 wants to read this dtd stream also, so we might as
495 well cache the whole dtd into memory (lame yes, but nice
496 if the dtd came from a remote URL, or a jar/zip file.
497 */
498 loadDTDIntoCache(is,entry);
499
500 if ( modifiedSystemID != null) {
501 entry.setSystemId( modifiedSystemID );
502 _systemIdCache.put( modifiedSystemID,entry);
503 }
504
505 String filepath = entry.getFilePath();
506 if (filepath != null) {
507 _filepathCache.put(filepath,entry);
508 }
509 // debug("DTDCache: returning PUBLIC='"+entry.getPublicId()+"' SYSTEM='"+entry.getSystemId()+"' FILE='"+filepath+"'");
510
511 return entry;
512 }
513 catch(IOException iex) {
514 return null;
515 }
516 }
517
518
519
520
521 /**
522 * Looks in our cache for a file with a given public ID
523 */
524 public DTDCacheEntry findDTDbyPublicId(String publicId, String systemId)
525 {
526 DTDCacheEntry entry = (DTDCacheEntry)_publicIdCache.get(publicId);
527 if (entry != null) {
528 checkCacheEntryTimestamp(entry);
529 return entry;
530 }
531
532 return null;
533
534
535 }
536
537 /**
538 * find a DTD based on the public id and system id
539 */
540 public DTDCacheEntry findDTD(String pubid, String sysid, String fileLocation)
541 {
542 // System.out.println("DTDCache.findDTD(public='"+pubid+"', sysid='"+sysid+"')");
543
544 DTDCacheEntry ret = null;
545 if (pubid != null) {
546 ret = findDTDbyPublicId(pubid,sysid);
547 }
548 if (ret == null && sysid != null) {
549 ret = findDTDbySystemId(pubid,sysid,fileLocation);
550 }
551
552 return ret;
553
554 }
555
556 /**
557 * resolve a dtd from another resolver. This way we can cache it locally.
558 */
559 public DTDCacheEntry resolveDTD(String publicId, String systemId, EntityResolver resolver, String fileLocation)
560 throws SAXException, IOException
561 {
562 debug("Resolve DTD: "+systemId);
563
564 InputSource is = resolver.resolveEntity(publicId, systemId);
565 if (is != null) {
566
567 String newPublicId = is.getPublicId();
568 String newSystemId = is.getSystemId();
569 if (newPublicId != null) {
570 publicId = newPublicId;
571 // debug("publicId = "+publicId+" newPublicId = "+newPublicId);
572
573 }
574 if (newSystemId != null) {
575 // debug("systemId = "+systemId+" newSystemId = "+newSystemId);
576 systemId = newSystemId;
577 }
578
579 // check to see if the resovler put one in our cache somehow
580 if (_publicIdCache.containsKey(publicId)) {
581 DTDCacheEntry entry = (DTDCacheEntry)_publicIdCache.get(publicId);
582 checkCacheEntryTimestamp(entry);
583 // debug("RESOLVE RETURNING DTD FROM PUBLIC MAP: "+entry);
584
585 return entry;
586 }
587
588 // create a new DtdEntry for it
589 DTDCacheEntry entry = new DTDCacheEntry(publicId, systemId);
590
591 InputStream stream = is.getByteStream();
592 Reader charstream = is.getCharacterStream();
593 if (charstream == null && stream != null) {
594 loadDTDIntoCache(stream,entry);
595 }
596 else if (charstream != null) {
597 loadDTDIntoCache(charstream,entry);
598 }
599 else {
600 return null;
601 }
602
603 // debug("RESOLVE RETURNING DTD ENTRY: "+entry);
604
605 return entry;
606
607 }
608 return null;
609
610 }
611
612 /**
613 * Loads a dtd into a DTDCacheEntry.
614 */
615 public void loadDTDIntoCache(InputStream is, DTDCacheEntry entry)
616 throws IOException
617 {
618 Reader r = new InputStreamReader(is);
619 loadDTDIntoCache(r,entry);
620
621 }
622
623 /**
624 * Loads a dtd into a DTDCacheEntry. The public and system id's should be set on the dtd entry.
625 */
626
627 public void loadDTDIntoCache(Reader r, DTDCacheEntry entry)
628 throws IOException
629 {
630 //System.out.println("loadDTDIntoCache("+r+","+entry+")");
631 BufferedReader br = new BufferedReader(r);
632 CharArrayWriter caw = new CharArrayWriter();
633 BufferedWriter bw = new BufferedWriter(caw);
634
635 int c;
636 while ((c = br.read()) >= 0) {
637 bw.write(c);
638 }
639 bw.flush();
640 bw.close();
641 br.close();
642
643
644 entry.setCachedDTDStream(caw.toCharArray());
645 CharArrayReader car = new CharArrayReader(entry.getCachedDTDStream());
646
647 // now parse the dtd for ourselves
648 String filename = entry.getFilePath();
649 if (filename == null) {
650 filename = entry.getSystemId();
651 }
652 // System.out.println("Parser("+filename+")");
653 String errorPrefix = filename;
654 if (errorPrefix == null || errorPrefix.trim().equals("")) {
655 errorPrefix = "error";
656 }
657
658 com.ibm.xml.parser.Parser p = new com.ibm.xml.parser.Parser(errorPrefix);
659 debug("Parsing DTD: "+errorPrefix);
660
661 DTD dtd = p.readDTDStream(car);
662 // debug("readDTDStream ok");
663
664 String publicId = entry.getPublicId();
665 String systemId = entry.getSystemId();
666
667 DTDDocumentImpl dtdimpl = new DTDDocumentImpl(dtd, publicId, systemId);
668 entry.setParsedDTD(dtdimpl);
669
670 car.close();
671 if (systemId != null && !systemId.trim().equals("")) {
672 _systemIdCache.put(systemId,entry);
673 // debug("added "+systemId+" to cache [2]");
674
675 }
676 if (publicId != null && !publicId.trim().equals("")) {
677 _publicIdCache.put(publicId,entry);
678 }
679 _dtdEntries.put(entry,null);
680
681
682 }
683
684 /**
685 * Checks the timestamp associated with a cache entry and reloads the
686 * dtd file if it has changed.
687 */
688 public void checkCacheEntryTimestamp(DTDCacheEntry entry)
689 {
690 boolean found = false;
691 if (entry != null) {
692 long timestamp = entry.getTimestamp();
693 if (timestamp > 0) {
694 File dtdFile = null;
695 InputStream is = null;
696 URL u = null;
697
698 // first see if the systemId exists as-is (is full path hard coded in the xml?)
699 String path = entry.getFilePath();
700 if (path != null) {
701 dtdFile = new File(path);
702 if (dtdFile.exists()) {
703 // we found it
704 found = true;
705 long newtime = dtdFile.lastModified();
706 if (newtime > timestamp) {
707 entry.setTimestamp(newtime);
708 try {
709 is = new FileInputStream(dtdFile);
710 }
711 catch (Exception ex) {
712 }
713 }
714 }
715
716 // still don't have it?
717 if (!found && is == null) {
718 // try it as a url
719 try {
720 u = new URL(path);
721 URLConnection connection = u.openConnection();
722 long newtime = connection.getExpiration();
723 if (newtime > timestamp) {
724 is = connection.getInputStream();
725
726 entry.setTimestamp(connection.getExpiration()); // cache until the document expires
727 if (entry.getTimestamp() < System.currentTimeMillis()) {
728 // ok, they don't want us to cache it... we will anyway.
729 // use the modified time as the timestamp
730 entry.setTimestamp(connection.getLastModified());
731 }
732 }
733 }
734 catch (Exception ex) {
735 }
736 }
737 try {
738 if (is != null) {
739 // debug("RELOADING CHANGED DTD: path = "+path);
740 loadDTDIntoCache(is,entry);
741 }
742 }
743 catch (Exception ex) {
744 }
745 }
746
747 }
748 }
749
750 }
751
752
753 public Collection getCachedDTDEntries()
754 {
755 Set keys = _dtdEntries.keySet();
756 TreeSet sortedkeys = new TreeSet(keys);
757 return sortedkeys;
758 }
759
760
761 public void printCache ()
762 {
763 Set s = _publicIdCache.keySet();
764 Iterator it = s.iterator();
765 debug("PUBLIC Id's:\n");
766
767 while (it.hasNext()) {
768 debug(it.next()+"\n");
769 }
770 s = _systemIdCache.keySet();
771 it = s.iterator();
772 debug("\nSYSTEM Id's:\n");
773
774 while (it.hasNext()) {
775 debug(it.next()+"\n");
776 }
777 debug("\n");
778
779 }
780
781
782 /**
783 @deprecated use fixSlashes instead
784 @author Frank Blecha
785 */
786 protected String fixslashes(String s)
787 {
788 return fixSlashes(s);
789 }
790
791
792 /**
793 * make all slashes forward slashes cause windows sucks
794 */
795 protected String fixSlashes(String s)
796 {
797 StringBuffer sb = new StringBuffer(s);
798 /*
799 strip off any leading slashes cause windows sucks and makes URL's like:
800 file:/C:/blah
801 when the cwd comes out like C:/blah
802 */
803 if (sb.charAt(0) == '/' && sb.charAt(2) == ':') {
804 sb.deleteCharAt(0);
805 }
806
807 for (int i=0;i < sb.length(); i++) {
808 if (sb.charAt(i) == '\\') {
809 sb.setCharAt(i,'/');
810 }
811 }
812 return sb.toString();
813 }
814
815 /**
816 simple debugging print routine
817 */
818 protected void debug(String s)
819 {
820 if (System.getProperty("DEBUG") != null) {
821 System.out.println("[debug] "+s);
822 }
823 }
824
825 /**
826 @param originalFileName - systemID
827 @return String
828 @author Frank Blecha
829 */
830 protected String formatFileName(String originalFileName )
831 {
832 String modifiedFileName = originalFileName;
833 if( originalFileName.startsWith( FILE_PROTOCOL_NAME ) ) {
834 modifiedFileName =
835 fixSlashes(originalFileName.substring(FILE_PROTOCOL_NAME.length()));
836 }
837 String currentDir = fixSlashes( System.getProperty("user.dir") );
838
839 if( originalFileName.startsWith( currentDir ) ) {
840 modifiedFileName =
841 modifiedFileName.substring( currentDir.length() );
842 }
843 return modifiedFileName;
844 }
845
846
847 protected String getDTDPath()
848 {
849 String ret = null;
850 if (_properties != null) {
851 ret = _properties.getProperty("path.dtd");
852 }
853 else {
854 debug("DTDCache: properties is null");
855 ret = null;
856 }
857 return ret;
858 }
859
860 }