PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/geotools-9.2/modules/library/main/src/main/java/org/geotools/feature/simple/SimpleFeatureImpl.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 654 lines | 427 code | 87 blank | 140 comment | 75 complexity | 5d8935be27d8e943cffe7df0662a92ac MD5 | raw file
  1. /*
  2. * GeoTools - The Open Source Java GIS Toolkit
  3. * http://geotools.org
  4. *
  5. * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation;
  10. * version 2.1 of the License.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. */
  17. package org.geotools.feature.simple;
  18. import java.util.AbstractList;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import java.util.Collections;
  23. import java.util.HashMap;
  24. import java.util.List;
  25. import java.util.Map;
  26. import org.geotools.feature.AttributeImpl;
  27. import org.geotools.feature.GeometryAttributeImpl;
  28. import org.geotools.feature.IllegalAttributeException;
  29. import org.geotools.feature.PropertyImpl;
  30. import org.geotools.feature.type.AttributeDescriptorImpl;
  31. import org.geotools.feature.type.Types;
  32. import org.geotools.geometry.jts.JTS;
  33. import org.geotools.geometry.jts.ReferencedEnvelope;
  34. import org.geotools.geometry.jts.ReferencedEnvelope3D;
  35. import org.geotools.util.Converters;
  36. import org.geotools.util.Utilities;
  37. import org.opengis.feature.GeometryAttribute;
  38. import org.opengis.feature.Property;
  39. import org.opengis.feature.simple.SimpleFeature;
  40. import org.opengis.feature.simple.SimpleFeatureType;
  41. import org.opengis.feature.type.AttributeDescriptor;
  42. import org.opengis.feature.type.AttributeType;
  43. import org.opengis.feature.type.GeometryDescriptor;
  44. import org.opengis.feature.type.GeometryType;
  45. import org.opengis.feature.type.Name;
  46. import org.opengis.filter.identity.FeatureId;
  47. import org.opengis.filter.identity.Identifier;
  48. import org.opengis.geometry.BoundingBox;
  49. import org.opengis.referencing.crs.CoordinateReferenceSystem;
  50. import com.vividsolutions.jts.geom.Envelope;
  51. import com.vividsolutions.jts.geom.Geometry;
  52. /**
  53. * An implementation of {@link SimpleFeature} geared towards speed and backed by an Object[].
  54. *
  55. * @author Justin
  56. * @author Andrea Aime
  57. *
  58. *
  59. *
  60. * @source $URL$
  61. */
  62. public class SimpleFeatureImpl implements SimpleFeature {
  63. protected FeatureId id;
  64. protected SimpleFeatureType featureType;
  65. /**
  66. * The actual values held by this feature
  67. */
  68. protected Object[] values;
  69. /**
  70. * The attribute name -> position index
  71. */
  72. protected Map<String,Integer> index;
  73. /**
  74. * The set of user data attached to the feature (lazily created)
  75. */
  76. protected Map<Object, Object> userData;
  77. /**
  78. * The set of user data attached to each attribute (lazily created)
  79. */
  80. protected Map<Object, Object>[] attributeUserData;
  81. /**
  82. * Whether this feature is self validating or not
  83. */
  84. protected boolean validating;
  85. /**
  86. * Builds a new feature based on the provided values and feature type
  87. * @param values
  88. * @param featureType
  89. * @param id
  90. */
  91. public SimpleFeatureImpl( List<Object> values, SimpleFeatureType featureType, FeatureId id) {
  92. this(values.toArray(), featureType, id, false,index(featureType));
  93. }
  94. /**
  95. * Fast construction of a new feature.
  96. * <p>
  97. * The object takes ownership of the provided value array,
  98. * do not modify after calling the constructor
  99. *</p>
  100. * @param values
  101. * @param featureType
  102. * @param id
  103. * @param validating
  104. */
  105. public SimpleFeatureImpl(Object[] values, SimpleFeatureType featureType, FeatureId id, boolean validating) {
  106. this(values, featureType, id, validating, index(featureType));
  107. }
  108. /**
  109. * Fast construction of a new feature.
  110. * <p>
  111. * The object takes ownership of the provided value array,
  112. * do not modify after calling the constructor
  113. *</p>
  114. * @param values
  115. * @param featureType
  116. * @param id
  117. * @param validating
  118. * @param index - attribute name to value index mapping
  119. */
  120. public SimpleFeatureImpl(Object[] values, SimpleFeatureType featureType,
  121. FeatureId id, boolean validating, Map<String,Integer> index) {
  122. this.id = id;
  123. this.featureType = featureType;
  124. this.values = values;
  125. this.validating = validating;
  126. this.index = index;
  127. // if we're self validating, do validation right now
  128. if(validating)
  129. validate();
  130. }
  131. /**
  132. * Generate (or lookup) an "index" mapping attribute to index for the provided FeatureType.
  133. * <p>
  134. * This method will use the following:
  135. * <ul>
  136. * <li>SimpleFeatureTypeImpl.index; or
  137. * <li>Check getUserData().get("indexLookup");
  138. * <li>or call {@link SimpleFeatureTypeImpl#buildIndex(SimpleFeatureType)} to generate the
  139. * required index
  140. * </ul>
  141. * @param featureType
  142. * @return mapping between attribute name to attribute index
  143. */
  144. @SuppressWarnings("unchecked")
  145. private static Map<String,Integer> index(SimpleFeatureType featureType) {
  146. // in the most common case reuse the map cached in the feature type
  147. if(featureType instanceof SimpleFeatureTypeImpl) {
  148. return ((SimpleFeatureTypeImpl) featureType).index;
  149. } else {
  150. synchronized (featureType) {
  151. // if we're not lucky, rebuild the index completely...
  152. Object cache = featureType.getUserData().get("indexLookup");
  153. if( cache instanceof Map){
  154. return (Map<String,Integer>) cache;
  155. }
  156. else {
  157. Map<String,Integer> generatedIndex = SimpleFeatureTypeImpl.buildIndex(featureType);
  158. featureType.getUserData().put("indexLookup", generatedIndex );
  159. return generatedIndex;
  160. }
  161. }
  162. }
  163. }
  164. public FeatureId getIdentifier() {
  165. return id;
  166. }
  167. public String getID() {
  168. return id.getID();
  169. }
  170. public int getNumberOfAttributes() {
  171. return values.length;
  172. }
  173. public Object getAttribute(int index) throws IndexOutOfBoundsException {
  174. return values[ index ];
  175. }
  176. public Object getAttribute(String name) {
  177. Integer idx = index.get(name);
  178. if(idx != null)
  179. return getAttribute(idx);
  180. else
  181. return null;
  182. }
  183. public Object getAttribute(Name name) {
  184. return getAttribute( name.getLocalPart() );
  185. }
  186. public int getAttributeCount() {
  187. return values.length;
  188. }
  189. public List<Object> getAttributes() {
  190. return new ArrayList(Arrays.asList( values ));
  191. }
  192. public Object getDefaultGeometry() {
  193. // should be specified in the index as the default key (null)
  194. Integer idx = index.get(null);
  195. Object defaultGeometry = idx != null ? getAttribute( idx ) : null;
  196. // not found? do we have a default geometry at all?
  197. if(defaultGeometry == null){
  198. GeometryDescriptor geometryDescriptor = featureType.getGeometryDescriptor();
  199. if(geometryDescriptor != null){
  200. Integer defaultGeomIndex = index.get(geometryDescriptor.getName().getLocalPart());
  201. defaultGeometry = getAttribute(defaultGeomIndex.intValue());
  202. }
  203. }
  204. return defaultGeometry;
  205. }
  206. public SimpleFeatureType getFeatureType() {
  207. return featureType;
  208. }
  209. public SimpleFeatureType getType() {
  210. return featureType;
  211. }
  212. public void setAttribute(int index, Object value)
  213. throws IndexOutOfBoundsException {
  214. // first do conversion
  215. Object converted = Converters.convert(value, getFeatureType().getDescriptor(index).getType().getBinding());
  216. // if necessary, validation too
  217. if(validating)
  218. Types.validate(featureType.getDescriptor(index), converted);
  219. // finally set the value into the feature
  220. values[index] = converted;
  221. }
  222. public void setAttribute(String name, Object value) {
  223. final Integer idx = index.get(name);
  224. if(idx == null)
  225. throw new IllegalAttributeException("Unknown attribute " + name);
  226. setAttribute( idx.intValue(), value );
  227. }
  228. public void setAttribute(Name name, Object value) {
  229. setAttribute( name.getLocalPart(), value );
  230. }
  231. public void setAttributes(List<Object> values) {
  232. for (int i = 0; i < this.values.length; i++) {
  233. this.values[i] = values.get(i);
  234. }
  235. }
  236. public void setAttributes(Object[] values) {
  237. setAttributes( Arrays.asList( values ) );
  238. }
  239. public void setDefaultGeometry(Object geometry) {
  240. Integer geometryIndex = index.get( null );
  241. if ( geometryIndex != null ) {
  242. setAttribute( geometryIndex, geometry );
  243. }
  244. }
  245. public BoundingBox getBounds() {
  246. //TODO: cache this value
  247. CoordinateReferenceSystem crs = featureType.getCoordinateReferenceSystem();
  248. Envelope bounds = ReferencedEnvelope.create( crs );
  249. for ( Object o : values ) {
  250. if ( o instanceof Geometry ) {
  251. Geometry g = (Geometry) o;
  252. //TODO: check userData for crs... and ensure its of the same
  253. // crs as the feature type
  254. if ( bounds.isNull() ) {
  255. bounds.init(JTS.bounds( g, crs ));
  256. }
  257. else {
  258. bounds.expandToInclude(JTS.bounds( g, crs ));
  259. }
  260. }
  261. }
  262. return (BoundingBox) bounds;
  263. }
  264. public GeometryAttribute getDefaultGeometryProperty() {
  265. GeometryDescriptor geometryDescriptor = featureType.getGeometryDescriptor();
  266. GeometryAttribute geometryAttribute = null;
  267. if(geometryDescriptor != null){
  268. Object defaultGeometry = getDefaultGeometry();
  269. geometryAttribute = new GeometryAttributeImpl(defaultGeometry, geometryDescriptor, null);
  270. }
  271. return geometryAttribute;
  272. }
  273. public void setDefaultGeometryProperty(GeometryAttribute geometryAttribute) {
  274. if(geometryAttribute != null)
  275. setDefaultGeometry(geometryAttribute.getValue());
  276. else
  277. setDefaultGeometry(null);
  278. }
  279. public Collection<Property> getProperties() {
  280. return new AttributeList();
  281. }
  282. public Collection<Property> getProperties(Name name) {
  283. return getProperties( name.getLocalPart() );
  284. }
  285. public Collection<Property> getProperties(String name) {
  286. final Integer idx = index.get(name);
  287. if(idx != null) {
  288. // cast temporarily to a plain collection to avoid type problems with generics
  289. Collection c = Collections.singleton( new Attribute( idx ) );
  290. return c;
  291. } else {
  292. return Collections.emptyList();
  293. }
  294. }
  295. public Property getProperty(Name name) {
  296. return getProperty( name.getLocalPart() );
  297. }
  298. public Property getProperty(String name) {
  299. final Integer idx = index.get(name);
  300. if(idx == null){
  301. return null;
  302. } else {
  303. int index = idx.intValue();
  304. AttributeDescriptor descriptor = featureType.getDescriptor(index);
  305. if(descriptor instanceof GeometryDescriptor){
  306. return new GeometryAttributeImpl(values[index], (GeometryDescriptor) descriptor, null);
  307. }else{
  308. return new Attribute( index );
  309. }
  310. }
  311. }
  312. public Collection<? extends Property> getValue() {
  313. return getProperties();
  314. }
  315. public void setValue(Collection<Property> values) {
  316. int i = 0;
  317. for ( Property p : values ) {
  318. this.values[i] = p.getValue();
  319. }
  320. }
  321. public void setValue(Object newValue) {
  322. setValue( (Collection<Property>) newValue );
  323. }
  324. /**
  325. * @see org.opengis.feature.Attribute#getDescriptor()
  326. */
  327. public AttributeDescriptor getDescriptor() {
  328. return new AttributeDescriptorImpl(featureType, featureType.getName(), 0,
  329. Integer.MAX_VALUE, true, null);
  330. }
  331. /**
  332. * @return same name than this feature's {@link SimpleFeatureType}
  333. * @see org.opengis.feature.Property#getName()
  334. */
  335. public Name getName() {
  336. return featureType.getName();
  337. }
  338. public boolean isNillable() {
  339. return true;
  340. }
  341. public Map<Object, Object> getUserData() {
  342. if(userData == null)
  343. userData = new HashMap<Object, Object>();
  344. return userData;
  345. }
  346. /**
  347. * returns a unique code for this feature
  348. *
  349. * @return A unique int
  350. */
  351. public int hashCode() {
  352. return id.hashCode() * featureType.hashCode();
  353. }
  354. /**
  355. * override of equals. Returns if the passed in object is equal to this.
  356. *
  357. * @param obj the Object to test for equality.
  358. *
  359. * @return <code>true</code> if the object is equal, <code>false</code>
  360. * otherwise.
  361. */
  362. public boolean equals(Object obj) {
  363. if (obj == null) {
  364. return false;
  365. }
  366. if (obj == this) {
  367. return true;
  368. }
  369. if (!(obj instanceof SimpleFeatureImpl)) {
  370. return false;
  371. }
  372. SimpleFeatureImpl feat = (SimpleFeatureImpl) obj;
  373. // this check shouldn't exist, by contract,
  374. //all features should have an ID.
  375. if (id == null) {
  376. if (feat.getIdentifier() != null) {
  377. return false;
  378. }
  379. }
  380. if (!id.equals(feat.getIdentifier())) {
  381. return false;
  382. }
  383. if (!feat.getFeatureType().equals(featureType)) {
  384. return false;
  385. }
  386. for (int i = 0, ii = values.length; i < ii; i++) {
  387. Object otherAtt = feat.getAttribute(i);
  388. if (values[i] == null) {
  389. if (otherAtt != null) {
  390. return false;
  391. }
  392. } else {
  393. if (!values[i].equals(otherAtt)) {
  394. return false;
  395. }
  396. }
  397. }
  398. return true;
  399. }
  400. public void validate() {
  401. for (int i = 0; i < values.length; i++) {
  402. AttributeDescriptor descriptor = getType().getDescriptor(i);
  403. Types.validate(descriptor, values[i]);
  404. }
  405. }
  406. /**
  407. * Live collection backed directly on the value array
  408. */
  409. class AttributeList extends AbstractList<Property> {
  410. public Property get(int index) {
  411. AttributeDescriptor descriptor = featureType.getDescriptor(index);
  412. if (descriptor instanceof GeometryDescriptor) {
  413. return new SimpleGeometryAttribute(index);
  414. }
  415. return new Attribute(index);
  416. }
  417. public Attribute set(int index, Property element) {
  418. values[index] = element.getValue();
  419. return null;
  420. }
  421. public int size() {
  422. return values.length;
  423. }
  424. }
  425. public String toString() {
  426. StringBuffer sb = new StringBuffer("SimpleFeatureImpl:");
  427. sb.append( getType().getName().getLocalPart());
  428. sb.append("=");
  429. sb.append( getValue() );
  430. return sb.toString();
  431. }
  432. /**
  433. * Attribute that delegates directly to the value array
  434. */
  435. class Attribute implements org.opengis.feature.Attribute {
  436. int index;
  437. Attribute( int index ) {
  438. this.index = index;
  439. }
  440. public Identifier getIdentifier() {
  441. return null;
  442. }
  443. public AttributeDescriptor getDescriptor() {
  444. return featureType.getDescriptor(index);
  445. }
  446. public AttributeType getType() {
  447. return featureType.getType(index);
  448. }
  449. public Name getName() {
  450. return getDescriptor().getName();
  451. }
  452. public Map<Object, Object> getUserData() {
  453. // lazily create the user data holder
  454. if(attributeUserData == null)
  455. attributeUserData = new HashMap[values.length];
  456. // lazily create the attribute user data
  457. if(attributeUserData[index] == null)
  458. attributeUserData[index] = new HashMap<Object, Object>();
  459. return attributeUserData[index];
  460. }
  461. public Object getValue() {
  462. return values[index];
  463. }
  464. public boolean isNillable() {
  465. return getDescriptor().isNillable();
  466. }
  467. public void setValue(Object newValue) {
  468. values[index] = newValue;
  469. }
  470. /**
  471. * Override of hashCode; uses descriptor name to agree with AttributeImpl
  472. *
  473. * @return hashCode for this object.
  474. */
  475. public int hashCode() {
  476. return 37 * getDescriptor().hashCode()
  477. + (37 * (getValue() == null ? 0 : getValue().hashCode()));
  478. }
  479. /**
  480. * Override of equals.
  481. *
  482. * @param other
  483. * the object to be tested for equality.
  484. *
  485. * @return whether other is equal to this attribute Type.
  486. */
  487. public boolean equals(Object obj) {
  488. if ( this == obj ) {
  489. return true;
  490. }
  491. if (!(obj instanceof Attribute)) {
  492. return false;
  493. }
  494. Attribute other = (Attribute) obj;
  495. if (!Utilities.equals(getDescriptor(), other.getDescriptor())){
  496. return false;
  497. }
  498. if (!Utilities.deepEquals(getValue(), other.getValue())){
  499. return false;
  500. }
  501. return Utilities.equals( getIdentifier(), other.getIdentifier());
  502. }
  503. public void validate() {
  504. Types.validate(getDescriptor(), values[index]);
  505. }
  506. public String toString() {
  507. StringBuffer sb = new StringBuffer("SimpleFeatureImpl.Attribute: ");
  508. sb.append(getDescriptor().getName().getLocalPart());
  509. if (!getDescriptor().getName().getLocalPart().equals(
  510. getDescriptor().getType().getName().getLocalPart())
  511. || id != null) {
  512. sb.append("<");
  513. sb.append(getDescriptor().getType().getName().getLocalPart());
  514. if (id != null) {
  515. sb.append(" id=");
  516. sb.append(id);
  517. }
  518. sb.append(">");
  519. }
  520. sb.append("=");
  521. sb.append( values[index] );
  522. return sb.toString();
  523. }
  524. }
  525. class SimpleGeometryAttribute extends Attribute implements GeometryAttribute {
  526. SimpleGeometryAttribute(int index) {
  527. super(index);
  528. }
  529. @Override
  530. public GeometryType getType() {
  531. return (GeometryType) super.getType();
  532. }
  533. @Override
  534. public GeometryDescriptor getDescriptor() {
  535. return (GeometryDescriptor) super.getDescriptor();
  536. }
  537. @Override
  538. public BoundingBox getBounds() {
  539. ReferencedEnvelope bounds = new ReferencedEnvelope(
  540. featureType.getCoordinateReferenceSystem());
  541. Object value = getAttribute(index);
  542. if (value instanceof Geometry) {
  543. bounds.init(((Geometry) value).getEnvelopeInternal());
  544. }
  545. return bounds;
  546. }
  547. @Override
  548. public void setBounds(BoundingBox bounds) {
  549. // do nothing, this property is strictly derived. Shall throw unsupported operation
  550. // exception?
  551. }
  552. @Override
  553. public int hashCode() {
  554. return 17 * super.hashCode();
  555. }
  556. @Override
  557. public boolean equals(Object obj) {
  558. if (this == obj) {
  559. return true;
  560. }
  561. if (!(obj instanceof SimpleGeometryAttribute)) {
  562. return false;
  563. }
  564. return super.equals(obj);
  565. }
  566. }
  567. }