//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/model/feature/Validator.java,v 1.5 2006/08/31 15:00:50 mschneider Exp $ /*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2006 by: Department of Geography, University of Bonn http://www.giub.uni-bonn.de/deegree/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstraße 19 53177 Bonn Germany E-Mail: poth@lat-lon.de Prof. Dr. Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.model.feature; import java.util.Date; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.deegree.datatypes.QualifiedName; import org.deegree.datatypes.Types; import org.deegree.datatypes.UnknownTypeException; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.TimeTools; import org.deegree.model.feature.schema.FeaturePropertyType; import org.deegree.model.feature.schema.FeatureType; import org.deegree.model.feature.schema.GeometryPropertyType; import org.deegree.model.feature.schema.MultiGeometryPropertyType; import org.deegree.model.feature.schema.PropertyType; import org.deegree.model.feature.schema.SimplePropertyType; import org.deegree.model.spatialschema.Geometry; import org.deegree.ogcwebservices.OGCWebServiceException; /** * Validator for feature instance (that have been constructed without schema information). * <p> * Validated features are assigned their respective feature types after succesful validation. * * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a> * @author last edited by: $Author: mschneider $ * * @version $Revision: 1.5 $, $Date: 2006/08/31 15:00:50 $ */ public class Validator { private static final ILogger LOG = LoggerFactory.getLogger( Validator.class ); private Set<Feature> inValidation = new HashSet<Feature> (); private Map<QualifiedName,FeatureType> ftMap; /** * Constructs a new instance of <code>Validator</code> that will use the given map to lookup * feature types by their names. * * @param ftMap */ public Validator( Map<QualifiedName, FeatureType> ftMap ) { this.ftMap = ftMap; } /** * Validates the given feature instance (and it's subfeatures). * <p> * The feature instance is then given the corresponding <code>FeatureType</code>. This * also applies for it's subfeatures. * * @param feature * feature instance to be validated * @throws OGCWebServiceException */ public void validate ( Feature feature ) throws OGCWebServiceException { if (inValidation.contains(feature)) { return; } inValidation.add (feature); QualifiedName ftName = feature.getName(); FeatureType ft = this.ftMap.get( ftName ); if ( ft == null ) { String msg = Messages.format("ERROR_FT_UNKNOWN", ftName); throw new OGCWebServiceException( this.getClass().getName(), msg ); } int idx = 0; FeatureProperty [] properties = feature.getProperties(); PropertyType [] propertyTypes = ft.getProperties(); for (int i = 0; i < propertyTypes.length; i++) { idx += validateProperties (ftName, propertyTypes [i], properties, idx); } if (idx != properties.length) { String msg = Messages.format ("ERROR_FT_INVALID1", ftName, properties[idx].getName()); throw new OGCWebServiceException( this.getClass().getName(), msg ); } feature.setFeatureType (ft); } /** * Validates that there is the correct amount of properties with the expected type in the given * array of properties. * * @param ftName * @param propertyType * @param properties * @param idx * @throws OGCWebServiceException */ private int validateProperties( QualifiedName ftName, PropertyType propertyType, FeatureProperty[] properties, int idx ) throws OGCWebServiceException { int minOccurs = propertyType.getMinOccurs(); int maxOccurs = propertyType.getMaxOccurs(); QualifiedName propertyName = propertyType.getName(); int count = 0; while (idx + count < properties.length) { if ( properties[idx + count].getName().equals( propertyName ) ) { validate( properties[idx + count], propertyType ); count++; } else { break; } } if ( count < minOccurs ) { if (count == 0) { String msg = Messages.format ("ERROR_FT_INVALID2", ftName, propertyName); throw new OGCWebServiceException( this.getClass().getName(), msg); } String msg = Messages.format( "ERROR_FT_INVALID3", new Object[] { ftName, propertyName, minOccurs, count } ); throw new OGCWebServiceException( this.getClass().getName(), msg); } if ( maxOccurs != -1 && count > maxOccurs ) { String msg = Messages.format( "ERROR_FT_INVALID4", new Object[] { ftName, propertyName, maxOccurs, count } ); throw new OGCWebServiceException( this.getClass().getName(), msg); } return count; } /** * Validates that there is the correct amount of properties with the expected type in the given * array of properties. * * @param ftName * @param propertyType * @param properties * @param idx * @throws OGCWebServiceException */ private void validate( FeatureProperty property, PropertyType propertyType ) throws OGCWebServiceException { Object value = property.getValue(); if ( propertyType instanceof SimplePropertyType ) { String s = value.toString(); if (value instanceof Date) { s = TimeTools.getISOFormattedTime((Date) value); } Object newValue = validateSimpleProperty( (SimplePropertyType) propertyType, s ); property.setValue( newValue ); } else if ( propertyType instanceof GeometryPropertyType ) { if (!(value instanceof Geometry)) { String msg = Messages.format( "ERROR_WRONG_PROPERTY_TYPE", propertyType.getName(), "GeometryProperty", value.getClass().getName() ); throw new OGCWebServiceException( this.getClass().getName(), msg ); } } else if ( propertyType instanceof FeaturePropertyType ) { if (!(value instanceof Feature)) { String msg = Messages.format( "ERROR_WRONG_PROPERTY_TYPE", propertyType.getName(), "FeatureProperty", value.getClass().getName() ); throw new OGCWebServiceException( this.getClass().getName(), msg ); } Feature feature = (Feature) value; //FeaturePropertyContent content = (FeaturePropertyContent) propertyType.getContents() [0]; //MappedFeatureType contentFT = content.getFeatureTypeReference().getFeatureType(); // TODO: check that feature is a correct subsitution for the expected featuretype validate( feature ); } else if ( propertyType instanceof MultiGeometryPropertyType ) { throw new OGCWebServiceException( "Handling of MultiGeometryPropertyTypes not implemented " + "in validateProperty()." ); } else { throw new OGCWebServiceException( "Internal error: Unhandled property type '" + propertyType.getClass() + "' encountered while validating property." ); } } /** * * @param propertyType * @param s * @return * @throws OGCWebServiceException */ private Object validateSimpleProperty( SimplePropertyType propertyType, String s ) throws OGCWebServiceException { int type = propertyType.getType(); QualifiedName propertyName = propertyType.getName(); Object value = null; if ( type == Types.NUMERIC || type == Types.DOUBLE ) { try { value = new Double( s ); } catch (NumberFormatException e) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Double" ); throw new OGCWebServiceException( msg ); } } else if ( type == Types.INTEGER ) { try { value = new Integer( s ); } catch (NumberFormatException e) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Integer" ); throw new OGCWebServiceException( msg ); } } else if ( type == Types.DECIMAL || type == Types.FLOAT ) { try { value = new Float( s ); } catch (NumberFormatException e) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Float" ); throw new OGCWebServiceException( msg ); } } else if ( type == Types.BOOLEAN ) { value = new Boolean( s ); } else if ( type == Types.VARCHAR ) { value = s; } else if ( type == Types.DATE || type == Types.TIMESTAMP) { try { value = TimeTools.createCalendar( s ).getTime(); } catch (NumberFormatException e) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Date" ); throw new OGCWebServiceException( msg ); } } else { String typeString = "" + type; try { typeString = Types.getTypeNameForSQLTypeCode(type); } catch (UnknownTypeException e) { LOG.logError ("No type name for code: " + type); } String msg = Messages.format( "ERROR_UNHANDLED_TYPE", "" + typeString ); LOG.logError( msg ); throw new OGCWebServiceException( msg ); } return value; } } /* ******************************************************************** Changes to this class. What the people have been up to: $Log: Validator.java,v $ Revision 1.5 2006/08/31 15:00:50 mschneider Javadoc fixes. Revision 1.4 2006/08/21 15:47:59 mschneider Refactored due to cleanup (and splitting) of org.deegree.io.datastore.schema package. Revision 1.3 2006/08/07 06:35:09 poth unneccessary else block removed Revision 1.2 2006/05/23 16:07:59 mschneider Improved javadoc. Revision 1.1 2006/04/10 16:38:52 mschneider Initial version. ********************************************************************** */