KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > SchemaValidate


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18 package org.apache.tools.ant.taskdefs.optional;
19
20 import org.apache.tools.ant.BuildException;
21 import org.apache.tools.ant.Project;
22 import org.apache.tools.ant.util.FileUtils;
23 import org.apache.tools.ant.util.XmlConstants;
24 import org.xml.sax.XMLReader JavaDoc;
25 import org.xml.sax.SAXNotRecognizedException JavaDoc;
26 import org.xml.sax.SAXNotSupportedException JavaDoc;
27 import org.xml.sax.SAXException JavaDoc;
28
29 import javax.xml.parsers.SAXParserFactory JavaDoc;
30 import javax.xml.parsers.SAXParser JavaDoc;
31 import javax.xml.parsers.ParserConfigurationException JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.io.File JavaDoc;
35 import java.net.MalformedURLException JavaDoc;
36
37 /**
38  * Validate XML Schema documents.
39  * This task validates XML schema documents. It requires an XML parser
40  * that handles the relevant SAx, Xerces or JAXP options.
41  *
42  * To resolve remote referencies, Ant may need its proxy set up, using the
43  * setproxy task.
44  *
45  * Hands off most of the work to its parent, {@link XMLValidateTask}
46  * @since Ant1.7
47  */

48
49 public class SchemaValidate extends XMLValidateTask {
50
51     /** map of all declared schemas; we catch and complain about redefinitions */
52     private HashMap JavaDoc schemaLocations = new HashMap JavaDoc();
53
54     /** full checking of a schema */
55     private boolean fullChecking = true;
56
57     /**
58      * flag to disable DTD support. Best left enabled.
59      */

60     private boolean disableDTD = false;
61
62     /**
63      * default URL for nonamespace schemas
64      */

65     private SchemaLocation anonymousSchema;
66
67     // Error strings
68
/** SAX1 not supported */
69     public static final String JavaDoc ERROR_SAX_1 = "SAX1 parsers are not supported";
70
71     /** schema features not supported */
72     public static final String JavaDoc ERROR_NO_XSD_SUPPORT
73         = "Parser does not support Xerces or JAXP schema features";
74
75     /** too many default schemas */
76     public static final String JavaDoc ERROR_TOO_MANY_DEFAULT_SCHEMAS
77         = "Only one of defaultSchemaFile and defaultSchemaURL allowed";
78
79     /** unable to create parser */
80     public static final String JavaDoc ERROR_PARSER_CREATION_FAILURE
81         = "Could not create parser";
82
83     /** adding schema */
84     public static final String JavaDoc MESSAGE_ADDING_SCHEMA = "Adding schema ";
85
86     /** Duplicate declaration of schema */
87     public static final String JavaDoc ERROR_DUPLICATE_SCHEMA
88         = "Duplicate declaration of schema ";
89
90     /**
91      * Called by the project to let the task initialize properly. The default
92      * implementation is a no-op.
93      *
94      * @throws BuildException if something goes wrong with the build
95      */

96     public void init() throws BuildException {
97         super.init();
98         //validating
99
setLenient(false);
100     }
101
102     /**
103      * Turn on XSD support in Xerces.
104      * @return true on success, false on failure
105      */

106     public boolean enableXercesSchemaValidation() {
107         try {
108             setFeature(XmlConstants.FEATURE_XSD, true);
109             //set the schema source for the doc
110
setNoNamespaceSchemaProperty(XmlConstants.PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION);
111         } catch (BuildException e) {
112             log(e.toString(), Project.MSG_VERBOSE);
113             return false;
114         }
115         return true;
116     }
117
118     /**
119      * set nonamespace handling up for xerces or other parsers
120      * @param property name of the property to set
121      */

122     private void setNoNamespaceSchemaProperty(String JavaDoc property) {
123         String JavaDoc anonSchema = getNoNamespaceSchemaURL();
124         if (anonSchema != null) {
125             setProperty(property, anonSchema);
126         }
127     }
128
129     /**
130      * Set schema attributes in a JAXP 1.2 engine.
131      * @see <A HREF="http://java.sun.com/xml/jaxp/change-requests-11.html">
132      * JAXP 1.2 Approved CHANGES</A>
133      * @return true on success, false on failure
134      */

135     public boolean enableJAXP12SchemaValidation() {
136         try {
137             //enable XSD
138
setProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_LANGUAGE, XmlConstants.URI_XSD);
139             //set the schema source for the doc
140
setNoNamespaceSchemaProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_SOURCE);
141         } catch (BuildException e) {
142             log(e.toString(), Project.MSG_VERBOSE);
143             return false;
144         }
145         return true;
146     }
147
148     /**
149      * add the schema
150      * @param location the schema location.
151      * @throws BuildException if there is no namespace, or if there already
152      * is a declaration of this schema with a different value
153      */

154     public void addConfiguredSchema(SchemaLocation location) {
155         log("adding schema " + location, Project.MSG_DEBUG);
156         location.validateNamespace();
157         SchemaLocation old = (SchemaLocation) schemaLocations.get(location.getNamespace());
158         if (old != null && !old.equals(location)) {
159             throw new BuildException(ERROR_DUPLICATE_SCHEMA + location);
160         }
161         schemaLocations.put(location.getNamespace(), location);
162     }
163
164     /**
165      * enable full schema checking. Slower but better.
166      * @param fullChecking a <code>boolean</code> value.
167      */

168     public void setFullChecking(boolean fullChecking) {
169         this.fullChecking = fullChecking;
170     }
171
172     /**
173      * create a schema location to hold the anonymous
174      * schema
175      */

176     protected void createAnonymousSchema() {
177         if (anonymousSchema == null) {
178             anonymousSchema = new SchemaLocation();
179         }
180         anonymousSchema.setNamespace("(no namespace)");
181     }
182
183     /**
184      * identify the URL of the default schema
185      * @param defaultSchemaURL the URL of the default schema.
186      */

187     public void setNoNamespaceURL(String JavaDoc defaultSchemaURL) {
188         createAnonymousSchema();
189         this.anonymousSchema.setUrl(defaultSchemaURL);
190     }
191
192     /**
193      * identify a file containing the default schema
194      * @param defaultSchemaFile the location of the default schema.
195      */

196     public void setNoNamespaceFile(File JavaDoc defaultSchemaFile) {
197         createAnonymousSchema();
198         this.anonymousSchema.setFile(defaultSchemaFile);
199     }
200
201     /**
202      * flag to disable DTD support.
203      * @param disableDTD a <code>boolean</code> value.
204      */

205     public void setDisableDTD(boolean disableDTD) {
206         this.disableDTD = disableDTD;
207     }
208
209     /**
210      * init the parser : load the parser class, and set features if necessary It
211      * is only after this that the reader is valid
212      *
213      * @throws BuildException if something went wrong
214      */

215     protected void initValidator() {
216         super.initValidator();
217         //validate the parser type
218
if (isSax1Parser()) {
219             throw new BuildException(ERROR_SAX_1);
220         }
221
222         //enable schema
223
//setFeature(XmlConstants.FEATURE_VALIDATION, false);
224
setFeature(XmlConstants.FEATURE_NAMESPACES, true);
225         if (!enableXercesSchemaValidation() && !enableJAXP12SchemaValidation()) {
226             //couldnt use the xerces or jaxp calls
227
throw new BuildException(ERROR_NO_XSD_SUPPORT);
228         }
229
230         //enable schema checking
231
setFeature(XmlConstants.FEATURE_XSD_FULL_VALIDATION, fullChecking);
232
233         //turn off DTDs if desired
234
setFeatureIfSupported(XmlConstants.FEATURE_DISALLOW_DTD, disableDTD);
235
236         //schema declarations go in next
237
addSchemaLocations();
238     }
239
240     /**
241      * Create a reader if the use of the class did not specify another one.
242      * The reason to not use {@link JAXPUtils#getXMLReader()} was to
243      * create our own factory with our own options.
244      * @return a default XML parser
245      */

246     protected XMLReader JavaDoc createDefaultReader() {
247         SAXParserFactory JavaDoc factory = SAXParserFactory.newInstance();
248         factory.setValidating(true);
249         factory.setNamespaceAware(true);
250         XMLReader JavaDoc reader = null;
251         try {
252             SAXParser JavaDoc saxParser = factory.newSAXParser();
253             reader = saxParser.getXMLReader();
254         } catch (ParserConfigurationException JavaDoc e) {
255             throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
256         } catch (SAXException JavaDoc e) {
257             throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
258         }
259         return reader;
260     }
261
262     /**
263      * build a string list of all schema locations, then set the relevant
264      * property.
265      */

266     protected void addSchemaLocations() {
267         Iterator JavaDoc it = schemaLocations.values().iterator();
268         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
269         int count = 0;
270         while (it.hasNext()) {
271             if (count > 0) {
272                 buffer.append(' ');
273             }
274             SchemaLocation schemaLocation = (SchemaLocation) it.next();
275             String JavaDoc tuple = schemaLocation.getURIandLocation();
276             buffer.append(tuple);
277             log("Adding schema " + tuple, Project.MSG_VERBOSE);
278             count++;
279         }
280         if (count > 0) {
281             setProperty(XmlConstants.PROPERTY_SCHEMA_LOCATION, buffer.toString());
282         }
283
284     }
285
286     /**
287      * get the URL of the no namespace schema
288      * @return the schema URL
289      */

290     protected String JavaDoc getNoNamespaceSchemaURL() {
291         if (anonymousSchema == null) {
292             return null;
293         } else {
294             return anonymousSchema.getSchemaLocationURL();
295         }
296     }
297
298     /**
299      * set a feature if it is supported, log at verbose level if
300      * not
301      * @param feature the feature.
302      * @param value a <code>boolean</code> value.
303      */

304     protected void setFeatureIfSupported(String JavaDoc feature, boolean value) {
305         try {
306             getXmlReader().setFeature(feature, value);
307         } catch (SAXNotRecognizedException JavaDoc e) {
308             log("Not recognizied: " + feature, Project.MSG_VERBOSE);
309         } catch (SAXNotSupportedException JavaDoc e) {
310             log("Not supported: " + feature, Project.MSG_VERBOSE);
311         }
312     }
313
314     /**
315      * handler called on successful file validation.
316      *
317      * @param fileProcessed number of files processed.
318      */

319     protected void onSuccessfulValidation(int fileProcessed) {
320         log(fileProcessed + MESSAGE_FILES_VALIDATED, Project.MSG_VERBOSE);
321     }
322
323     /**
324      * representation of a schema location. This is a URI plus either a file or
325      * a url
326      */

327     public static class SchemaLocation {
328         private String JavaDoc namespace;
329
330         private File JavaDoc file;
331
332         private String JavaDoc url;
333
334         /** No namespace URI */
335         public static final String JavaDoc ERROR_NO_URI = "No namespace URI";
336
337         /** Both URL and File were given for schema */
338         public static final String JavaDoc ERROR_TWO_LOCATIONS
339             = "Both URL and File were given for schema ";
340
341         /** File not found */
342         public static final String JavaDoc ERROR_NO_FILE = "File not found: ";
343
344         /** Cannot make URL */
345         public static final String JavaDoc ERROR_NO_URL_REPRESENTATION
346             = "Cannot make a URL of ";
347
348         /** No location provided */
349         public static final String JavaDoc ERROR_NO_LOCATION
350             = "No file or URL supplied for the schema ";
351
352         /** No arg constructor */
353         public SchemaLocation() {
354         }
355
356         /**
357          * Get the namespace.
358          * @return the namespace.
359          */

360         public String JavaDoc getNamespace() {
361             return namespace;
362         }
363
364         /**
365          * set the namespace of this schema. Any URI
366          * @param namespace the namespace to use.
367          */

368         public void setNamespace(String JavaDoc namespace) {
369             this.namespace = namespace;
370         }
371
372         /**
373          * Get the file.
374          * @return the file containing the schema.
375          */

376         public File JavaDoc getFile() {
377             return file;
378         }
379
380         /**
381          * identify a file that contains this namespace's schema.
382          * The file must exist.
383          * @param file the file contains the schema.
384          */

385         public void setFile(File JavaDoc file) {
386             this.file = file;
387         }
388
389         /**
390          * The URL containing the schema.
391          * @return the URL string.
392          */

393         public String JavaDoc getUrl() {
394             return url;
395         }
396
397         /**
398          * identify a URL that hosts the schema.
399          * @param url the URL string.
400          */

401         public void setUrl(String JavaDoc url) {
402             this.url = url;
403         }
404
405         /**
406          * get the URL of the schema
407          * @return a URL to the schema
408          * @throws BuildException if not
409          */

410         public String JavaDoc getSchemaLocationURL() {
411             boolean hasFile = file != null;
412             boolean hasURL = isSet(url);
413             //error if both are empty, or both are set
414
if (!hasFile && !hasURL) {
415                 throw new BuildException(ERROR_NO_LOCATION + namespace);
416             }
417             if (hasFile && hasURL) {
418                 throw new BuildException(ERROR_TWO_LOCATIONS + namespace);
419             }
420             String JavaDoc schema = url;
421             if (hasFile) {
422                 if (!file.exists()) {
423                     throw new BuildException(ERROR_NO_FILE + file);
424                 }
425
426                 try {
427                     schema = FileUtils.getFileUtils().getFileURL(file).toString();
428                 } catch (MalformedURLException JavaDoc e) {
429                     //this is almost implausible, but required handling
430
throw new BuildException(ERROR_NO_URL_REPRESENTATION + file, e);
431                 }
432             }
433             return schema;
434         }
435
436         /**
437          * validate the fields then create a "uri location" string
438          *
439          * @return string of uri and location
440          * @throws BuildException if there is an error.
441          */

442         public String JavaDoc getURIandLocation() throws BuildException {
443             validateNamespace();
444             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
445             buffer.append(namespace);
446             buffer.append(' ');
447             buffer.append(getSchemaLocationURL());
448             return new String JavaDoc(buffer);
449         }
450
451         /**
452          * assert that a namespace is valid
453          * @throws BuildException if not
454          */

455         public void validateNamespace() {
456             if (!isSet(getNamespace())) {
457                 throw new BuildException(ERROR_NO_URI);
458             }
459         }
460
461         /**
462          * check that a property is set
463          * @param property string to check
464          * @return true if it is not null or empty
465          */

466         private boolean isSet(String JavaDoc property) {
467             return property != null && property.length() != 0;
468         }
469
470         /**
471          * equality test checks namespace, location and filename. All must match,
472          * @param o object to compare against
473          * @return true iff the objects are considered equal in value
474          */

475
476         public boolean equals(Object JavaDoc o) {
477             if (this == o) {
478                 return true;
479             }
480             if (!(o instanceof SchemaLocation)) {
481                 return false;
482             }
483
484             final SchemaLocation schemaLocation = (SchemaLocation) o;
485
486             if (file != null ? !file.equals(schemaLocation.file) : schemaLocation.file != null) {
487                 return false;
488             }
489             if (namespace != null ? !namespace.equals(schemaLocation.namespace)
490                     : schemaLocation.namespace != null) {
491                 return false;
492             }
493             if (url != null ? !url.equals(schemaLocation.url) : schemaLocation.url != null) {
494                 return false;
495             }
496
497             return true;
498         }
499
500         /**
501          * Generate a hashcode depending on the namespace, url and file name.
502          * @return the hashcode.
503          */

504         public int hashCode() {
505             int result;
506             result = (namespace != null ? namespace.hashCode() : 0);
507             result = 29 * result + (file != null ? file.hashCode() : 0);
508             result = 29 * result + (url != null ? url.hashCode() : 0);
509             return result;
510         }
511
512         /**
513          * Returns a string representation of the object for error messages
514          * and the like
515          * @return a string representation of the object.
516          */

517         public String JavaDoc toString() {
518             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
519             buffer.append(namespace != null ? namespace : "(anonymous)");
520             buffer.append(' ');
521             buffer.append(url != null ? (url + " ") : "");
522             buffer.append(file != null ? file.getAbsolutePath() : "");
523             return buffer.toString();
524         }
525     } //SchemaLocation
526
}
527
Popular Tags