OSDN Git Service

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