001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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 }