001 //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/io/datastore/FeatureId.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 037 package org.deegree.io.datastore; 038 039 import org.deegree.datatypes.Types; 040 import org.deegree.datatypes.UnknownTypeException; 041 import org.deegree.i18n.Messages; 042 import org.deegree.io.datastore.idgenerator.IdGenerationException; 043 import org.deegree.io.datastore.schema.MappedFeatureType; 044 import org.deegree.io.datastore.schema.MappedGMLId; 045 import org.deegree.io.datastore.schema.content.MappingField; 046 047 /** 048 * Used to identify persistent (stored) feature instances. 049 * 050 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a> 051 * @author last edited by: $Author: apoth $ 052 * 053 * @version $Revision: 29953 $, $Date: 2011-03-09 13:15:46 +0100 (Wed, 09 Mar 2011) $ 054 */ 055 public class FeatureId implements Comparable<FeatureId> { 056 057 private MappedFeatureType ft; 058 059 private MappedGMLId fidDefinition; 060 061 private Object[] values; 062 063 /** 064 * Creates a new instance of <code>FeatureId</code> from the given parameters. 065 * 066 * @param ft 067 * cannot be null, must not be an abstract feature type 068 * @param values 069 * cannot be null or empty 070 */ 071 public FeatureId( MappedFeatureType ft, Object[] values ) { 072 this.ft = ft; 073 this.fidDefinition = ft.getGMLId(); 074 this.values = values; 075 } 076 077 /** 078 * Creates a new instance of <code>FeatureId</code> from the given parameters. 079 * 080 * @param ft 081 * cannot be null, must not be an abstract feature type 082 * @param fid 083 * cannot be null 084 * @throws IdGenerationException 085 */ 086 public FeatureId( MappedFeatureType ft, String fid ) throws IdGenerationException { 087 this.ft = ft; 088 this.fidDefinition = ft.getGMLId(); 089 this.values = new Object[1]; 090 this.values[0] = removeFIDPrefix( fid, fidDefinition ); 091 } 092 093 094 095 /** 096 * Return the {@link MappedFeatureType} of the identified feature. 097 * <p> 098 * The feature type is concrete, never abstract. 099 * 100 * @return type of the identified feature, never abstract 101 */ 102 public MappedFeatureType getFeatureType() { 103 return this.ft; 104 } 105 106 /** 107 * Return the underlying {@link MappedGMLId}. 108 * 109 * @return MappedGMLId 110 */ 111 public MappedGMLId getFidDefinition() { 112 return this.fidDefinition; 113 } 114 115 /** 116 * Returns the number of components that the key consists of. 117 * 118 * @return the number of components that the key consists of 119 */ 120 public int getLength() { 121 return this.values.length; 122 } 123 124 /** 125 * Returns all column values of the key. 126 * 127 * @return all column values of the key 128 */ 129 public Object[] getValues() { 130 return this.values; 131 } 132 133 /** 134 * Returns a certain column value of the key. 135 * 136 * @param i 137 * requested column 138 * @return the requested column value of the key 139 */ 140 public Object getValue( int i ) { 141 return this.values[i]; 142 } 143 144 /** 145 * Returns the canonical textual representation, i.e. the key components, separated by the separator defined in the 146 * associated {@link MappedGMLId}. 147 * 148 * @return the canonical textual representation 149 */ 150 public String getAsString() { 151 StringBuffer sb = new StringBuffer( fidDefinition.getPrefix() ); 152 for ( int i = 0; i < this.values.length; i++ ) { 153 sb.append( values[i] ); 154 if ( i != this.values.length - 1 ) { 155 sb.append( fidDefinition.getSeparator() ); 156 } 157 } 158 return sb.toString(); 159 } 160 161 public int compareTo( FeatureId that ) { 162 return this.getAsString().compareTo( that.getAsString() ); 163 } 164 165 @Override 166 public int hashCode() { 167 int hashCode = fidDefinition.hashCode(); 168 for ( int i = 0; i < this.values.length; i++ ) { 169 hashCode += this.values[i].toString().hashCode(); 170 } 171 return hashCode; 172 } 173 174 @Override 175 public boolean equals( Object obj ) { 176 if ( obj == null || !( obj instanceof FeatureId ) ) { 177 return false; 178 } 179 FeatureId that = (FeatureId) obj; 180 if ( this.fidDefinition != that.fidDefinition ) { 181 return false; 182 } 183 if ( this.values == null && that.values == null ) { 184 return true; 185 } 186 if ( ( this.values != null && that.values == null ) || ( this.values == null && that.values != null ) 187 || ( this.values.length != that.values.length ) ) { 188 return false; 189 } 190 for ( int i = 0; i < this.values.length; i++ ) { 191 if ( ( this.values[i] != null && that.values[i] == null ) 192 || ( this.values[i] == null && that.values[i] != null ) ) { 193 return false; 194 } 195 if ( this.values[i] != null && that.values[i] != null ) { 196 if ( !this.values[i].equals( that.values[i] ) ) { 197 return false; 198 } 199 } 200 } 201 return true; 202 } 203 204 /** 205 * Returns a string representation of the object. 206 * 207 * @return a string representation of the object 208 */ 209 @Override 210 public String toString() { 211 StringBuffer sb = new StringBuffer(); 212 sb.append( "fid=" ); 213 sb.append( getAsString() ); 214 sb.append( ", " ); 215 MappingField[] fidFields = fidDefinition.getIdFields(); 216 for ( int i = 0; i < fidFields.length; i++ ) { 217 sb.append( fidFields[i].getField() ); 218 sb.append( "=" ); 219 sb.append( values[i] ); 220 if ( i != fidFields.length - 1 ) { 221 sb.append( ", " ); 222 } 223 } 224 return sb.toString(); 225 } 226 227 /** 228 * Removes the prefix from the given feature id. 229 * <p> 230 * The prefix is taken from the given gml:id mapping. 231 * 232 * @param id 233 * feature id (including prefix). 234 * @param idMapping 235 * target gml:id mapping (where the fid will be stored) 236 * @return feature id (without prefix) as an object of the right type (matching the table column) 237 * @throws IdGenerationException 238 * if the given fid does not begin with the expected prefix from the gml:id mapping 239 */ 240 public static Object removeFIDPrefix( String id, MappedGMLId idMapping ) 241 throws IdGenerationException { 242 String plainIdValue = id; 243 String prefix = idMapping.getPrefix(); 244 if ( prefix != null && prefix.length() > 0 ) { 245 if ( !id.startsWith( prefix ) ) { 246 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_NO_PREFIX", id, prefix ); 247 throw new IdGenerationException( msg ); 248 } 249 plainIdValue = id.substring( prefix.length() ); 250 } 251 252 String[] plainIdValues = null; 253 String separator = idMapping.getSeparator(); 254 if ( separator != null && separator.length() > 0 ) { 255 plainIdValues = plainIdValue.split( separator ); 256 } else { 257 plainIdValues = new String[1]; 258 plainIdValues[0] = plainIdValue; 259 } 260 261 MappingField[] idFields = idMapping.getIdFields(); 262 if ( idFields.length != plainIdValues.length ) { 263 String msg = "The given feature id \"" + id + "\" consists of " + plainIdValues.length 264 + " value parts. Should be " + idFields.length + "."; 265 throw new IdGenerationException( msg ); 266 } 267 268 int sqlTypeCode; 269 Object fidObject = null; 270 Object[] fidObjects = new Object[idFields.length]; 271 for ( int i = 0; i < idFields.length; i++ ) { 272 plainIdValue = plainIdValues[i]; 273 sqlTypeCode = idFields[i].getType(); 274 switch ( sqlTypeCode ) { 275 case Types.NUMERIC: 276 case Types.DECIMAL: 277 case Types.DOUBLE: { 278 try { 279 fidObject = Double.parseDouble( plainIdValue ); 280 } catch ( NumberFormatException e ) { 281 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, "Double" ); 282 throw new IdGenerationException( msg ); 283 } 284 break; 285 } 286 case Types.FLOAT: { 287 try { 288 fidObject = Float.parseFloat( plainIdValue ); 289 } catch ( NumberFormatException e ) { 290 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, "Float" ); 291 throw new IdGenerationException( msg ); 292 } 293 break; 294 } 295 case Types.INTEGER: { 296 try { 297 fidObject = Integer.parseInt( plainIdValue ); 298 } catch ( NumberFormatException e ) { 299 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, "Integer" ); 300 throw new IdGenerationException( msg ); 301 } 302 break; 303 } 304 case Types.VARCHAR: 305 case Types.CHAR: { 306 fidObject = plainIdValue; 307 break; 308 } 309 default: { 310 String msg = null; 311 try { 312 msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, 313 Types.getTypeNameForSQLTypeCode( sqlTypeCode ) ); 314 } catch ( UnknownTypeException e ) { 315 throw new IdGenerationException( e.getMessage() ); 316 } 317 throw new IdGenerationException( msg ); 318 } 319 } 320 fidObjects[i] = fidObject; 321 } 322 323 if ( fidObjects.length > 1 ) { 324 return fidObjects; 325 } 326 return fidObject; 327 } 328 329 }