OSDN Git Service

5af978974ffb70c08dc7d3b5e13adc053e65650a
[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.net.URI;
13 import java.net.URISyntaxException;
14 import java.net.URL;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.Map;
18 import org.w3c.dom.DOMImplementation;
19 import org.w3c.dom.bootstrap.DOMImplementationRegistry;
20 import org.w3c.dom.ls.DOMImplementationLS;
21 import org.w3c.dom.ls.LSInput;
22 import org.w3c.dom.ls.LSResourceResolver;
23
24 /**
25  * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。
26  * 相対URIはこのクラスをベースに解決される。
27  * 主な用途は外部スキーマのリソース化など。
28  */
29 public class XmlResourceResolver
30         implements LSResourceResolver{
31
32     private static final URI EMPTY_URI = URI.create("");
33
34     private static final DOMImplementationLS DOM_LS;
35
36
37     private final Map<URI, URI> uriMap;
38
39
40     static{
41         try{
42             DOM_LS = buildDomImplLS();
43         }catch(   ClassNotFoundException
44                 | IllegalAccessException
45                 | InstantiationException e){
46             throw new ExceptionInInitializerError(e);
47         }
48     }
49
50
51     /**
52      * コンストラクタ。
53      */
54     public XmlResourceResolver(){
55         super();
56
57         Map<URI, URI> map;
58         map = new HashMap<>();
59         map = Collections.synchronizedMap(map);
60         this.uriMap = map;
61
62         return;
63     }
64
65
66     /**
67      * return DOMImplementationLS implement.
68      *
69      * @return DOMImplementationLS implement
70      * @throws ClassNotFoundException no class
71      * @throws InstantiationException no object
72      * @throws IllegalAccessException no grant
73      */
74     private static DOMImplementationLS buildDomImplLS() throws
75             ClassNotFoundException,
76             InstantiationException,
77             IllegalAccessException {
78         DOMImplementationRegistry domReg;
79         DOMImplementation         domImp;
80         DOMImplementationLS       domImpLs;
81
82         domReg = DOMImplementationRegistry.newInstance();
83         domImp = domReg.getDOMImplementation("LS 3.0");
84
85         Object feature = domImp.getFeature("LS", "3.0");
86         assert feature instanceof DOMImplementationLS;
87         domImpLs = (DOMImplementationLS) feature;
88
89         return domImpLs;
90     }
91
92     /**
93      * return LSInput implement.
94      *
95      * @return LSInput implement
96      */
97     public static LSInput createLSInput(){
98         LSInput input = DOM_LS.createLSInput();
99         return input;
100     }
101
102     /**
103      * 絶対URIと相対URIを合成したURIを返す。
104      * 正規化も行われる。
105      *
106      * @param base 絶対URIでなければならない。nullでもよい。
107      * @param relative 絶対URIでもよいがその場合baseは無視される。null可。
108      * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
109      * @throws java.net.URISyntaxException URIとして変。
110      * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
111      */
112     protected static URI buildBaseRelativeURI(String base, String relative)
113             throws URISyntaxException,
114                    IllegalArgumentException {
115         URI baseURI;
116         if(base != null){
117             baseURI = new URI(base);
118             if( ! baseURI.isAbsolute() ){
119                 throw new IllegalArgumentException();
120             }
121         }else{
122             baseURI = null;
123         }
124
125         URI relativeURI;
126         if(relative != null){
127             relativeURI = new URI(relative);
128         }else{
129             relativeURI = EMPTY_URI;
130         }
131
132         URI result = buildBaseRelativeURI(baseURI, relativeURI);
133         return result;
134     }
135
136     /**
137      * 絶対URIと相対URIを合成したURIを返す。
138      * 正規化も行われる。
139      *
140      * @param baseURI 絶対URIでなければならない。nullでもよい。
141      * @param relativeURI 絶対URIでもよいがその場合baseは無視される。
142      * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
143      * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
144      */
145     private static URI buildBaseRelativeURI(URI baseURI, URI relativeURI)
146             throws IllegalArgumentException {
147         URI resultURI;
148
149         if(baseURI == null || relativeURI.isAbsolute()){
150             resultURI = relativeURI;
151         }else{
152             resultURI = baseURI.resolve(relativeURI);
153         }
154
155         if( ! resultURI.isAbsolute() ){
156             throw new IllegalArgumentException();
157         }
158
159         resultURI = resultURI.normalize();
160
161         return resultURI;
162     }
163
164
165     /**
166      * オリジナルURIとリダイレクト先のURIを登録する。
167      * オリジナルURIへのアクセスはリダイレクトされる。
168      *
169      * @param original オリジナルURI
170      * @param redirect リダイレクトURI
171      */
172     private void putRedirectedImpl(URI original, URI redirect){
173         URI oridinalNorm = original.normalize();
174         URI redirectNorm = redirect.normalize();
175
176         this.uriMap.put(oridinalNorm, redirectNorm);
177
178         return;
179     }
180
181     /**
182      * オリジナルURIとリダイレクト先のURIを登録する。
183      * オリジナルURIへのアクセスはリダイレクトされる。
184      *
185      * @param original オリジナルURI
186      * @param redirect リダイレクトURI
187      */
188     public void putRedirected(URI original, URI redirect){
189         putRedirectedImpl(original, redirect);
190         return;
191     }
192
193     /**
194      * ローカル版リソース参照解決を登録する。
195      *
196      * @param lsc ローカル版リソース参照解決
197      */
198     public void putRedirected(LocalXmlResource lsc){
199         URI original = lsc.getOriginalResource();
200         if(original == null) return;
201
202         URI local = lsc.getLocalResource();
203
204         putRedirected(original, local);
205
206         return;
207     }
208
209     /**
210      * 別リゾルバの登録内容を追加登録する。
211      *
212      * @param other 別リゾルバ
213      */
214     public void putRedirected(XmlResourceResolver other){
215         this.uriMap.putAll(other.uriMap);
216         return;
217     }
218
219     /**
220      * 登録済みリダイレクト先URIを返す。
221      *
222      * @param original オリジナルURI
223      * @return リダイレクト先URI。未登録の場合はnull
224      */
225     public URI getRedirected(URI original){
226         URI keyURI = original.normalize();
227         URI resourceURI = this.uriMap.get(keyURI);
228         return resourceURI;
229     }
230
231     /**
232      * 登録済みリダイレクト先URIを返す。
233      *
234      * @param original オリジナルURI
235      * @return リダイレクト先URI。未登録の場合はオリジナルを返す
236      */
237     public URI resolveRedirected(URI original){
238         URI result = getRedirected(original);
239         if(result == null) result = original;
240         return result;
241     }
242
243     /**
244      * 登録済みリダイレクト先リソースの入力ストリームを得る。
245      *
246      * @param originalURI オリジナルURI
247      * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
248      * @throws java.io.IOException 入出力エラー。
249      *     もしくはリソースが見つからない。
250      */
251     private InputStream getXMLResourceAsStream(URI originalURI)
252             throws IOException{
253         URI resourceURI = getRedirected(originalURI);
254         if(resourceURI == null) return null;
255
256         URL resourceURL = resourceURI.toURL();
257         InputStream is = resourceURL.openStream();
258
259         return is;
260     }
261
262     /**
263      * {@inheritDoc}
264      *
265      * <p>URL変換したあとの入力ソースを返す。
266      *
267      * @param type {@inheritDoc}
268      * @param namespaceURI {@inheritDoc}
269      * @param publicId {@inheritDoc}
270      * @param systemId {@inheritDoc}
271      * @param baseURI {@inheritDoc}
272      * @return {@inheritDoc}
273      */
274     @Override
275     public LSInput resolveResource(String type,
276                                      String namespaceURI,
277                                      String publicId,
278                                      String systemId,
279                                      String baseURI ){
280         if(systemId == null) return null;
281
282         URI originalURI;
283         try{
284             originalURI = buildBaseRelativeURI(baseURI, systemId);
285         }catch(URISyntaxException e){
286             return null;
287         }
288
289         InputStream is;
290         try{
291             is = getXMLResourceAsStream(originalURI);
292         }catch(IOException e){
293             return null;
294         }
295         if(is == null) return null;
296
297         LSInput input = createLSInput();
298         input.setBaseURI(baseURI);
299         input.setPublicId(publicId);
300         input.setSystemId(systemId);
301         input.setByteStream(is);
302
303         return input;
304     }
305
306 }