OSDN Git Service

modify javadoc paragraph.
[mikutoga/Pmd2XML.git] / src / main / java / jp / sfjp / mikutoga / pmd2xml / XmlInputUtil.java
1 /*
2  * xml input utility
3  *
4  * License : The MIT License
5  * Copyright(c) 2013 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.pmd2xml;
9
10 import java.io.BufferedInputStream;
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.net.MalformedURLException;
15 import java.net.URI;
16 import java.net.URL;
17 import javax.xml.XMLConstants;
18 import javax.xml.parsers.ParserConfigurationException;
19 import javax.xml.parsers.SAXParser;
20 import javax.xml.parsers.SAXParserFactory;
21 import javax.xml.validation.Schema;
22 import jp.sfjp.mikutoga.pmd.model.xml.Schema101009;
23 import jp.sfjp.mikutoga.pmd.model.xml.Schema130128;
24 import jp.sfjp.mikutoga.xml.BotherHandler;
25 import jp.sfjp.mikutoga.xml.NoopEntityResolver;
26 import jp.sfjp.mikutoga.xml.SchemaUtil;
27 import org.xml.sax.InputSource;
28 import org.xml.sax.SAXException;
29 import org.xml.sax.SAXNotRecognizedException;
30 import org.xml.sax.SAXNotSupportedException;
31 import org.xml.sax.XMLReader;
32
33 /**
34  * XML入力に関する各種ユーティリティ。
35  */
36 final class XmlInputUtil {
37
38     private static final String F_DISALLOW_DOCTYPE_DECL =
39             "http://apache.org/xml/features/disallow-doctype-decl";
40     private static final String F_EXTERNAL_GENERAL_ENTITIES =
41             "http://xml.org/sax/features/external-general-entities";
42     private static final String F_EXTERNAL_PARAMETER_ENTITIES =
43             "http://xml.org/sax/features/external-parameter-entities";
44     private static final String F_LOAD_EXTERNAL_DTD =
45             "http://apache.org/xml/features/nonvalidating/load-external-dtd";
46
47
48     /**
49      * 隠しコンストラクタ。
50      */
51     private XmlInputUtil(){
52         assert false;
53         throw new AssertionError();
54     }
55
56
57     /**
58      * 実在ファイルからXML入力ソースを得る。
59      *
60      * @param file 実在ファイル
61      * @return XML入力ソース
62      */
63     static InputSource fileToSource(File file){
64         assert file.exists();
65
66         URI uri = file.toURI();
67
68         URL url;
69         try{
70             url = uri.toURL();
71         }catch(MalformedURLException e){
72             // 実在File由来のURLでは起こりえない
73             assert false;
74             throw new AssertionError(e);
75         }
76
77         String systemId = url.toString();
78
79         InputSource source = new InputSource(systemId);
80
81         return source;
82     }
83
84     /**
85      * InputSourceからInputStreamを得る。
86      *
87      * <p>入力ソースには、少なくともバイトストリームか
88      * URL文字列(SystemId)のいずれかが設定されていなければならない。
89      *
90      * @param source 入力ソース
91      * @return 入力バイトストリーム
92      * @throws IllegalArgumentException 入力ソースの設定が足りない。
93      * @throws IOException 入力ソースにアクセス不能。
94      */
95     static InputStream openInputSource(InputSource source)
96             throws IllegalArgumentException, IOException{
97         InputStream is;
98
99         is = source.getByteStream();
100
101         if(is == null){
102             String systemId = source.getSystemId();
103             if(systemId == null) throw new IllegalArgumentException();
104
105             URL url = new URL(systemId);
106             is = url.openStream();
107         }
108
109         is = new BufferedInputStream(is);
110
111         return is;
112     }
113
114     /**
115      * SAXパーサファクトリを生成する。
116      *
117      * <ul>
118      * <li>XML名前空間機能は有効になる。
119      * <li>DTDによる形式検証は無効となる。
120      * <li>XIncludeによる差し込み機能は無効となる。
121      * </ul>
122      *
123      * @param schema スキーマ
124      * @return ファクトリ
125      */
126     private static SAXParserFactory buildFactory(Schema schema){
127         SAXParserFactory factory = SAXParserFactory.newInstance();
128
129         factory.setNamespaceAware(true);
130         factory.setValidating(false);
131         factory.setXIncludeAware(false);
132
133         try{
134             factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
135             factory.setFeature(F_DISALLOW_DOCTYPE_DECL, true);
136             factory.setFeature(F_EXTERNAL_GENERAL_ENTITIES, false);
137             factory.setFeature(F_EXTERNAL_PARAMETER_ENTITIES, false);
138             factory.setFeature(F_LOAD_EXTERNAL_DTD, false);
139         }catch(   ParserConfigurationException
140                 | SAXNotRecognizedException
141                 | SAXNotSupportedException e ){
142             assert false;
143             throw new AssertionError(e);
144         }
145
146         factory.setSchema(schema);
147
148         return factory;
149     }
150
151     /**
152      * SAXパーサを生成する。
153      *
154      * @param schema スキーマ
155      * @return SAXパーサ
156      */
157     private static SAXParser buildParser(Schema schema){
158         SAXParserFactory factory = buildFactory(schema);
159
160         SAXParser parser;
161         try{
162             parser = factory.newSAXParser();
163         }catch(ParserConfigurationException | SAXException e){
164             assert false;
165             throw new AssertionError(e);
166         }
167
168         try{
169             parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
170             parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
171         }catch(SAXNotRecognizedException | SAXNotSupportedException e){
172             assert false;
173             throw new AssertionError(e);
174         }
175
176         return parser;
177     }
178
179     /**
180      * スキーマを生成する。
181      *
182      * @param xmlInType 入力XML種別
183      * @return スキーマ
184      */
185     private static Schema buildSchema(ModelFileType xmlInType ){
186         URI[] schemaUris;
187         switch(xmlInType){
188         case XML_101009:
189             schemaUris = new URI[]{
190                 Schema101009.RES_SCHEMA_PMDXML,
191             };
192             break;
193         case XML_130128:
194             schemaUris = new URI[]{
195                 Schema130128.RES_SCHEMA_PMDXML,
196             };
197             break;
198         case XML_AUTO:
199             schemaUris = new URI[]{
200                 Schema101009.RES_SCHEMA_PMDXML,
201                 Schema130128.RES_SCHEMA_PMDXML,
202             };
203             break;
204         default:
205             throw new IllegalStateException();
206         }
207
208         Schema schema;
209         try{
210             schema = SchemaUtil.newSchema(schemaUris);
211         }catch(IOException | SAXException e){
212             assert false;
213             throw new AssertionError(e);
214         }
215
216         return schema;
217     }
218
219     /**
220      * XMLリーダを生成する。
221      *
222      * <p>エラーハンドラには{@link BotherHandler}が指定される。
223      *
224      * @param xmlInType 入力XML種別
225      * @return XMLリーダ
226      */
227     static XMLReader buildReader(ModelFileType xmlInType){
228         Schema schema = buildSchema(xmlInType);
229
230         SAXParser parser = buildParser(schema);
231
232         XMLReader reader;
233         try{
234             reader = parser.getXMLReader();
235         }catch(SAXException e){
236             assert false;
237             throw new AssertionError(e);
238         }
239
240         reader.setEntityResolver(NoopEntityResolver.NOOP_RESOLVER);
241         reader.setErrorHandler(BotherHandler.HANDLER);
242
243         return reader;
244     }
245
246 }