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