/* Copyright (c) 2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.api; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.geotools.referencing.crs.DefaultGeographicCRS.WGS84; import org.geotools.data.DataUtilities; import org.geotools.referencing.CRS; import org.locationtech.geogig.api.plumbing.HashObject; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.Name; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; /** * A binary representation of the state of a Feature Type. */ public class RevFeatureTypeImpl extends AbstractRevObject implements RevFeatureType { private final FeatureType featureType; private ImmutableList<PropertyDescriptor> sortedDescriptors; public static RevFeatureTypeImpl build(FeatureType featureType) { RevFeatureTypeImpl unnamed = new RevFeatureTypeImpl(featureType); ObjectId id = new HashObject().setObject(unnamed).call(); return new RevFeatureTypeImpl(id, featureType); } /** * Constructs a new {@code RevFeatureType} from the given {@link FeatureType}. * * @param featureType the feature type to use */ private RevFeatureTypeImpl(FeatureType featureType) { this(ObjectId.NULL, featureType); } /** * Constructs a new {@code RevFeatureType} from the given {@link ObjectId} and * {@link FeatureType}. * * @param id the object id to use for this feature type * @param featureType the feature type to use */ public RevFeatureTypeImpl(ObjectId id, FeatureType featureType) { super(id); checkNotNull(featureType); CoordinateReferenceSystem defaultCrs = featureType.getCoordinateReferenceSystem(); if (WGS84.equals(defaultCrs)) { // GeoTools treats DefaultGeographic.WGS84 as a special case when calling the // CRS.toSRS() method, and that causes the parsed RevFeatureType to hash differently. // To compensate that, we replace any instance of it with a CRS built using the // EPSG:4326 code, which works consistently when storing it and later recovering it from // the database. checkArgument(featureType instanceof SimpleFeatureType); try { final boolean longitudeFirst = true; CoordinateReferenceSystem epsg4326 = CRS.decode("EPSG:4326", longitudeFirst); String[] includeAllAttributes = null; featureType = DataUtilities.createSubType((SimpleFeatureType) featureType, includeAllAttributes, epsg4326); } catch (Exception e) { throw Throwables.propagate(e); } } this.featureType = featureType; sortedDescriptors = ImmutableList.copyOf(featureType.getDescriptors()); } @Override public TYPE getType() { return TYPE.FEATURETYPE; } @Override public FeatureType type() { return featureType; } /** * @return the sorted {@link PropertyDescriptor}s of the feature type */ @Override public ImmutableList<PropertyDescriptor> sortedDescriptors() { return sortedDescriptors; } /** * @return the name of the feature type */ @Override public Name getName() { Name name = type().getName(); return name; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FeatureType["); builder.append(getId().toString()); builder.append("; "); boolean first = true; for (PropertyDescriptor desc : sortedDescriptors()) { if (first) { first = false; } else { builder.append(", "); } builder.append(desc.getName().getLocalPart()); builder.append(": "); builder.append(desc.getType().getBinding().getSimpleName()); } builder.append(']'); return builder.toString(); } }