KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > XMLEntityResolver


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util;
11
12 import java.io.InputStream JavaDoc;
13 import java.io.InputStreamReader JavaDoc;
14 import java.io.ByteArrayInputStream JavaDoc;
15 import java.util.Map JavaDoc;
16 import java.util.Hashtable JavaDoc;
17
18 import org.mmbase.util.xml.ApplicationReader;
19 import org.mmbase.util.xml.BuilderReader;
20 import org.mmbase.util.xml.ModuleReader;
21 import org.mmbase.util.logging.Logger;
22 import org.mmbase.util.logging.Logging;
23
24 import org.xml.sax.EntityResolver JavaDoc;
25 import org.xml.sax.InputSource JavaDoc;
26
27 /**
28  * Take the systemId and converts it into a local file, using the MMBase config path
29  *
30  * @move org.mmbase.util.xml
31  * @rename EntityResolver
32  * @author Gerard van Enk
33  * @author Michiel Meeuwissen
34  * @version $Id: XMLEntityResolver.java,v 1.59 2006/01/17 12:25:21 michiel Exp $
35  */

36 public class XMLEntityResolver implements EntityResolver JavaDoc {
37
38     public static final String JavaDoc DOMAIN = "http://www.mmbase.org/";
39     public static final String JavaDoc DTD_SUBPATH = "dtd/";
40     public static final String JavaDoc XMLNS_SUBPATH = "xmlns/";
41     private static final String JavaDoc XSD_SUBPATH = "xsd/"; // deprecated
42

43     private static Logger log = Logging.getLoggerInstance(XMLEntityResolver.class);
44
45     private static final String JavaDoc MMRESOURCES = "/org/mmbase/resources/";
46
47     private static Map JavaDoc publicIDtoResource = new Hashtable JavaDoc();
48     // This maps public id's to classes which are know to be able to parse this XML's.
49
// The package of these XML's will also contain the resources with the DTD.
50

51     /**
52      * XSD's have only system ID
53      */

54     private static Map JavaDoc systemIDtoResource = new Hashtable JavaDoc();
55
56     /**
57      * Container for dtd resources information
58      */

59     static class Resource {
60         private Class JavaDoc clazz;
61         private String JavaDoc file;
62         Resource(Class JavaDoc c, String JavaDoc f) {
63             clazz = c; file = f;
64         }
65
66         String JavaDoc getResource() {
67             return "resources/" + file;
68         }
69         String JavaDoc getFileName() {
70             return file;
71         }
72         InputStream JavaDoc getAsStream() {
73             if (log.isDebugEnabled()) log.debug("Getting document definition as resource " + getResource() + " of " + clazz.getName());
74             return clazz != null ? clazz.getResourceAsStream(getResource()) : null;
75         }
76         public String JavaDoc toString() {
77             return file + ": " + clazz;
78         }
79
80     }
81
82     static {
83         // ask known (core) xml readers to register their public ids and dtds
84
// the advantage of doing it this soon, is that the 1DTD are know as early as possible.
85
org.mmbase.util.xml.DocumentReader.registerPublicIDs();
86         BuilderReader.registerPublicIDs();
87         BuilderReader.registerSystemIDs();
88         ApplicationReader.registerPublicIDs();
89         ModuleReader.registerPublicIDs();
90         org.mmbase.util.xml.UtilReader.registerPublicIDs();
91         org.mmbase.bridge.util.xml.query.QueryReader.registerSystemIDs();
92
93         registerSystemID("http://www.w3.org/2001/03/xml.xsd", "xml.xsd", null);
94         registerSystemID("http://www.w3.org/2001/03/XMLSchema.dtd", "XMLSchema.dtd", null);
95         registerSystemID("http://www.w3.org/2001/03/datatypes.dtd", "datatypes.dtd", null);
96     }
97
98
99     /**
100      * Register a given publicID, binding it to a resource determined by a given class and resource filename
101      * @param publicID the Public ID to register
102      * @param dtd the name of the resourcefile
103      * @param c the class indicating the location of the resource in the pacakage structure. The
104      * resource is to be found in the 'resources' package under the package of the class.
105      * @since MMBase-1.7
106      */

107     public static void registerPublicID(String JavaDoc publicID, String JavaDoc dtd, Class JavaDoc c) {
108         publicIDtoResource.put(publicID, new Resource(c, dtd));
109         if (log.isDebugEnabled()) log.debug("publicIDtoResource: " + publicID + " " + dtd + c.getName());
110     }
111
112     /**
113      * It seems that in XSD's you don't have public id's. So, this makes it possible to use system id.
114      * @todo EXPERIMENTAL
115      * @since MMBase-1.8
116      */

117     public static void registerSystemID(String JavaDoc systemID, String JavaDoc xsd, Class JavaDoc c) {
118         systemIDtoResource.put(systemID, new Resource(c, xsd));
119     }
120
121     private String JavaDoc definitionPath;
122
123     private boolean hasDefinition; // tells whether or not a DTD/XSD is set - if not, no validition can take place
124

125     private boolean validate;
126     private Class JavaDoc resolveBase;
127
128
129
130     /**
131      * empty constructor
132      */

133     public XMLEntityResolver() {
134         this(true);
135     }
136
137     public XMLEntityResolver(boolean v) {
138         this(v, null);
139     }
140
141     public XMLEntityResolver(boolean v, Class JavaDoc base) {
142         hasDefinition = false;
143         definitionPath = null;
144         validate = v;
145         resolveBase = base;
146     }
147
148
149     private InputStream JavaDoc getStream(Resource res) {
150         InputStream JavaDoc stream = null;
151        if (res != null) {
152            stream = ResourceLoader.getConfigurationRoot().getResourceAsStream(DTD_SUBPATH + res.getFileName());
153            if (stream == null) {
154                stream = ResourceLoader.getConfigurationRoot().getResourceAsStream(XMLNS_SUBPATH + res.getFileName());
155            }
156            if (stream == null) {
157                // XXX I think this was deprecated in favour in xmlns/ (all in 1.8), so perhaps this can be dropped
158
stream = ResourceLoader.getConfigurationRoot().getResourceAsStream(XSD_SUBPATH + res.getFileName());
159            }
160            if (stream == null) {
161                stream = res.getAsStream();
162            }
163        }
164        return stream;
165     }
166
167     /**
168      * Takes the systemId and returns the local location of the dtd/xsd
169      */

170     public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId) {
171         if (log.isDebugEnabled()) {
172             log.debug("resolving PUBLIC " + publicId + " SYSTEM " + systemId);
173         }
174         if (! validate) {
175             log.debug("Not validating, not need to resolve DTD, returning empty resource");
176             return new InputSource JavaDoc(new ByteArrayInputStream JavaDoc(new byte[0]));
177         }
178
179         InputStream JavaDoc definitionStream = null;
180
181         // first try with publicID or namespace
182
if (publicId != null) {
183             Resource res = (Resource) publicIDtoResource.get(publicId);
184             definitionStream = getStream(res);
185         }
186         log.debug("Get definition stream by public id: " + definitionStream);
187
188         if (definitionStream == null) {
189             Resource res = (Resource) systemIDtoResource.get(systemId);
190             if (res != null) {
191                 definitionStream = getStream(res);
192             }
193         }
194
195         if (definitionStream == null) { // not succeeded with publicid, go trying with systemId
196

197             //does systemId contain a mmbase-dtd
198
if ((systemId == null) || (! systemId.startsWith(DOMAIN))) {
199                 // it's a systemId we can't do anything with,
200
// so let the parser decide what to do
201

202                 if (log.isDebugEnabled()) {
203                     log.debug("Cannot resolve " + systemId + ", but needed for validation leaving to parser.");
204                     log.debug("Find culpit: " + Logging.stackTrace(new Exception JavaDoc()));
205                 }
206                 return null;
207             } else {
208                 log.debug("mmbase resource");
209                 String JavaDoc mmResource = systemId.substring(22);
210                 // first, try MMBase config directory (if initialized)
211
definitionStream = ResourceLoader.getConfigurationRoot().getResourceAsStream(mmResource);
212                 if (definitionStream == null) {
213                     Class JavaDoc base = resolveBase; // if resolveBase was specified, use that.
214
Resource res = null;
215                     if (base != null) {
216                         if (mmResource.startsWith("xmlns/")) {
217                             res = new Resource(base, mmResource.substring(6));
218                         } else {
219                             res = new Resource(base, mmResource.substring(4)); // dtd or xsd
220
}
221                     }
222                     if (res != null) {
223                         definitionStream = res.getAsStream();
224                         if (definitionStream == null) {
225                             log.warn("Could not find " + res.getResource() + " in " + base.getName() + ", falling back to " + MMRESOURCES);
226                             base = null; // try it in org.mmbase.resources too.
227
}
228                     }
229
230                     if (base == null) {
231                         String JavaDoc resource = MMRESOURCES + mmResource;
232                         if (log.isDebugEnabled()) log.debug("Getting document definition as resource " + resource);
233                         definitionStream = getClass().getResourceAsStream(resource);
234                     }
235                 }
236                 if (definitionStream == null) {
237                     
238                     if (resolveBase != null) {
239                         log.error("Could not find MMBase entity '" + publicId + " " + systemId + "' (did you make a typo?), returning null, system id will be used (needing a connection, or put in config dir)");
240                     } else {
241                         log.service("Could not find MMBase entity '" + publicId + " " + systemId + "' (did you make a typo?), returning null, system id will be used (needing a connection, or put in config dir)");
242                         
243                     }
244                     // not sure, probably should return 'null' after all, then it will be resolved with internet.
245
// but this can not happen, in fact...
246
//return new InputSource(new StringReader(""));
247
// FAILED
248
return null;
249                 }
250             }
251         }
252         hasDefinition = true;
253
254         InputStreamReader JavaDoc definitionInputStreamReader = new InputStreamReader JavaDoc(definitionStream);
255         InputSource JavaDoc definitionInputSource = new InputSource JavaDoc();
256         if (systemId != null) {
257             definitionInputSource.setSystemId(systemId);
258         }
259         if (publicId != null) {
260             definitionInputSource.setPublicId(publicId);
261         }
262         definitionInputSource.setCharacterStream(definitionInputStreamReader);
263         return definitionInputSource;
264     }
265
266     /**
267      * @return whether the resolver has determiend a DTD
268      */

269     public boolean hasDTD() {
270         return hasDefinition;
271     }
272
273     /**
274      * @return The actually used path to the DTD
275      */

276     public String JavaDoc getDTDPath() {
277         return definitionPath;
278     }
279 }
280
Popular Tags