001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2004 TOPP - www.openplans.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * Created on Jun 25, 2004
018: */
019: package org.geotools.validation;
020:
021: import java.io.IOException;
022: import java.util.HashMap;
023: import java.util.HashSet;
024: import java.util.Iterator;
025: import java.util.Map;
026: import java.util.Set;
027: import java.util.TreeMap;
028: import java.util.logging.Logger;
029:
030: import org.geotools.data.DataSourceException;
031: import org.geotools.feature.FeatureIterator;
032: import org.geotools.data.FeatureSource;
033: import org.geotools.data.Repository;
034: import org.geotools.feature.Feature;
035: import org.geotools.feature.FeatureCollection;
036: import org.geotools.feature.FeatureType;
037:
038: import com.vividsolutions.jts.geom.Envelope;
039:
040: /**
041: * Validator<br>
042: * @author bowens<br>
043: * Created Jun 25, 2004<br>
044: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/validation/src/main/java/org/geotools/validation/Validator.java $
045: * @version <br>
046: *
047: * <b>Puropse:</b><br>
048: * <p>
049: * Provides access to feature validation and integrity validation.<br>
050: *
051: *
052: * </p>
053: *
054: * <b>Description:</b><br>
055: * <p>
056: * Feature validation will iterate over a feature features and test all features
057: * that have a validation test specific to them in the validation processor
058: * passed in.<br>
059: *
060: * Integrity validation will iterate over all data stores passed in through the
061: * stores map and run the tests associated with each store.
062: * </p>
063: *
064: * <b>Usage:</b><br>
065: * <p>
066: * DOCUMENT ME!!
067: * </p>
068: */
069: public class Validator {
070: /** Standard logging instance for class */
071: private static final Logger LOGGER = org.geotools.util.logging.Logging
072: .getLogger("org.vfny.geoserver.responses");
073:
074: private ValidationProcessor validationProcessor;
075:
076: private Repository repository;
077:
078: /**
079: * Validator Constructor
080: *
081: */
082: public Validator(Repository repository,
083: ValidationProcessor processor) {
084: this .repository = repository;
085: validationProcessor = processor;//new ValidationProcessor();
086: }
087:
088: /**
089: * <b>featureValidation Purpose:</b> <br>
090: * <p>
091: * DOCUMENT ME!!
092: * </p>
093: *
094: * <b>Description:</b><br>
095: * <p>
096: * Feature validation will iterate over a feature features and test all features
097: * that have a validation test specific to them in the validation processor
098: * passed in.
099: * </p>
100: *
101: * Author: bowens<br>
102: * Created on: Jun 25, 2004<br>
103: * @param dsid
104: * @param features
105: * @throws IOException
106: * @throws Exception
107: */
108: public void featureValidation(String dsid,
109: FeatureCollection features, ValidationResults results)
110: throws IOException, Exception//, WfsTransactionException
111: {
112: //LOGGER.finer("FeatureValidation called on "+dsid+":"+type.getTypeName() );
113:
114: if (validationProcessor == null) {
115: LOGGER.warning("ValidationProcessor unavailable");
116: return;
117: }
118:
119: FeatureType type = features.getFeatureType();
120:
121: final Map failed = new TreeMap();
122:
123: /** Set up our validation results */
124: try {
125: validationProcessor
126: .runFeatureTests(dsid, features, results);
127: } catch (Exception badIdea) {
128: // ValidationResults should have handled stuff, will redesign :-)
129: throw new DataSourceException("Validation Failed", badIdea);
130: }
131: }
132:
133: /**
134: * <b>getFeatureValidationResults Purpose:</b> <br>
135: * <p>
136: * DOCUMENT ME!!
137: * </p>
138: *
139: * <b>Description:</b><br>
140: * <p>
141: * DOCUMENT ME!!
142: * </p>
143: *
144: * Author: bowens<br>
145: * Created on: Jun 26, 2004<br>
146: * @param failed
147: */
148: private ValidationResults makeFeatureValidationResults(
149: final Map failed) {
150: ValidationResults results = new ValidationResults() {
151: String name;
152: String description;
153:
154: public void setValidation(Validation validation) {
155: name = validation.getName();
156: description = validation.getDescription();
157: }
158:
159: public void error(Feature feature, String message) {
160: LOGGER.warning(name + ": " + message + " ("
161: + description + ")");
162: failed.put(feature.getID(), name + ": " + message + " "
163: + "(" + description + ")");
164: }
165:
166: public void warning(Feature feature, String message) {
167: LOGGER.warning(name + ": " + message + " ("
168: + description + ")");
169: }
170: };
171: return results;
172: }
173:
174: /**
175: * <b>integrityValidation Purpose:</b> <br>
176: * <p>
177: * DOCUMENT ME!!
178: * </p>
179: *
180: * <b>Description:</b><br>
181: * <p>
182: * Integrity validation will iterate over all data stores passed in through the
183: * stores map and run the tests associated with each store.
184: * </p>
185: *
186: * Author: bowens<br>
187: * Created on: Jun 26, 2004<br>
188: * @param featureStores Map of required FeatureStores by typeRef (dataStoreId:typeName)
189: * @param bBox
190: * @throws IOException
191: * @throws Exception
192: */
193: public void integrityValidation(Map featureStores, Envelope bBox,
194: ValidationResults results) throws IOException, Exception// WfsTransactionException
195: {
196: //Data catalog = request.getWFS().getData();
197: //ValidationProcessor validation = request.getValidationProcessor();
198: if (validationProcessor == null) {
199: LOGGER.warning("Validation Processor unavaialble");
200: return;
201: }
202: LOGGER.finer("Required to validate " + featureStores.size()
203: + " typeRefs");
204: LOGGER.finer("within " + bBox);
205:
206: // go through each typeName passed in through stores
207: // and ask what we need to check
208: Set typeRefs = new HashSet();
209: for (Iterator i = featureStores.keySet().iterator(); i
210: .hasNext();) {
211: String typeRef = (String) i.next();
212: typeRefs.add(typeRef);
213:
214: Set dependencies = validationProcessor
215: .getDependencies(typeRef);
216: LOGGER.finer("typeRef " + typeRef + " requires "
217: + dependencies);
218: if (dependencies != null && dependencies.size() > 0)
219: typeRefs.addAll(dependencies);
220: }
221:
222: // Grab a source for each typeName we need to check
223: // Grab from the provided stores - so we check against
224: // the transaction
225: //
226: Map sources = new HashMap();
227:
228: for (Iterator i = typeRefs.iterator(); i.hasNext();) {
229: String typeRef = (String) i.next();
230: LOGGER.finer("Searching for required typeRef: " + typeRef);
231:
232: /** This checks to see if we have already loaded in any feature stores.
233: * They can be loaded already if we are in a transaction operation. If
234: * this is for the "do it" button, there will be no feature stores
235: * already loaded and thus we always hit the 'else' statement.*/
236: if (featureStores.containsKey(typeRef)) // if it was passed in through stores
237: {
238: LOGGER.finer(" found required typeRef: " + typeRef
239: + " (it was already loaded)");
240: sources.put(typeRef, featureStores.get(typeRef));
241: } else // if we have to go get it (ie. it is a dependant for a test)
242: {
243: // These will be using Transaction.AUTO_COMMIT
244: // this is okay as they were not involved in our
245: // Transaction...
246: LOGGER.finer(" could not find typeRef: " + typeRef
247: + " (we will now load it)");
248: String split[] = typeRef.split(":");
249: String dataStoreId = split[0];
250: String typeName = split[1];
251: LOGGER.finer(" going to look for dataStoreId:"
252: + dataStoreId + " and typeName:" + typeName);
253:
254: // FeatureTypeInfo meta = catalog.getFeatureTypeInfo(typeName);
255: LOGGER.finer(" loaded required typeRef: " + typeRef);
256: FeatureSource source = repository.source(dataStoreId,
257: typeName);
258: sources.put(typeRef, source);
259: }
260: }
261: LOGGER.finer("Total of " + sources.size()
262: + " featureSource marshalled for testing");
263: final Map failed = new TreeMap();
264:
265: try {
266: //should never be null, but confDemo is giving grief, and I
267: //don't want transactions to mess up just because validation
268: //stuff is messed up. ch
269: LOGGER
270: .finer("Runing integrity tests using validation validationProcessor ");
271: validationProcessor.runIntegrityTests(featureStores
272: .keySet(), sources, bBox, results);
273: } catch (Exception badIdea) {
274: badIdea.printStackTrace();
275: // ValidationResults should of handled stuff will redesign :-)
276: throw new DataSourceException("Validation Failed", badIdea);
277: }
278: if (failed.isEmpty()) {
279: LOGGER.finer("All validation tests passed");
280: return; // everything worked out
281: }
282:
283: /** One or more of the tests failed if we reached here, so dump out
284: * the information from teh tests that failed. */
285: LOGGER
286: .finer("Validation fail - marshal result for transaction document");
287: StringBuffer message = new StringBuffer();
288: for (Iterator i = failed.entrySet().iterator(); i.hasNext();) {
289: Map.Entry entry = (Map.Entry) i.next();
290: message.append(entry.getKey());
291: message.append(" failed test ");
292: message.append(entry.getValue());
293: message.append("\n");
294: }
295: //throw new Exception("Validation - " + message.toString());
296: //throw new WfsTransactionException(message.toString(), "validation");
297: }
298:
299: /**
300: * <b>getIntegrityValidationResults Purpose:</b> <br>
301: * <p>
302: * Gets the validation results for Integrity tests.
303: * </p>
304: *
305: * <b>Description:</b><br>
306: * <p>
307: * DOCUMENT ME!!
308: * </p>
309: *
310: * Author: bowens<br>
311: * Created on: Jun 26, 2004<br>
312: * @param failed the map of failed features
313: */
314: private ValidationResults makeIntegrityValidationResults(
315: final Map failed) {
316: ValidationResults results = new ValidationResults() {
317: String name;
318: String description;
319:
320: public void setValidation(Validation validation) {
321: name = validation.getName();
322: description = validation.getDescription();
323: }
324:
325: public void error(Feature feature, String message) {
326: LOGGER.warning(name + ": " + message + " ("
327: + description + ")");
328: if (feature == null) {
329: failed.put("ALL", name + ": " + message + " " + "("
330: + description + ")");
331: } else {
332: failed.put(feature.getID(), name + ": " + message
333: + " " + "(" + description + ")");
334: }
335: }
336:
337: public void warning(Feature feature, String message) {
338: LOGGER.warning(name + ": " + message + " ("
339: + description + ")");
340: }
341: };
342: return results;
343: }
344:
345: }
|