OSDN Git Service

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