001 package com.thaiopensource.validate.xerces;
002
003 import com.thaiopensource.util.PropertyMap;
004 import com.thaiopensource.validate.ValidateProperty;
005 import com.thaiopensource.validate.Validator;
006
007 import org.apache.xerces.impl.XMLEntityManager;
008 import org.apache.xerces.impl.XMLErrorReporter;
009 import org.apache.xerces.impl.validation.EntityState;
010 import org.apache.xerces.impl.validation.ValidationManager;
011 import org.apache.xerces.impl.xs.XMLSchemaValidator;
012 import org.apache.xerces.util.NamespaceSupport;
013 import org.apache.xerces.util.ParserConfigurationSettings;
014 import org.apache.xerces.util.SymbolTable;
015 import org.apache.xerces.util.XMLAttributesImpl;
016 import org.apache.xerces.util.XMLSymbols;
017 import org.apache.xerces.util.ErrorHandlerWrapper;
018 import org.apache.xerces.xni.NamespaceContext;
019 import org.apache.xerces.xni.QName;
020 import org.apache.xerces.xni.XMLAttributes;
021 import org.apache.xerces.xni.XMLLocator;
022 import org.apache.xerces.xni.XMLResourceIdentifier;
023 import org.apache.xerces.xni.XMLString;
024 import org.apache.xerces.xni.XNIException;
025 import org.apache.xerces.xni.grammars.XMLGrammarPool;
026 import org.apache.xerces.xni.parser.XMLComponent;
027 import org.apache.xerces.xni.parser.XMLEntityResolver;
028 import org.apache.xerces.xni.parser.XMLInputSource;
029 import org.apache.xerces.xni.parser.XMLParseException;
030 import org.apache.xerces.xni.parser.XMLErrorHandler;
031 import org.xml.sax.Attributes;
032 import org.xml.sax.Locator;
033 import org.xml.sax.SAXException;
034 import org.xml.sax.SAXParseException;
035 import org.xml.sax.DTDHandler;
036 import org.xml.sax.ContentHandler;
037
038 import java.io.IOException;
039 import java.util.Hashtable;
040
041 class ValidatorImpl extends ParserConfigurationSettings implements Validator, ContentHandler, DTDHandler, XMLLocator, XMLEntityResolver, EntityState {
042
043 private final XMLSchemaValidator schemaValidator = new XMLSchemaValidator();
044 private final XMLErrorReporter errorReporter = new XMLErrorReporter();
045 private final XMLEntityManager entityManager = new XMLEntityManager();
046 private final ValidationManager validationManager = new ValidationManager();
047 private final NamespaceContext namespaceContext = new NamespaceSupport();
048 private final XMLAttributes attributes = new XMLAttributesImpl();
049 private final SymbolTable symbolTable;
050 private final XMLComponent[] components;
051 private Locator locator;
052 private final Hashtable entityTable = new Hashtable();
053 private boolean pushedContext = false;
054
055 // JC deal with baseURI
056
057 static private final String[] recognizedFeatures = {
058 Features.SCHEMA_AUGMENT_PSVI,
059 Features.SCHEMA_FULL_CHECKING,
060 Features.VALIDATION,
061 Features.SCHEMA_VALIDATION,
062 };
063
064 static private final String[] recognizedProperties = {
065 Properties.XMLGRAMMAR_POOL,
066 Properties.SYMBOL_TABLE,
067 Properties.ERROR_REPORTER,
068 Properties.ERROR_HANDLER,
069 Properties.VALIDATION_MANAGER,
070 Properties.ENTITY_MANAGER,
071 Properties.ENTITY_RESOLVER,
072 };
073
074 ValidatorImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool, PropertyMap properties) {
075 this.symbolTable = symbolTable;
076 XMLErrorHandler errorHandlerWrapper = new ErrorHandlerWrapper(ValidateProperty.ERROR_HANDLER.get(properties));
077 components = new XMLComponent[] { errorReporter, schemaValidator, entityManager };
078 for (int i = 0; i < components.length; i++) {
079 addRecognizedFeatures(components[i].getRecognizedFeatures());
080 addRecognizedProperties(components[i].getRecognizedProperties());
081 }
082 addRecognizedFeatures(recognizedFeatures);
083 addRecognizedProperties(recognizedProperties);
084 setFeature(Features.SCHEMA_AUGMENT_PSVI, false);
085 setFeature(Features.SCHEMA_FULL_CHECKING, true);
086 setFeature(Features.VALIDATION, true);
087 setFeature(Features.SCHEMA_VALIDATION, true);
088 setProperty(Properties.XMLGRAMMAR_POOL, grammarPool);
089 setProperty(Properties.SYMBOL_TABLE, symbolTable);
090 errorReporter.setDocumentLocator(this);
091 setProperty(Properties.ERROR_REPORTER, errorReporter);
092 setProperty(Properties.ERROR_HANDLER, errorHandlerWrapper);
093 setProperty(Properties.VALIDATION_MANAGER, validationManager);
094 // In Xerces 2.4.0, XMLSchemaValidator uses ENTITY_MANAGER when
095 // it should use ENTITY_RESOLVER
096
097 // George: comment out the next line, otherwise
098 // with newwe versions of Xerces we got a CCE if I remember right...
099
100 setProperty(Properties.ENTITY_MANAGER, entityManager);
101
102 setProperty(Properties.ENTITY_RESOLVER, this);
103 reset();
104 }
105
106 public void reset() {
107 validationManager.reset();
108 namespaceContext.reset();
109 for (int i = 0; i < components.length; i++)
110 components[i].reset(this);
111 validationManager.setEntityState(this);
112 }
113
114 public ContentHandler getContentHandler() {
115 return this;
116 }
117
118 public DTDHandler getDTDHandler() {
119 return this;
120 }
121
122 public void setDocumentLocator(Locator locator) {
123 this.locator = locator;
124 }
125
126 public void notationDecl(String name,
127 String publicId,
128 String systemId) {
129 // nothing needed
130 }
131
132 public void unparsedEntityDecl(String name,
133 String publicId,
134 String systemId,
135 String notationName) {
136 entityTable.put(name, name);
137 }
138
139 public boolean isEntityDeclared(String name) {
140 return entityTable.get(name) != null;
141 }
142
143 public boolean isEntityUnparsed(String name) {
144 return entityTable.get(name) != null;
145 }
146
147 public void startDocument()
148 throws SAXException {
149 try {
150 schemaValidator.startDocument(locator == null ? null : this, null, namespaceContext, null);
151 }
152 catch (XNIException e) {
153 throw toSAXException(e);
154 }
155 }
156
157 public void endDocument()
158 throws SAXException {
159 try {
160 schemaValidator.endDocument(null);
161 }
162 catch (XNIException e) {
163 throw toSAXException(e);
164 }
165 }
166
167 public void startElement(String namespaceURI, String localName,
168 String qName, Attributes atts)
169 throws SAXException {
170 try {
171 if (!pushedContext)
172 namespaceContext.pushContext();
173 else
174 pushedContext = false;
175 for (int i = 0, len = atts.getLength(); i < len; i++)
176 attributes.addAttribute(makeQName(atts.getURI(i), atts.getLocalName(i), atts.getQName(i)),
177 symbolTable.addSymbol(atts.getType(i)),
178 atts.getValue(i));
179 schemaValidator.startElement(makeQName(namespaceURI, localName, qName), attributes, null);
180 attributes.removeAllAttributes();
181 }
182 catch (XNIException e) {
183 throw toSAXException(e);
184 }
185 }
186
187 public void endElement(String namespaceURI, String localName,
188 String qName)
189 throws SAXException {
190 try {
191 schemaValidator.endElement(makeQName(namespaceURI, localName, qName), null);
192 namespaceContext.popContext();
193 }
194 catch (XNIException e) {
195 throw toSAXException(e);
196 }
197 }
198
199 public void startPrefixMapping(String prefix, String uri)
200 throws SAXException {
201 try {
202 if (!pushedContext) {
203 namespaceContext.pushContext();
204 pushedContext = true;
205 }
206 if (prefix == null)
207 prefix = XMLSymbols.EMPTY_STRING;
208 else
209 prefix = symbolTable.addSymbol(prefix);
210 if (uri != null) {
211 if (uri.equals(""))
212 uri = null;
213 else
214 uri = symbolTable.addSymbol(uri);
215 }
216 namespaceContext.declarePrefix(prefix, uri);
217 }
218 catch (XNIException e) {
219 throw toSAXException(e);
220 }
221 }
222
223 public void endPrefixMapping(String prefix)
224 throws SAXException {
225 // do nothing
226 }
227
228 public void characters(char ch[], int start, int length)
229 throws SAXException {
230 try {
231 schemaValidator.characters(new XMLString(ch, start, length), null);
232 }
233 catch (XNIException e) {
234 throw toSAXException(e);
235 }
236 }
237
238 public void ignorableWhitespace(char ch[], int start, int length)
239 throws SAXException {
240 try {
241 schemaValidator.ignorableWhitespace(new XMLString(ch, start, length), null);
242 }
243 catch (XNIException e) {
244 throw toSAXException(e);
245 }
246 }
247
248 public void processingInstruction(String target, String data)
249 throws SAXException {
250 // do nothing
251 }
252
253 public void skippedEntity(String name)
254 throws SAXException {
255 // do nothing
256 }
257
258 private QName makeQName(String namespaceURI, String localName, String qName) {
259 localName = symbolTable.addSymbol(localName);
260 String prefix;
261 if (namespaceURI.equals("")) {
262 namespaceURI = null;
263 prefix = XMLSymbols.EMPTY_STRING;
264 qName = localName;
265 }
266 else {
267 namespaceURI = symbolTable.addSymbol(namespaceURI);
268 if (qName.equals("")) {
269 prefix = namespaceContext.getPrefix(namespaceURI);
270 if (prefix == XMLSymbols.EMPTY_STRING)
271 qName = localName;
272 else if (prefix == null)
273 qName = localName; // JC what to do?
274 else
275 qName = symbolTable.addSymbol(prefix + ":" + localName);
276 }
277 else {
278 qName = symbolTable.addSymbol(qName);
279 int colon = qName.indexOf(':');
280 if (colon > 0)
281 prefix = symbolTable.addSymbol(qName.substring(0, colon));
282 else
283 prefix = XMLSymbols.EMPTY_STRING;
284 }
285 }
286 return new QName(prefix, localName, qName, namespaceURI);
287 }
288
289 public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
290 throws XNIException, IOException {
291 return null;
292 }
293
294 public String getPublicId() {
295 return locator.getPublicId();
296 }
297
298 public String getEncoding() {
299 return null;
300 }
301
302 public String getBaseSystemId() {
303 return null;
304 }
305
306 public String getLiteralSystemId() {
307 return null;
308 }
309
310 public String getExpandedSystemId() {
311 return locator.getSystemId();
312 }
313
314 public int getLineNumber() {
315 return locator.getLineNumber();
316 }
317
318 public int getColumnNumber() {
319 return locator.getColumnNumber();
320 }
321
322 static SAXException toSAXException(XNIException e) {
323 if (e instanceof XMLParseException) {
324 XMLParseException pe = (XMLParseException)e;
325 return new SAXParseException(pe.getMessage(),
326 pe.getPublicId(),
327 pe.getExpandedSystemId(),
328 pe.getLineNumber(),
329 pe.getColumnNumber(),
330 pe.getException());
331 }
332 Exception nested = e.getException();
333 if (nested == null)
334 return new SAXException(e.getMessage());
335 if (nested instanceof SAXException)
336 return (SAXException)nested;
337 if (nested instanceof RuntimeException)
338 throw (RuntimeException)nested;
339 return new SAXException(nested);
340 }
341
342 /**
343 * This is needed by the Xerces 2.7.0 - we do not include it yet
344 * as it is not yet released but made an integration from CVS some
345 * time ago. When reverting to 2.6.2 the method remained here as we
346 * will neet it when we will get back to 2.7.0.
347 *
348 * @see org.apache.xerces.xni.XMLLocator#getCharacterOffset()
349 */
350 public int getCharacterOffset() {
351 return 0;
352 }
353
354 /**
355 * This is needed by the Xerces 2.7.0 - we do not include it yet
356 * as it is not yet released but made an integration from CVS some
357 * time ago. When reverting to 2.6.2 the method remained here as we
358 * will neet it when we will get back to 2.7.0.
359 *
360 * @see org.apache.xerces.xni.XMLLocator#getXMLVersion()
361 */
362 public String getXMLVersion() {
363 return "1.0";
364 }
365 }