OSDN Git Service

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