OSDN Git Service

2.102.2版リリース準備
[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/xmlspace.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         putRedirectedImpl(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 putRedirectedImpl(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 putRedirected(URI original, URI redirect){
154         putRedirectedImpl(original, redirect);
155         return;
156     }
157
158     /**
159      * 別リゾルバの登録内容を追加登録する。
160      * @param other 別リゾルバ
161      */
162     public void putRedirected(XmlResourceResolver other){
163         this.uriMap.putAll(other.uriMap);
164         return;
165     }
166
167     /**
168      * 登録済みリダイレクト先URIを返す。
169      * @param original オリジナルURI
170      * @return リダイレクト先URI。未登録の場合はnull
171      */
172     public URI getRedirected(URI original){
173         URI keyURI = original.normalize();
174         URI resourceURI = this.uriMap.get(keyURI);
175         return resourceURI;
176     }
177
178     /**
179      * 登録済みリダイレクト先URIを返す。
180      * @param original オリジナルURI
181      * @return リダイレクト先URI。未登録の場合はオリジナルを返す
182      */
183     public URI resolveRedirected(URI original){
184         URI result = getRedirected(original);
185         if(result == null) result = original;
186         return result;
187     }
188
189     /**
190      * 登録済みリダイレクト先リソースの入力ストリームを得る。
191      * @param originalURI オリジナルURI
192      * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
193      * @throws java.io.IOException 入出力エラー。
194      * もしくはリソースが見つからない。
195      */
196     private InputStream getXMLResourceAsStream(URI originalURI)
197             throws IOException{
198         URI resourceURI = getRedirected(originalURI);
199         if(resourceURI == null) return null;
200
201         URL resourceURL = resourceURI.toURL();
202         InputStream is = resourceURL.openStream();
203
204         return is;
205     }
206
207     /**
208      * {@inheritDoc}
209      * URL変換したあとの入力ソースを返す。
210      * @param type {@inheritDoc}
211      * @param namespaceURI {@inheritDoc}
212      * @param publicId {@inheritDoc}
213      * @param systemId {@inheritDoc}
214      * @param baseURI {@inheritDoc}
215      * @return {@inheritDoc}
216      */
217     @Override
218     public LSInput resolveResource(String type,
219                                      String namespaceURI,
220                                      String publicId,
221                                      String systemId,
222                                      String baseURI ){
223         if(systemId == null) return null;
224
225         URI originalURI;
226         try{
227             originalURI = buildBaseRelativeURI(baseURI, systemId);
228         }catch(URISyntaxException e){
229             return null;
230         }
231
232         InputStream is;
233         try{
234             is = getXMLResourceAsStream(originalURI);
235         }catch(IOException e){
236             return null;
237         }
238         if(is == null) return null;
239
240         LSInput input = createLSInput();
241         input.setBaseURI(baseURI);
242         input.setPublicId(publicId);
243         input.setSystemId(systemId);
244         input.setByteStream(is);
245
246         return input;
247     }
248
249     /**
250      * {@inheritDoc}
251      * URL変換したあとの入力ソースを返す。
252      * @param publicId {@inheritDoc}
253      * @param systemId {@inheritDoc}
254      * @return {@inheritDoc}
255      * @throws org.xml.sax.SAXException {@inheritDoc}
256      * @throws java.io.IOException {@inheritDoc}
257      */
258     @Override
259     public InputSource resolveEntity(String publicId, String systemId)
260             throws SAXException, IOException{
261         if(systemId == null) return null;
262
263         URI originalUri;
264         try{
265             originalUri = new URI(systemId);
266         }catch(URISyntaxException e){
267             return null;
268         }
269
270         InputStream is = getXMLResourceAsStream(originalUri);
271         if(is == null) return null;
272
273         InputSource source = new InputSource(is);
274         source.setPublicId(publicId);
275         source.setSystemId(systemId);
276
277         return source;
278     }
279
280     /**
281      * JRE1.5用LSInput実装。
282      * JRE1.6なら
283      * org.w3c.dom.ls.DOMImplementationLS#createLSInput()
284      * で生成可能かも。
285      */
286     private static final class LSInputImpl implements LSInput {
287
288         private String baseURI = null;
289         private InputStream byteStream = null;
290         private boolean certifiedText = false;
291         private Reader characterStream = null;
292         private String encoding = null;
293         private String publicId = null;
294         private String stringData = null;
295         private String systemId = null;
296
297         /**
298          * コンストラクタ。
299          */
300         LSInputImpl(){
301             super();
302             return;
303         }
304
305         /**
306          * {@inheritDoc}
307          * @return {@inheritDoc}
308          */
309         @Override
310         public String getBaseURI(){
311             return this.baseURI;
312         }
313
314         /**
315          * {@inheritDoc}
316          * @param baseURI {@inheritDoc}
317          */
318         @Override
319         public void setBaseURI(String baseURI){
320             this.baseURI = baseURI;
321             return;
322         }
323
324         /**
325          * {@inheritDoc}
326          * @return {@inheritDoc}
327          */
328         @Override
329         public InputStream getByteStream(){
330             return this.byteStream;
331         }
332
333         /**
334          * {@inheritDoc}
335          * @param byteStream {@inheritDoc}
336          */
337         @Override
338         public void setByteStream(InputStream byteStream){
339             this.byteStream = byteStream;
340         }
341
342         /**
343          * {@inheritDoc}
344          * @return {@inheritDoc}
345          */
346         @Override
347         public boolean getCertifiedText(){
348             return this.certifiedText;
349         }
350
351         /**
352          * {@inheritDoc}
353          * @param certifiedText {@inheritDoc}
354          */
355         @Override
356         public void setCertifiedText(boolean certifiedText){
357             this.certifiedText = certifiedText;
358             return;
359         }
360
361         /**
362          * {@inheritDoc}
363          * @return {@inheritDoc}
364          */
365         @Override
366         public Reader getCharacterStream(){
367             return this.characterStream;
368         }
369
370         /**
371          * {@inheritDoc}
372          * @param characterStream {@inheritDoc}
373          */
374         @Override
375         public void setCharacterStream(Reader characterStream){
376             this.characterStream = characterStream;
377         }
378
379         /**
380          * {@inheritDoc}
381          * @return {@inheritDoc}
382          */
383         @Override
384         public String getEncoding(){
385             return this.encoding;
386         }
387
388         /**
389          * {@inheritDoc}
390          * @param encoding {@inheritDoc}
391          */
392         @Override
393         public void setEncoding(String encoding){
394             this.encoding = encoding;
395             return;
396         }
397
398         /**
399          * {@inheritDoc}
400          * @return {@inheritDoc}
401          */
402         @Override
403         public String getPublicId(){
404             return this.publicId;
405         }
406
407         /**
408          * {@inheritDoc}
409          * @param publicId {@inheritDoc}
410          */
411         @Override
412         public void setPublicId(String publicId){
413             this.publicId = publicId;
414             return;
415         }
416
417         /**
418          * {@inheritDoc}
419          * @return {@inheritDoc}
420          */
421         @Override
422         public String getStringData(){
423             return this.stringData;
424         }
425
426         /**
427          * {@inheritDoc}
428          * @param stringData {@inheritDoc}
429          */
430         @Override
431         public void setStringData(String stringData){
432             this.stringData = stringData;
433             return;
434         }
435
436         /**
437          * {@inheritDoc}
438          * @return {@inheritDoc}
439          */
440         @Override
441         public String getSystemId(){
442             return this.systemId;
443         }
444
445         /**
446          * {@inheritDoc}
447          * @param systemId {@inheritDoc}
448          */
449         @Override
450         public void setSystemId(String systemId){
451             this.systemId = systemId;
452             return;
453         }
454
455     }
456
457 }