in incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java [647:791]
public synchronized void updateType(DefaultFeatureType newType) throws DataStoreException {
if (!isDefaultView()) throw new DataStoreException("Resource not writable in current filter state");
if (Files.exists(shpPath)) {
throw new DataStoreException("Update type is possible only when files do not exist. It can be used to create a new shapefile but not to update one.");
}
final Class<?>[] supportedDateTypes; // All types other than the one at index 0 will lost information.
if (timezone == null) {
supportedDateTypes = new Class<?>[] {
LocalDate.class, LocalDateTime.class
};
} else {
supportedDateTypes = new Class<?>[] {
LocalDate.class, LocalDateTime.class, OffsetDateTime.class, ZonedDateTime.class, Instant.class
};
}
lock.writeLock().lock();
try {
final ShapeHeader shpHeader = new ShapeHeader();
shpHeader.bbox = new ImmutableEnvelope(new GeneralEnvelope(4));
final DBFHeader dbfHeader = new DBFHeader();
dbfHeader.lastUpdate = LocalDate.now();
dbfHeader.fields = new DBFField[0];
final Charset charset = userDefinedCharSet == null ? StandardCharsets.UTF_8 : userDefinedCharSet;
CoordinateReferenceSystem crs = CommonCRS.WGS84.normalizedGeographic();
for (AbstractIdentifiedType pt : newType.getProperties(true)) {
if (pt instanceof DefaultAttributeType) {
final DefaultAttributeType at = (DefaultAttributeType) pt;
final Class valueClass = at.getValueClass();
final String attName = at.getName().tip().toString();
Integer length = AttributeConvention.getMaximalLengthCharacteristic(newType, pt);
if (length == null || length == 0) length = 255;
if (Geometry.class.isAssignableFrom(valueClass)) {
if (shpHeader.shapeType != null) {
throw new DataStoreException("Shapefile format can only contain one geometry");
}
if (Point.class.isAssignableFrom(valueClass)) shpHeader.shapeType = ShapeType.POINT;
else if (MultiPoint.class.isAssignableFrom(valueClass))
shpHeader.shapeType = ShapeType.MULTIPOINT;
else if (LineString.class.isAssignableFrom(valueClass) || MultiLineString.class.isAssignableFrom(valueClass))
shpHeader.shapeType = ShapeType.POLYLINE;
else if (Polygon.class.isAssignableFrom(valueClass) || MultiPolygon.class.isAssignableFrom(valueClass))
shpHeader.shapeType = ShapeType.POLYGON;
else throw new DataStoreException("Unsupported geometry type " + valueClass);
Object cdt = at.characteristics().get(AttributeConvention.CRS);
if (cdt instanceof DefaultAttributeType) {
Object defaultValue = ((DefaultAttributeType) cdt).getDefaultValue();
if (defaultValue instanceof CoordinateReferenceSystem) {
crs = (CoordinateReferenceSystem) defaultValue;
}
}
} else if (String.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_CHAR, 0, length, 0, charset, null));
} else if (Byte.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 4, 0, null, null));
} else if (Short.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 6, 0, null, null));
} else if (Integer.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 9, 0, null, null));
} else if (Long.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 19, 0, null, null));
} else if (Float.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 11, 6, null, null));
} else if (Double.class.isAssignableFrom(valueClass)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 33, 18, null, null));
} else if (Classes.isAssignableToAny(valueClass, supportedDateTypes)) {
dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_DATE, 0, 20, 0, null, timezone));
if (!(LocalDate.class.isAssignableFrom(valueClass))) { // TODO: use `index != 0` instead.
LOGGER.log(Level.WARNING, "Shapefile writing, field {0} will lost the time component of the date", pt.getName());
}
} else {
LOGGER.log(Level.WARNING, "Shapefile writing, field {0} is not supported", pt.getName());
}
} else {
LOGGER.log(Level.WARNING, "Shapefile writing, field {0} is not supported", pt.getName());
}
}
//write shapefile
try (ShapeWriter writer = new ShapeWriter(ShpFiles.openWriteChannel(files.shpFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
writer.writeHeader(shpHeader);
} catch (IOException ex) {
throw new DataStoreException("Failed to create shapefile (shp).", ex);
}
//write shx
try (IndexWriter writer = new IndexWriter(ShpFiles.openWriteChannel(files.getShx(true), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
writer.writeHeader(shpHeader);
} catch (IOException ex) {
throw new DataStoreException("Failed to create shapefile (shx).", ex);
}
//write dbf
try (DBFWriter writer = new DBFWriter(ShpFiles.openWriteChannel(files.getDbf(true), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
writer.writeHeader(dbfHeader);
} catch (IOException ex) {
throw new DataStoreException("Failed to create shapefile (dbf).", ex);
}
//write cpg
try {
CpgFiles.write(charset, files.getCpg(true));
} catch (IOException ex) {
throw new DataStoreException("Failed to create shapefile (cpg).", ex);
}
//write prj
try {
final String wkt;
if (Utilities.equalsApproximately(crs, CommonCRS.WGS84.normalizedGeographic())) {
/*
* TODO until we manage to understand the expected ESRI writing for CRS:84
* we replace it by hand.
* There is an odd recursive information that shapefiles are longitude first whatever the CRS.
* But the ESRI specification do not say anything about it.
* Generate WKT by tools like ogr,qgis do not declare the axes so we are clueless.
*/
wkt = "GEOGCS[\"GCS_WGS_84_CRS84\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]";
} else {
final WKTFormat format = new WKTFormat();
format.setConvention(Convention.WKT1_COMMON_UNITS);
format.setNameAuthority(Citations.ESRI);
format.setIndentation(WKTFormat.SINGLE_LINE);
wkt = format.format(crs);
}
Files.writeString(files.getPrj(true), wkt, StandardCharsets.ISO_8859_1, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
} catch (IOException ex) {
throw new DataStoreException("Failed to create shapefile (prj).", ex);
}
//update file list
files.scan();
} finally {
lock.writeLock().unlock();
}
}