001: //$HeadURL: https://sushibar/svn/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $
002: /*---------------- FILE HEADER ------------------------------------------
003: This file is part of deegree.
004: Copyright (C) 2001-2007 by:
005: Department of Geography, University of Bonn
006: http://www.giub.uni-bonn.de/deegree/
007: lat/lon GmbH
008: http://www.lat-lon.de
009:
010: This library is free software; you can redistribute it and/or
011: modify it under the terms of the GNU Lesser General Public
012: License as published by the Free Software Foundation; either
013: version 2.1 of the License, or (at your option) any later version.
014: This library is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018: You should have received a copy of the GNU Lesser General Public
019: License along with this library; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: Contact:
022:
023: Andreas Poth
024: lat/lon GmbH
025: Aennchenstr. 19
026: 53177 Bonn
027: Germany
028: E-Mail: poth@lat-lon.de
029:
030: Prof. Dr. Klaus Greve
031: Department of Geography
032: University of Bonn
033: Meckenheimer Allee 166
034: 53115 Bonn
035: Germany
036: E-Mail: greve@giub.uni-bonn.de
037: ---------------------------------------------------------------------------*/
038:
039: package org.deegree.tools.xml;
040:
041: import static java.lang.System.out;
042: import static org.deegree.framework.log.LoggerFactory.getLogger;
043: import static org.deegree.framework.xml.DOMPrinter.nodeToString;
044: import static org.deegree.framework.xml.XMLTools.getNodes;
045: import static org.deegree.ogcbase.CommonNamespaces.getNamespaceContext;
046:
047: import java.io.BufferedReader;
048: import java.io.File;
049: import java.io.IOException;
050: import java.io.InputStreamReader;
051: import java.net.MalformedURLException;
052: import java.net.URL;
053: import java.util.LinkedList;
054: import java.util.List;
055: import java.util.StringTokenizer;
056:
057: import org.deegree.framework.log.ILogger;
058: import org.deegree.framework.util.StringPair;
059: import org.deegree.framework.xml.NamespaceContext;
060: import org.deegree.framework.xml.XMLFragment;
061: import org.deegree.framework.xml.XMLParsingException;
062: import org.w3c.dom.Node;
063: import org.xml.sax.SAXException;
064:
065: /**
066: * <code>SimpleValidator</code> is a simple xpath based "validator". It can be used to crudely
067: * check XML documents for existing nodes. The configuration/rules file looks like this:
068: *
069: * Simple rules:
070: *
071: * <pre>
072: * theid / WMT_MS_Capabilities
073: * </pre>
074: *
075: * This checks whether the XPath yields a node or not. Every rule has an ID by which it can be
076: * identified in case of a failure.
077: *
078: * Conditional rules look like this:
079: *
080: * <pre>
081: * theid2 if /WMT_MS_Capabilities/Capability
082: * then theid2_then /WMT_MS_Capabilities/Capability/Request
083: * </pre>
084: *
085: * So, the conditional rule itself has an ID. The test does not have an id, but the then clauses
086: * have, as they're just rules themselves.
087: *
088: * A more complex rule with a nested if then might look like this:
089: *
090: * <pre>
091: * 3 if /WMT_MS_Capabilities/Capability
092: * then 4 if Request then 5 GetMap
093: * </pre>
094: *
095: * Note that the follow-up-rules may be specified relatively.
096: *
097: * Comment lines start with #.
098: *
099: * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
100: * @author last edited by: $Author:$
101: *
102: * @version $Revision:$, $Date:$
103: */
104: public class SimpleValidator {
105:
106: static final NamespaceContext nsContext = getNamespaceContext();
107:
108: private static final ILogger LOG = getLogger(SimpleValidator.class);
109:
110: private LinkedList<Rule> rules;
111:
112: /**
113: * Initializes from configuration URL. File should be encoded in UTF-8.
114: *
115: * @param config
116: * @throws IOException
117: */
118: public SimpleValidator(URL config) throws IOException {
119: rules = new LinkedList<Rule>();
120:
121: BufferedReader in = new BufferedReader(new InputStreamReader(
122: config.openStream()));
123:
124: StringBuffer buf = new StringBuffer(65536);
125: String s;
126: while ((s = in.readLine()) != null) {
127: if (s.startsWith("#")) {
128: continue;
129: }
130: buf.append(s).append(" ");
131: }
132:
133: in.close();
134:
135: StringTokenizer tok = new StringTokenizer(buf.toString());
136: while (tok.hasMoreTokens()) {
137: rules.add(parseRule(tok));
138: }
139:
140: LOG.logDebug("Parsed rule file with " + rules.size()
141: + " rules.");
142: }
143:
144: private static Rule parseRule(StringTokenizer tok)
145: throws IOException {
146: String id = tok.nextToken();
147: String s = tok.nextToken();
148:
149: if (s.equals("if")) {
150: String test = tok.nextToken();
151: if (!tok.nextToken().equals("then")) {
152: throw new IOException("Missing 'then' after " + test
153: + ".");
154: }
155:
156: Rule then = parseRule(tok);
157:
158: return new Rule(id, test, then);
159: }
160:
161: return new Rule(id, s);
162: }
163:
164: /**
165: * @param n
166: * @return a list of errors. A pair will include the id of the failed rule, and the context node
167: * as string (if applicable) or null (if not).
168: */
169: public LinkedList<StringPair> validate(Node n) {
170: LinkedList<StringPair> list = new LinkedList<StringPair>();
171:
172: for (Rule r : rules) {
173: if (!r.eval(n)) {
174: list.addAll(r.errors);
175: }
176: }
177:
178: return list;
179: }
180:
181: /**
182: * @param args
183: */
184: public static void main(String[] args) {
185: if (args.length < 2) {
186: out.println("Usage:");
187: out
188: .println("org.deegree.tools.xml.SimpleValidator <rulesfile> <xmlfiletovalidate> [-v]");
189: return;
190: }
191:
192: boolean verbose = args.length > 2 && args[2].equals("-v");
193:
194: try {
195: XMLFragment doc = new XMLFragment(new File(args[1]));
196: SimpleValidator val = new SimpleValidator(new File(args[0])
197: .toURL());
198:
199: LinkedList<StringPair> errors = val.validate(doc
200: .getRootElement());
201: if (errors.size() > 0) {
202: out.println("Errors:");
203: for (StringPair p : errors) {
204: if (verbose) {
205: out.println(p);
206: } else {
207: out.print(p.first);
208: if (errors.indexOf(p) != errors.size() - 1) {
209: out.print(", ");
210: }
211: }
212: }
213: if (!verbose) {
214: out.println();
215: }
216: } else {
217: out.println("All rules passed.");
218: }
219: } catch (MalformedURLException e) {
220: out
221: .println("Error: one of the files is not a valid filename.");
222: out.println("Usage:");
223: out
224: .println("org.deegree.tools.xml.SimpleValidator <rulesfile> <xmlfiletovalidate> [-v]");
225: } catch (IOException e) {
226: out.println("Error: second file cannot be read.");
227: out.println("Usage:");
228: out
229: .println("org.deegree.tools.xml.SimpleValidator <rulesfile> <xmlfiletovalidate> [-v]");
230: } catch (SAXException e) {
231: out.println("Error: second file is not parsable XML.");
232: out.println("Usage:");
233: out
234: .println("org.deegree.tools.xml.SimpleValidator <rulesfile> <xmlfiletovalidate> [-v]");
235: }
236: }
237:
238: private static class Rule {
239:
240: String id;
241:
242: List<StringPair> errors;
243:
244: private String xpath;
245:
246: private Rule then;
247:
248: Rule(String id, String xpath) {
249: this .xpath = xpath;
250: this .id = id;
251: errors = new LinkedList<StringPair>();
252: }
253:
254: Rule(String id, String xpath, Rule then) {
255: this (id, xpath);
256: this .then = then;
257: }
258:
259: boolean eval(Node n) {
260: try {
261: List<Node> tmps = getNodes(n, xpath, nsContext);
262:
263: if (then == null) {
264: if (tmps.size() == 0) {
265: errors.add(new StringPair(id, null));
266: }
267: return tmps.size() != 0;
268: }
269:
270: if (tmps.size() == 0) {
271: return true;
272: }
273:
274: boolean res = true;
275:
276: for (Node tmp : tmps) {
277: if (then.eval(tmp)) {
278: continue;
279: }
280:
281: res = false;
282:
283: errors.add(new StringPair(then.id, nodeToString(
284: tmp, "UTF-8")));
285: }
286:
287: return res;
288: } catch (XMLParsingException e) {
289: return false;
290: }
291: }
292:
293: }
294:
295: }
|