View Javadoc

1   package pl.psnc.dl.ege.validator.xml;
2   
3   import java.io.FileNotFoundException;
4   import java.io.IOException;
5   import java.io.InputStream;
6   import java.io.OutputStream;
7   import java.io.PipedInputStream;
8   import java.io.PipedOutputStream;
9   
10  import javax.xml.parsers.ParserConfigurationException;
11  import javax.xml.parsers.SAXParser;
12  import javax.xml.parsers.SAXParserFactory;
13  
14  import org.apache.log4j.Logger;
15  import org.jdom.DocType;
16  import org.jdom.Document;
17  import org.jdom.JDOMException;
18  import org.jdom.input.SAXBuilder;
19  import org.jdom.output.XMLOutputter;
20  import org.xml.sax.ErrorHandler;
21  import org.xml.sax.InputSource;
22  import org.xml.sax.SAXException;
23  import org.xml.sax.SAXParseException;
24  import org.xml.sax.XMLReader;
25  
26  import pl.psnc.dl.ege.ExceptionListener;
27  import pl.psnc.dl.ege.validator.StandardErrorHandler;
28  
29  /**
30   * Validates XML data against referenced external DTD.<br/><br/>
31   *  
32   * If streamed XML data has no !DOCTYPE declaration, validator adds it by default
33   * with specified external reference to DTD and root element.<br/><br/>   
34   *  
35   * @author mariuszs
36   */
37  public class DTDValidator
38  	implements XmlValidator
39  {
40  
41  	private static final Logger LOGGER = Logger.getLogger(DTDValidator.class);
42  
43  	/*
44  	 * DTD declaration systemId 
45  	 */
46  	private final String mainDTD;
47  
48  	/*
49  	 * Root element for DTD declaration
50  	 */
51  	private final String root;
52  
53  
54  	/**
55  	 * Default constructor.
56  	 * 
57  	 * @param systemId - "systemId" of !DOCTYPE declaration
58  	 * @param root - root-element of !DOCTYPE declaration
59  	 */
60  	public DTDValidator(String systemId, String root)
61  	{
62  		if (systemId == null || root == null) {
63  			throw new IllegalArgumentException();
64  		}
65  		this.root = root;
66  		this.mainDTD = systemId;
67  	}
68  
69  	/**
70  	 * Performs XML stream validation.<br/>
71  	 * Validation results can be stored within {@link ErrorHandler} implementation
72  	 * ({@link StandardErrorHandler} by default).
73  	 * 
74  	 * @param inputData - streamed XML data.
75  	 */
76  	public void validateXml(InputStream inputData, ErrorHandler errorHandler)
77  		throws SAXException, FileNotFoundException, IOException, Exception
78  	{
79  		PipedOutputStream os = new PipedOutputStream();
80  		PipedInputStream is = new PipedInputStream(os);
81  		ExceptionListenerImpl el = new ExceptionListenerImpl();
82  		DoctypeFilter filter = new DoctypeFilter(inputData, os, el, errorHandler);
83  		filter.start();
84  		SAXParserFactory factory = SAXParserFactory.newInstance();
85  		factory.setValidating(true);
86  		factory.setNamespaceAware(true);
87  		try {
88  			SAXParser parser = factory.newSAXParser();
89  			XMLReader reader = parser.getXMLReader();
90  			reader.setErrorHandler(errorHandler);
91  			reader.parse(new InputSource(is));
92  		}
93  		catch (ParserConfigurationException ex) {
94  			throw new SAXException(ex.getMessage());
95  		}catch (SAXParseException ex){
96  			filter.join();
97  			Exception exe = el.throwException();
98  			if(exe != null){
99  				throw exe;
100 			}
101 		}
102 	}
103 
104 	/*
105 	 * Adds !DOCTYPE declaration to XML stream (if it does not exists)
106 	 * with validation DTD.
107 	 */
108 	private class DoctypeFilter
109 		extends Thread
110 	{
111 
112 		private final InputStream inputStream;
113 
114 		private final OutputStream outputStream;
115 
116 		private final ExceptionListener el;
117 		
118 		private final ErrorHandler eh;
119 
120 		public DoctypeFilter(InputStream is, OutputStream os,
121 				ExceptionListener el, ErrorHandler eh)
122 		{
123 			super();
124 			inputStream = is;
125 			outputStream = os;
126 			this.el = el;
127 			this.eh = eh;
128 		}
129 
130 
131 		@Override
132 		public void run()
133 		{
134 			try {
135 				SAXBuilder sb = new SAXBuilder();
136 				Document doc = sb.build(inputStream);
137 				if (doc.getDocType() == null) {
138 					doc.setDocType(new DocType(root, mainDTD));
139 				}
140 				XMLOutputter outp = new XMLOutputter();
141 				outp.output(doc, outputStream);
142 				outputStream.flush();
143 			}
144 			catch(FileNotFoundException ex){
145 				el.catchException(ex);
146 			}
147 			catch (JDOMException ex) {
148 				el.catchException(ex);
149 			}
150 			catch (IOException ex) {
151 				LOGGER.error(ex.getMessage(), ex);
152 				el.catchException(ex);
153 			}
154 			finally {
155 				if (outputStream != null) {
156 					try {
157 						outputStream.close();
158 					}
159 					catch (IOException ex) {
160 						LOGGER.error(ex.getMessage());
161 					}
162 				}
163 			}
164 
165 		}
166 
167 	}
168 
169 }