OSDN Git Service

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