OSDN Git Service

9d5b2588c8028f4f681e4eac2bc75d6bd76282b9
[mikutoga/TogaGem.git] / src / main / java / jp / sourceforge / mikutoga / xml / XmlResourceResolver.java
1 /*\r
2  * xml resource resolver\r
3  *\r
4  * License : The MIT License\r
5  * Copyright(c) 2009 olyutorskii\r
6  */\r
7 \r
8 package jp.sourceforge.mikutoga.xml;\r
9 \r
10 import java.io.IOException;\r
11 import java.io.InputStream;\r
12 import java.io.Reader;\r
13 import java.net.URI;\r
14 import java.net.URISyntaxException;\r
15 import java.net.URL;\r
16 import java.util.HashMap;\r
17 import java.util.Map;\r
18 import org.w3c.dom.ls.LSInput;\r
19 import org.w3c.dom.ls.LSResourceResolver;\r
20 import org.xml.sax.EntityResolver;\r
21 import org.xml.sax.InputSource;\r
22 import org.xml.sax.SAXException;\r
23 \r
24 /**\r
25  * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。\r
26  * 相対URIはこのクラスをベースに解決される。\r
27  * 主な用途は外部スキーマのリソース化など。\r
28  */\r
29 public class XmlResourceResolver\r
30         implements LSResourceResolver, EntityResolver {\r
31 \r
32     public static final String SCHEMA_XML =\r
33             "http://www.w3.org/2001/xml.xsd";\r
34     public static final String NS_XSD =\r
35             "http://www.w3.org/2001/XMLSchema-instance";\r
36 \r
37     private static final String LOCAL_SCHEMA_XML =\r
38             "resources/xml-2009-01.xsd";\r
39     private static final URI EMPTY_URI = URI.create("");\r
40     private static final Class THISCLASS = XmlResourceResolver.class;\r
41 \r
42 \r
43     /**\r
44      * 絶対URIと相対URIを合成したURIを返す。\r
45      * 正規化も行われる。\r
46      * @param base 絶対URIでなければならない。nullでもよい。\r
47      * @param relative 絶対URIでもよいがその場合baseは無視される。null可。\r
48      * @return 合成結果のURLオブジェクト。必ず絶対URIになる。\r
49      * @throws java.net.URISyntaxException URIとして変。\r
50      * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。\r
51      */\r
52     protected static URI buildBaseRelativeURI(String base, String relative)\r
53             throws URISyntaxException,\r
54                    IllegalArgumentException {\r
55         URI baseURI = null;\r
56         if(base != null){\r
57             baseURI = new URI(base);\r
58             if( ! baseURI.isAbsolute() ) throw new IllegalArgumentException();\r
59         }\r
60 \r
61         URI relativeURI = EMPTY_URI;\r
62         if(relative != null){\r
63             relativeURI = new URI(relative);\r
64         }\r
65 \r
66         URI resultURI;\r
67         if(baseURI == null || relativeURI.isAbsolute()){\r
68             resultURI = relativeURI;\r
69         }else{\r
70             resultURI = baseURI.resolve(relativeURI);\r
71         }\r
72 \r
73         if( ! resultURI.isAbsolute() ) throw new IllegalArgumentException();\r
74 \r
75         resultURI = resultURI.normalize();\r
76 \r
77         return resultURI;\r
78     }\r
79 \r
80     /**\r
81      * LSInput実装を生成する。\r
82      * @return LSInput実装\r
83      */\r
84     public static LSInput createLSInput(){\r
85         LSInput input = new LSInputImpl();\r
86         return input;\r
87     }\r
88 \r
89     private final Map<URI, URI> uriMap = new HashMap<URI, URI>();\r
90 \r
91     /**\r
92      * コンストラクタ。\r
93      */\r
94     public XmlResourceResolver(){\r
95         super();\r
96 \r
97         assert this.getClass().equals(THISCLASS);\r
98 \r
99         URI originalURI = URI.create(SCHEMA_XML);\r
100         URL redirectURL = THISCLASS.getResource(LOCAL_SCHEMA_XML);\r
101         URI redirectURI;\r
102         try{\r
103             redirectURI = redirectURL.toURI();\r
104         }catch(URISyntaxException e){\r
105             assert false;\r
106             throw new AssertionError(e);\r
107         }\r
108 \r
109         this.uriMap.put(originalURI, redirectURI);\r
110 \r
111         return;\r
112     }\r
113 \r
114     /**\r
115      * オリジナルURIとリダイレクト先のURIを登録する。\r
116      * オリジナルURIへのアクセスはリダイレクトされる。\r
117      * @param original オリジナルURI\r
118      * @param redirect リダイレクトURI\r
119      */\r
120     public void putURIMap(URI original, URI redirect){\r
121         this.uriMap.put(original.normalize(), redirect.normalize());\r
122         return;\r
123     }\r
124 \r
125     /**\r
126      * 変換後のリソースの入力ストリームを得る。\r
127      * @param originalURI オリジナルURI\r
128      * @return 入力ストリーム\r
129      * @throws java.io.IOException 入出力エラー\r
130      */\r
131     public InputStream getXMLResourceAsStream(URI originalURI)\r
132             throws IOException{\r
133         URI resourceURI = this.uriMap.get(originalURI.normalize());\r
134         URL resourceURL = resourceURI.toURL();\r
135         InputStream is = resourceURL.openStream();\r
136 \r
137         return is;\r
138     }\r
139 \r
140     /**\r
141      * {@inheritDoc}\r
142      * URL変換したあとの入力ソースを返す。\r
143      * @param type {@inheritDoc}\r
144      * @param namespaceURI {@inheritDoc}\r
145      * @param publicId {@inheritDoc}\r
146      * @param systemId {@inheritDoc}\r
147      * @param baseURI {@inheritDoc}\r
148      * @return {@inheritDoc}\r
149      */\r
150     @Override\r
151     public LSInput resolveResource(String type,\r
152                                      String namespaceURI,\r
153                                      String publicId,\r
154                                      String systemId,\r
155                                      String baseURI ){\r
156         if(systemId == null) return null;\r
157 \r
158         URI originalURI;\r
159         try{\r
160             originalURI = buildBaseRelativeURI(baseURI, systemId);\r
161         }catch(URISyntaxException e){\r
162             return null;\r
163         }\r
164 \r
165         InputStream is;\r
166         try{\r
167             is = getXMLResourceAsStream(originalURI);\r
168         }catch(IOException e){\r
169             return null;\r
170         }\r
171 \r
172         LSInput input = createLSInput();\r
173         input.setBaseURI(baseURI);\r
174         input.setPublicId(publicId);\r
175         input.setSystemId(systemId);\r
176         input.setByteStream(is);\r
177 \r
178         return input;\r
179     }\r
180 \r
181     /**\r
182      * {@inheritDoc}\r
183      * URL変換したあとの入力ソースを返す。\r
184      * @param publicId {@inheritDoc}\r
185      * @param systemId {@inheritDoc}\r
186      * @return {@inheritDoc}\r
187      * @throws org.xml.sax.SAXException {@inheritDoc}\r
188      * @throws java.io.IOException {@inheritDoc}\r
189      */\r
190     @Override\r
191     public InputSource resolveEntity(String publicId, String systemId)\r
192             throws SAXException, IOException{\r
193         if(systemId == null) return null;\r
194 \r
195         URI originalUri;\r
196         try{\r
197             originalUri = new URI(systemId);\r
198         }catch(URISyntaxException e){\r
199             return null;\r
200         }\r
201 \r
202         InputStream is = getXMLResourceAsStream(originalUri);\r
203 \r
204         InputSource source = new InputSource(is);\r
205         source.setPublicId(publicId);\r
206         source.setSystemId(systemId);\r
207 \r
208         return source;\r
209     }\r
210 \r
211     /**\r
212      * JRE1.5用LSInput実装。\r
213      * JRE1.6なら\r
214      * org.w3c.dom.ls.DOMImplementationLS#createLSInput()\r
215      * で生成可能かも。\r
216      */\r
217     private static class LSInputImpl implements LSInput {\r
218 \r
219         private String baseURI = null;\r
220         private InputStream byteStream = null;\r
221         private boolean certifiedText = false;\r
222         private Reader characterStream = null;\r
223         private String encoding = null;\r
224         private String publicId = null;\r
225         private String stringData = null;\r
226         private String systemId = null;\r
227 \r
228         /**\r
229          * コンストラクタ。\r
230          */\r
231         private LSInputImpl(){\r
232             super();\r
233             return;\r
234         }\r
235 \r
236         /**\r
237          * {@inheritDoc}\r
238          * @return {@inheritDoc}\r
239          */\r
240         @Override\r
241         public String getBaseURI(){\r
242             return this.baseURI;\r
243         }\r
244 \r
245         /**\r
246          * {@inheritDoc}\r
247          * @param baseURI {@inheritDoc}\r
248          */\r
249         @Override\r
250         public void setBaseURI(String baseURI){\r
251             this.baseURI = baseURI;\r
252             return;\r
253         }\r
254 \r
255         /**\r
256          * {@inheritDoc}\r
257          * @return {@inheritDoc}\r
258          */\r
259         @Override\r
260         public InputStream getByteStream(){\r
261             return this.byteStream;\r
262         }\r
263 \r
264         /**\r
265          * {@inheritDoc}\r
266          * @param byteStream {@inheritDoc}\r
267          */\r
268         @Override\r
269         public void setByteStream(InputStream byteStream){\r
270             this.byteStream = byteStream;\r
271         }\r
272 \r
273         /**\r
274          * {@inheritDoc}\r
275          * @return {@inheritDoc}\r
276          */\r
277         @Override\r
278         public boolean getCertifiedText(){\r
279             return this.certifiedText;\r
280         }\r
281 \r
282         /**\r
283          * {@inheritDoc}\r
284          * @param certifiedText {@inheritDoc}\r
285          */\r
286         @Override\r
287         public void setCertifiedText(boolean certifiedText){\r
288             this.certifiedText = certifiedText;\r
289             return;\r
290         }\r
291 \r
292         /**\r
293          * {@inheritDoc}\r
294          * @return {@inheritDoc}\r
295          */\r
296         @Override\r
297         public Reader getCharacterStream(){\r
298             return this.characterStream;\r
299         }\r
300 \r
301         /**\r
302          * {@inheritDoc}\r
303          * @param characterStream {@inheritDoc}\r
304          */\r
305         @Override\r
306         public void setCharacterStream(Reader characterStream){\r
307             this.characterStream = characterStream;\r
308         }\r
309 \r
310         /**\r
311          * {@inheritDoc}\r
312          * @return {@inheritDoc}\r
313          */\r
314         @Override\r
315         public String getEncoding(){\r
316             return this.encoding;\r
317         }\r
318 \r
319         /**\r
320          * {@inheritDoc}\r
321          * @param encoding {@inheritDoc}\r
322          */\r
323         @Override\r
324         public void setEncoding(String encoding){\r
325             this.encoding = encoding;\r
326             return;\r
327         }\r
328 \r
329         /**\r
330          * {@inheritDoc}\r
331          * @return {@inheritDoc}\r
332          */\r
333         @Override\r
334         public String getPublicId(){\r
335             return this.publicId;\r
336         }\r
337 \r
338         /**\r
339          * {@inheritDoc}\r
340          * @param publicId {@inheritDoc}\r
341          */\r
342         @Override\r
343         public void setPublicId(String publicId){\r
344             this.publicId = publicId;\r
345             return;\r
346         }\r
347 \r
348         /**\r
349          * {@inheritDoc}\r
350          * @return {@inheritDoc}\r
351          */\r
352         @Override\r
353         public String getStringData(){\r
354             return this.stringData;\r
355         }\r
356 \r
357         /**\r
358          * {@inheritDoc}\r
359          * @param stringData {@inheritDoc}\r
360          */\r
361         @Override\r
362         public void setStringData(String stringData){\r
363             this.stringData = stringData;\r
364             return;\r
365         }\r
366 \r
367         /**\r
368          * {@inheritDoc}\r
369          * @return {@inheritDoc}\r
370          */\r
371         @Override\r
372         public String getSystemId(){\r
373             return this.systemId;\r
374         }\r
375 \r
376         /**\r
377          * {@inheritDoc}\r
378          * @param systemId {@inheritDoc}\r
379          */\r
380         @Override\r
381         public void setSystemId(String systemId){\r
382             this.systemId = systemId;\r
383             return;\r
384         }\r
385 \r
386     }\r
387 \r
388     // TODO OASIS XML Catalog などと調和したい。\r
389 }\r