001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/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: aschmitz $ 052 * 053 * @version $Revision: 22080 $, $Date: 2010-01-21 13:24:52 +0100 (Do, 21 Jan 2010) $ 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 * Creates a new instance of <code>FeatureId</code> from the given parameters. 095 * 096 * @param fidDefinition 097 * cannot be null 098 * @param values 099 * @deprecated use {@link #FeatureId(MappedFeatureType, Object[])} instead 100 */ 101 @Deprecated 102 public FeatureId( MappedGMLId fidDefinition, Object[] values ) { 103 this.fidDefinition = fidDefinition; 104 this.values = values; 105 } 106 107 /** 108 * Creates a new instance of <code>FeatureId</code> from the given parameters. 109 * 110 * @param fidDefinition 111 * cannot be null 112 * @param fid 113 * cannot be null 114 * @throws IdGenerationException 115 * @deprecated use {@link #FeatureId(MappedFeatureType, String)} instead 116 */ 117 @Deprecated 118 public FeatureId( MappedGMLId fidDefinition, String fid ) throws IdGenerationException { 119 this.fidDefinition = fidDefinition; 120 this.values = new Object[1]; 121 this.values[0] = removeFIDPrefix( fid, fidDefinition ); 122 } 123 124 /** 125 * Return the {@link MappedFeatureType} of the identified feature. 126 * <p> 127 * The feature type is concrete, never abstract. 128 * 129 * @return type of the identified feature, never abstract 130 */ 131 public MappedFeatureType getFeatureType() { 132 return this.ft; 133 } 134 135 /** 136 * Return the underlying {@link MappedGMLId}. 137 * 138 * @return MappedGMLId 139 */ 140 public MappedGMLId getFidDefinition() { 141 return this.fidDefinition; 142 } 143 144 /** 145 * Returns the number of components that the key consists of. 146 * 147 * @return the number of components that the key consists of 148 */ 149 public int getLength() { 150 return this.values.length; 151 } 152 153 /** 154 * Returns all column values of the key. 155 * 156 * @return all column values of the key 157 */ 158 public Object[] getValues() { 159 return this.values; 160 } 161 162 /** 163 * Returns a certain column value of the key. 164 * 165 * @param i 166 * requested column 167 * @return the requested column value of the key 168 */ 169 public Object getValue( int i ) { 170 return this.values[i]; 171 } 172 173 /** 174 * Returns the canonical textual representation, i.e. the key components, separated by the separator defined in the 175 * associated {@link MappedGMLId}. 176 * 177 * @return the canonical textual representation 178 */ 179 public String getAsString() { 180 StringBuffer sb = new StringBuffer( fidDefinition.getPrefix() ); 181 for ( int i = 0; i < this.values.length; i++ ) { 182 sb.append( values[i] ); 183 if ( i != this.values.length - 1 ) { 184 sb.append( fidDefinition.getSeparator() ); 185 } 186 } 187 return sb.toString(); 188 } 189 190 public int compareTo( FeatureId that ) { 191 return this.getAsString().compareTo( that.getAsString() ); 192 } 193 194 @Override 195 public int hashCode() { 196 int hashCode = fidDefinition.hashCode(); 197 for ( int i = 0; i < this.values.length; i++ ) { 198 hashCode += this.values[i].toString().hashCode(); 199 } 200 return hashCode; 201 } 202 203 @Override 204 public boolean equals( Object obj ) { 205 if ( obj == null || !( obj instanceof FeatureId ) ) { 206 return false; 207 } 208 FeatureId that = (FeatureId) obj; 209 if ( this.fidDefinition != that.fidDefinition ) { 210 return false; 211 } 212 if ( this.values == null && that.values == null ) { 213 return true; 214 } 215 if ( ( this.values != null && that.values == null ) || ( this.values == null && that.values != null ) 216 || ( this.values.length != that.values.length ) ) { 217 return false; 218 } 219 for ( int i = 0; i < this.values.length; i++ ) { 220 if ( ( this.values[i] != null && that.values[i] == null ) 221 || ( this.values[i] == null && that.values[i] != null ) ) { 222 return false; 223 } 224 if ( this.values[i] != null && that.values[i] != null ) { 225 if ( !this.values[i].equals( that.values[i] ) ) { 226 return false; 227 } 228 } 229 } 230 return true; 231 } 232 233 /** 234 * Returns a string representation of the object. 235 * 236 * @return a string representation of the object 237 */ 238 @Override 239 public String toString() { 240 StringBuffer sb = new StringBuffer(); 241 sb.append( "fid=" ); 242 sb.append( getAsString() ); 243 sb.append( ", " ); 244 MappingField[] fidFields = fidDefinition.getIdFields(); 245 for ( int i = 0; i < fidFields.length; i++ ) { 246 sb.append( fidFields[i].getField() ); 247 sb.append( "=" ); 248 sb.append( values[i] ); 249 if ( i != fidFields.length - 1 ) { 250 sb.append( ", " ); 251 } 252 } 253 return sb.toString(); 254 } 255 256 /** 257 * Removes the prefix from the given feature id. 258 * <p> 259 * The prefix is taken from the given gml:id mapping. 260 * 261 * @param id 262 * feature id (including prefix). 263 * @param idMapping 264 * target gml:id mapping (where the fid will be stored) 265 * @return feature id (without prefix) as an object of the right type (matching the table column) 266 * @throws IdGenerationException 267 * if the given fid does not begin with the expected prefix from the gml:id mapping 268 */ 269 public static Object removeFIDPrefix( String id, MappedGMLId idMapping ) 270 throws IdGenerationException { 271 String plainIdValue = id; 272 String prefix = idMapping.getPrefix(); 273 if ( prefix != null && prefix.length() > 0 ) { 274 if ( !id.startsWith( prefix ) ) { 275 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_NO_PREFIX", id, prefix ); 276 throw new IdGenerationException( msg ); 277 } 278 plainIdValue = id.substring( prefix.length() ); 279 } 280 281 String[] plainIdValues = null; 282 String separator = idMapping.getSeparator(); 283 if ( separator != null && separator.length() > 0 ) { 284 plainIdValues = plainIdValue.split( separator ); 285 } else { 286 plainIdValues = new String[1]; 287 plainIdValues[0] = plainIdValue; 288 } 289 290 MappingField[] idFields = idMapping.getIdFields(); 291 if ( idFields.length != plainIdValues.length ) { 292 String msg = "The given feature id \"" + id + "\" consists of " + plainIdValues.length 293 + " value parts. Should be " + idFields.length + "."; 294 throw new IdGenerationException( msg ); 295 } 296 297 int sqlTypeCode; 298 Object fidObject = null; 299 Object[] fidObjects = new Object[idFields.length]; 300 for ( int i = 0; i < idFields.length; i++ ) { 301 plainIdValue = plainIdValues[i]; 302 sqlTypeCode = idFields[i].getType(); 303 switch ( sqlTypeCode ) { 304 case Types.NUMERIC: 305 case Types.DECIMAL: 306 case Types.DOUBLE: { 307 try { 308 fidObject = Double.parseDouble( plainIdValue ); 309 } catch ( NumberFormatException e ) { 310 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, "Double" ); 311 throw new IdGenerationException( msg ); 312 } 313 break; 314 } 315 case Types.FLOAT: { 316 try { 317 fidObject = Float.parseFloat( plainIdValue ); 318 } catch ( NumberFormatException e ) { 319 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, "Float" ); 320 throw new IdGenerationException( msg ); 321 } 322 break; 323 } 324 case Types.INTEGER: { 325 try { 326 fidObject = Integer.parseInt( plainIdValue ); 327 } catch ( NumberFormatException e ) { 328 String msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, "Integer" ); 329 throw new IdGenerationException( msg ); 330 } 331 break; 332 } 333 case Types.VARCHAR: 334 case Types.CHAR: { 335 fidObject = plainIdValue; 336 break; 337 } 338 default: { 339 String msg = null; 340 try { 341 msg = Messages.getMessage( "DATASTORE_FEATURE_ID_CONVERT", plainIdValue, 342 Types.getTypeNameForSQLTypeCode( sqlTypeCode ) ); 343 } catch ( UnknownTypeException e ) { 344 throw new IdGenerationException( e.getMessage() ); 345 } 346 throw new IdGenerationException( msg ); 347 } 348 } 349 fidObjects[i] = fidObject; 350 } 351 352 if ( fidObjects.length > 1 ) { 353 return fidObjects; 354 } 355 return fidObject; 356 } 357 358 }