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 }