1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package junitx.ddtunit.data.processing.parser;
39
40 import java.io.File;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.Reader;
44 import java.io.StringReader;
45 import java.net.MalformedURLException;
46
47 import javax.xml.parsers.ParserConfigurationException;
48 import javax.xml.parsers.SAXParser;
49 import javax.xml.parsers.SAXParserFactory;
50
51 import junitx.ddtunit.DDTException;
52 import junitx.ddtunit.data.DDTTestDataException;
53 import junitx.ddtunit.data.TestClusterDataSet;
54 import junitx.ddtunit.data.TypedObject;
55 import junitx.ddtunit.data.processing.IParser;
56 import junitx.ddtunit.util.DDTConfiguration;
57
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.xml.sax.InputSource;
61 import org.xml.sax.Locator;
62 import org.xml.sax.SAXException;
63 import org.xml.sax.SAXNotRecognizedException;
64 import org.xml.sax.SAXParseException;
65 import org.xml.sax.XMLReader;
66 import org.xml.sax.helpers.DefaultHandler;
67 import org.xml.sax.helpers.LocatorImpl;
68
69
70
71
72
73
74
75
76
77 public final class ParserImpl implements IParser {
78 private static final String XML_XERCES_NONAMESPACE_SCHEMA_LOCATION_URI = "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
79
80 private static final String XML_XERCES_SCHEMA_FULL_CHECK_URI = "http://apache.org/xml/features/validation/schema-full-checking";
81
82 private static final String XML_VALIDATE_URI = "http://xml.org/sax/features/validation";
83
84 private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
85
86 private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
87
88 private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
89
90 private static final String XML_LEXICAL_HANDLER_URI = "http://xml.org/sax/properties/lexical-handler";
91
92 private static final String XML_XERCES_VALIDATE_URI = "http://apache.org/xml/features/validation/schema";
93
94
95
96
97 public final static String XSD_URL = "http://ddtunit.sourceforge.net/ddtunit.xsd";
98
99
100
101
102 public final static String XSD_RESOURCE_PATH = "/junitx/ddtunit/data/processing/parser/ddtunit.xsd";
103
104 private final Logger log = LoggerFactory.getLogger(ParserImpl.class);
105
106 private XMLReader producer;
107
108 private ContentHandler consumer;
109
110 private final static String XML_NAMESPACE_URI = "http://xml.org/sax/features/namespaces";
111
112 private final static String XML_NAMESPACE_PREFIX_URI = "http://xml.org/sax/features/namespace-prefixes";
113
114 private static final String LF = System.getProperty("line.separator");
115
116 private static final String XML_HEADER = "<?xml version=\"1.0\" ?>";
117
118
119
120
121 public ParserImpl() {
122 log.debug("DDTParser - constructor START");
123 try {
124
125
126
127 SAXParserFactory factory = SAXParserFactory.newInstance();
128 factory.setNamespaceAware(true);
129 factory.setValidating(DDTConfiguration.getInstance().isActiveXmlValidation());
130 SAXParser saxParser = factory.newSAXParser();
131
132
133 this.producer = saxParser.getXMLReader();
134 this.producer.setFeature(XML_NAMESPACE_PREFIX_URI, false);
135 this.producer.setFeature(XML_NAMESPACE_URI, true);
136 } catch (SAXNotRecognizedException e) {
137 throw DDTException
138 .create(
139 new StringBuffer(
140 "XML ParserImpl does not support schema validation as of JAXP 1.2"),
141 e);
142 } catch (ParserConfigurationException e) {
143 throw DDTException.create(new StringBuffer(
144 "Error configuring parser."), e);
145 } catch (SAXException e) {
146 throw DDTException.create(new StringBuffer(
147 "Error configuring parser."), e);
148 }
149 this.producer.setErrorHandler(new ErrorHandler());
150 this.producer.setEntityResolver(new EntityResolver());
151 log.debug("DDTParser - constructor END");
152 }
153
154
155
156
157
158
159
160 public TestClusterDataSet parse(String resource, boolean byName,
161 String clusterId, TestClusterDataSet baseDataSet) {
162 log.debug("parse(" + resource + ", " + clusterId + ")-START");
163 this.consumer = new ContentHandler(resource, baseDataSet);
164 Locator locator = new LocatorImpl();
165 this.consumer.setDocumentLocator(locator);
166
167 try {
168
169 this.consumer.setClusterId(clusterId);
170
171 InputSource iSource = createInputSource(resource, true);
172 if (validateSource(iSource)) {
173 iSource = createInputSource(resource, byName);
174 }
175 this.producer.setProperty("http://xml.org/sax/properties/"
176 + "lexical-handler", consumer);
177 this.producer.setContentHandler(consumer);
178 this.producer.parse(iSource);
179 } catch (IOException e) {
180 log.error("Error on behalf of xml test resource.", e);
181 throw DDTTestDataException.create(new StringBuffer(
182 "Error on behalf of xml test resource."), e);
183 } catch (SAXException e) {
184 StringBuffer sb = new StringBuffer(
185 "Error during parsing of xml testresource");
186 if (SAXParseException.class.isInstance(e)) {
187 sb.append(LF).append("Resource \'").append(resource).append(
188 "\' line/column ").append(
189 ((SAXParseException) e).getLineNumber()).append("/")
190 .append(((SAXParseException) e).getColumnNumber());
191 }
192 log.error(sb.toString(), e);
193 throw DDTTestDataException.create(sb, e);
194 } finally {
195 log.debug("parse(" + resource + ", " + clusterId + ")-END");
196 }
197 if (baseDataSet.size() == 0) {
198 StringBuffer sb = new StringBuffer(
199 "No testdata provided for class id \'")
200 .append(baseDataSet.getId())
201 .append("\' in testresource \'")
202 .append(resource)
203 .append("\'\n")
204 .append(
205 "Check if referred class id in xml resources matches definition")
206 .append(
207 " of \n initTestData(resource, classId) inside of your testclass.");
208 throw new DDTTestDataException(sb.toString());
209 }
210
211 return baseDataSet;
212 }
213
214
215
216
217
218
219
220
221
222
223
224 public TypedObject parseElement(String xmlObjectDef, boolean addXMLHeader) {
225 TypedObject myObj = null;
226 String defaultCluster = "singleton";
227 log
228 .debug("parse(\"" + xmlObjectDef + "\", " + addXMLHeader
229 + ")-START");
230 TestClusterDataSet dataSet = new TestClusterDataSet(defaultCluster,
231 null);
232 this.consumer = new ContentHandler(null, dataSet);
233 Locator locator = new LocatorImpl();
234 this.consumer.setDocumentLocator(locator);
235 this.producer.setContentHandler(consumer);
236
237
238 try {
239 InputSource iSource = createInputSource(xmlObjectDef, false);
240 validateSource(iSource);
241 iSource = createInputSource(xmlObjectDef, false);
242 this.producer.parse(iSource);
243 } catch (IOException e) {
244 log.error("Error on behalf of xml test resource.", e);
245 throw DDTTestDataException.create(new StringBuffer(
246 "Error on behalf of xml test resource."), e);
247 } catch (SAXException e) {
248 StringBuffer sb = new StringBuffer(
249 "Error during parsing of xml testresource from reader.");
250 throw DDTTestDataException.create(sb, e);
251 } finally {
252 log.debug("parse(reader)-END");
253 }
254 myObj = dataSet.getObject("singleton");
255 return myObj;
256 }
257
258
259
260
261
262
263
264
265
266
267 private InputSource createInputSource(String resource, boolean byName)
268 throws MalformedURLException {
269
270 InputSource iSource = null;
271 if (byName) {
272 InputStream in = this.getClass().getResourceAsStream(resource);
273 if (in == null) {
274 File inFile = new File(resource);
275
276 iSource = new InputSource(resource);
277 iSource.setSystemId(inFile.toURL().toExternalForm());
278 } else {
279 iSource = new InputSource(in);
280 iSource.setSystemId(this.getClass().getResource(resource)
281 .toExternalForm());
282 }
283 } else {
284 String xmlDef = null;
285 xmlDef = XML_HEADER + resource;
286 Reader reader = new StringReader(xmlDef);
287 iSource = new InputSource(reader);
288 }
289 return iSource;
290 }
291
292
293
294
295
296
297 private boolean validateSource(InputSource iSource) {
298 boolean validated = false;
299 try {
300 if (this.producer.getFeature(XML_XERCES_VALIDATE_URI)) {
301 DDTConfiguration.getInstance().setActiveParserValidation(true);
302 }
303 } catch (SAXException ex) {
304
305 }
306 if (DDTConfiguration.getInstance().isActiveXmlValidation()
307 && DDTConfiguration.getInstance().isActiveParserValidation()) {
308 try {
309 validated = true;
310 this.producer.setContentHandler(new DefaultHandler());
311
312 this.producer.setFeature(XML_VALIDATE_URI, true);
313 this.producer.setFeature(XML_XERCES_VALIDATE_URI, true);
314 this.producer
315 .setFeature(XML_XERCES_SCHEMA_FULL_CHECK_URI, true);
316 this.producer.setProperty(
317 XML_XERCES_NONAMESPACE_SCHEMA_LOCATION_URI,
318 ParserImpl.XSD_URL);
319 this.producer.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
320 this.producer.setProperty(JAXP_SCHEMA_SOURCE,
321 ParserImpl.XSD_URL);
322
323 this.producer.parse(iSource);
324 } catch (DDTException ex) {
325 if (ex.getMessage() != null
326 && ex.getMessage().startsWith("Error during parsing")) {
327 throw ex;
328 }
329 log.warn("Error on validation", ex);
330 } catch (IOException e) {
331 log.error("Error on behalf of xml test resource.", e);
332 throw DDTException.create(new StringBuffer(
333 "Error on behalf of xml test resource."), e);
334 } catch (SAXException e) {
335 StringBuffer sb = new StringBuffer(
336 "Error during parsing of xml testresource");
337 if (SAXParseException.class.isInstance(e)) {
338 sb.append(LF).append("Resource \'").append(
339 iSource.getSystemId()).append("\' line/column ")
340 .append(((SAXParseException) e).getLineNumber())
341 .append("/").append(
342 ((SAXParseException) e).getColumnNumber());
343 }
344 log.error(sb.toString(), e);
345 throw DDTException.create(sb, e);
346 }
347 }
348 return validated;
349 }
350
351 public TypedObject parseElement(String xmlObjectDef) {
352 return parseElement(xmlObjectDef, true);
353 }
354
355 }