OSDN Git Service

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