This is an automated email from the ASF dual-hosted git repository.
jsorel pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 39fc3245a1 feat(Shapefile): test add, remove and update from
WritableFeatureSet
39fc3245a1 is described below
commit 39fc3245a1e9c1be8fcc5f981d785464164a184e
Author: jsorel <[email protected]>
AuthorDate: Tue Dec 5 15:24:29 2023 +0100
feat(Shapefile): test add, remove and update from WritableFeatureSet
---
.../sis/storage/shapefile/ShapefileStore.java | 5 +-
.../apache/sis/storage/shapefile/dbf/DBFField.java | 58 +++++++++-----
.../sis/storage/shapefile/ShapefileStoreTest.java | 89 ++++++++++++++++++----
3 files changed, 115 insertions(+), 37 deletions(-)
diff --git
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
index 2d6fe5e827..6c755a466e 100644
---
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
+++
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
@@ -172,7 +172,6 @@ public final class ShapefileStore extends DataStore
implements WritableFeatureSe
public void close() throws DataStoreException {
}
-
/*
Redirect FeatureSet interface to View
*/
@@ -649,9 +648,9 @@ public final class ShapefileStore extends DataStore
implements WritableFeatureSe
} else if (Long.class.isAssignableFrom(valueClass)) {
dbfHeader.fields =
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char)
DBFField.TYPE_NUMBER, 0, 19, 0, null));
} else if (Float.class.isAssignableFrom(valueClass)) {
- dbfHeader.fields =
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char)
DBFField.TYPE_NUMBER, 0, 11, 8, null));
+ dbfHeader.fields =
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char)
DBFField.TYPE_NUMBER, 0, 11, 6, null));
} else if (Double.class.isAssignableFrom(valueClass)) {
- dbfHeader.fields =
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char)
DBFField.TYPE_NUMBER, 0, 33, 30, null));
+ dbfHeader.fields =
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char)
DBFField.TYPE_NUMBER, 0, 33, 18, null));
} else if
(LocalDate.class.isAssignableFrom(valueClass)) {
dbfHeader.fields =
ArraysExt.append(dbfHeader.fields, new DBFField(attName, (char)
DBFField.TYPE_DATE, 0, 20, 0, null));
} else {
diff --git
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
index 85976ea76a..564bd7ba9d 100644
---
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
+++
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/dbf/DBFField.java
@@ -111,6 +111,7 @@ public final class DBFField {
case TYPE_NUMBER : {
if (fieldDecimals != 0) { valueClass = Double.class; reader
= this::readNumber; writer = this::writeNumber;
format = NumberFormat.getNumberInstance(Locale.US);
+ format.setGroupingUsed(false);
format.setMaximumFractionDigits(fieldDecimals);
format.setMinimumFractionDigits(fieldDecimals);
}
@@ -198,7 +199,20 @@ public final class DBFField {
}
private Object readLogic(ChannelDataInput channel) throws IOException {
- throw new UnsupportedOperationException();
+ final String str = new
String(channel.readBytes(fieldLength)).trim().toLowerCase();
+ final char c = str.charAt(0);
+ switch (c) {
+ case '1':
+ case 't':
+ case 'y':
+ return Boolean.TRUE;
+ case '0':
+ case 'f':
+ case 'n':
+ return Boolean.FALSE;
+ default:
+ throw new IOException("Unexpected logic value : " + str);
+ }
}
private Object readMemo(ChannelDataInput channel) throws IOException {
@@ -218,11 +232,11 @@ public final class DBFField {
}
private Object readFloat(ChannelDataInput channel) throws IOException {
- throw new UnsupportedOperationException();
+ return channel.readFloat();
}
private Object readDouble(ChannelDataInput channel) throws IOException {
- throw new UnsupportedOperationException();
+ return channel.readDouble();
}
private Object readOLE(ChannelDataInput channel) throws IOException {
@@ -260,6 +274,7 @@ public final class DBFField {
sb.append(month);
if(day.length() < 2) sb.append("0");
sb.append(day);
+ ensureLength(sb.toString());
channel.repeat(fieldLength - sb.length(), (byte)' ');
channel.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
}
@@ -268,32 +283,30 @@ public final class DBFField {
final Number v = ((Number) value);
final String str = format.format(v.doubleValue());
final int length = str.length();
+ ensureLength(str);
channel.repeat(fieldLength - length, (byte)' ');
channel.write(str.getBytes(StandardCharsets.US_ASCII));
}
private void writeNumberInt(ChannelDataOutput channel, Object value)
throws IOException {
- final String v = ((Integer) value).toString();
- final int length = v.length();
- if (length > fieldLength) {
- throw new IOException(v + " is longer then field length " +
fieldLength);
- }
- channel.repeat(fieldLength - length, (byte)' ');
- channel.write(v.getBytes(StandardCharsets.US_ASCII));
+ final String str = ((Integer) value).toString();
+ ensureLength(str);
+ channel.repeat(fieldLength - str.length(), (byte)' ');
+ channel.write(str.getBytes(StandardCharsets.US_ASCII));
}
private void writeNumberLong(ChannelDataOutput channel, Object value)
throws IOException {
- final String v = ((Long) value).toString();
- final int length = v.length();
- if (length > fieldLength) {
- throw new IOException(v + " is longer then field length " +
fieldLength);
- }
- channel.repeat(fieldLength - length, (byte)' ');
- channel.write(v.getBytes(StandardCharsets.US_ASCII));
+ final String str = ((Long) value).toString();
+ ensureLength(str);
+ channel.repeat(fieldLength - str.length(), (byte)' ');
+ channel.write(str.getBytes(StandardCharsets.US_ASCII));
}
private void writeLogic(ChannelDataOutput channel, Object value) throws
IOException {
- throw new UnsupportedOperationException();
+ final String str = Boolean.TRUE.equals(value) ? "T" : "F";
+ ensureLength(str);
+ channel.repeat(fieldLength - str.length(), (byte)' ');
+ channel.write(str.getBytes(StandardCharsets.US_ASCII));
}
private void writeMemo(ChannelDataOutput channel, Object value) throws
IOException {
@@ -313,17 +326,22 @@ public final class DBFField {
}
private void writeFloat(ChannelDataOutput channel, Object value) throws
IOException {
- throw new UnsupportedOperationException();
+ channel.writeFloat(((Number)value).floatValue());
}
private void writeDouble(ChannelDataOutput channel, Object value) throws
IOException {
- throw new UnsupportedOperationException();
+ channel.writeDouble(((Number)value).doubleValue());
}
private void writeOLE(ChannelDataOutput channel, Object value) throws
IOException {
throw new UnsupportedOperationException();
}
+ private void ensureLength(String str) throws IOException{
+ final int remain = fieldLength - str.length();
+ if (remain < 0) throw new IOException("Failed to write field value" +
str + ", value is larger then field " + this);
+ }
+
@Override
public String toString() {
return "DBFField{" +
diff --git
a/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
b/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
index 6fd3fcf34c..4ea5bcbb25 100644
---
a/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
+++
b/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.storage.shapefile;
+import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
@@ -23,8 +24,10 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
import org.apache.sis.util.Utilities;
@@ -48,6 +51,7 @@ import org.junit.Test;
import org.opengis.feature.AttributeType;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
+import org.opengis.filter.BinaryComparisonOperator;
import org.opengis.filter.FilterFactory;
@@ -194,8 +198,8 @@ public class ShapefileStoreTest {
*/
@Test
public void testCreate() throws URISyntaxException, DataStoreException,
IOException {
- final Path temp = Files.createTempFile("test", ".shp");
- Files.delete(temp);
+ final Path folder = Files.createTempDirectory("shapefileTest");
+ final Path temp = folder.resolve("test.shp");
final String name = temp.getFileName().toString().split("\\.")[0];
try (final ShapefileStore store = new ShapefileStore(temp)) {
Path[] componentFiles = store.getComponentFiles();
@@ -219,7 +223,6 @@ public class ShapefileStoreTest {
{// check created type
FeatureType type = store.getType();
assertEquals(name, type.getName().toString());
- System.out.println(type.toString());
assertEquals(9, type.getProperties(true).size());
assertNotNull(type.getProperty("sis:identifier"));
assertNotNull(type.getProperty("sis:envelope"));
@@ -239,17 +242,18 @@ public class ShapefileStoreTest {
assertEquals(Double.class, floatProp.getValueClass());
assertEquals(LocalDate.class, dateProp.getValueClass());
}
+ } finally {
+ deleteDirectory(folder);
}
}
/**
* Test adding features to a shapefile.
*/
- @Ignore
@Test
public void testAddFeatures() throws URISyntaxException,
DataStoreException, IOException {
- final Path temp = Files.createTempFile("test", ".shp");
- Files.delete(temp);
+ final Path folder = Files.createTempDirectory("shapefileTest");
+ final Path temp = folder.resolve("test.shp");
try (final ShapefileStore store = new ShapefileStore(temp)) {
FeatureType type = createType();
store.updateType(type);
@@ -260,27 +264,76 @@ public class ShapefileStoreTest {
store.add(List.of(feature1, feature2).iterator());
Object[] result = store.features(false).toArray();
-
-
+ assertEquals(2, result.length);
+ assertEquals(feature1, result[0]);
+ assertEquals(feature2, result[1]);
+ } finally {
+ deleteDirectory(folder);
}
}
/**
* Test remove features from a shapefile.
*/
- @Ignore
@Test
- public void testRemoveFeatures() throws URISyntaxException,
DataStoreException {
- //todo
+ public void testRemoveFeatures() throws DataStoreException, IOException {
+ final Path folder = Files.createTempDirectory("shapefileTest");
+ final Path temp = folder.resolve("test.shp");
+ try (final ShapefileStore store = new ShapefileStore(temp)) {
+ FeatureType type = createType();
+ store.updateType(type);
+ type = store.getType();
+ Feature feature1 = createFeature1(type);
+ Feature feature2 = createFeature2(type);
+ store.add(List.of(feature1, feature2).iterator());
+
+ //remove first feature
+ final FilterFactory<Feature, Object, Object> ff =
DefaultFilterFactory.forFeatures();
+ final BinaryComparisonOperator<Feature> filter =
ff.equal(ff.property("id"), ff.literal(1));
+ store.removeIf(filter);
+
+ Object[] result = store.features(false).toArray();
+ assertEquals(1, result.length);
+ assertEquals(feature2, result[0]);
+ } finally {
+ deleteDirectory(folder);
+ }
}
/**
* Test replacing features in a shapefile.
*/
- @Ignore
@Test
- public void testReplaceFeatures() throws URISyntaxException,
DataStoreException {
- //todo
+ public void testReplaceFeatures() throws DataStoreException, IOException {
+ final Path folder = Files.createTempDirectory("shapefileTest");
+ final Path temp = folder.resolve("test.shp");
+ try (final ShapefileStore store = new ShapefileStore(temp)) {
+ FeatureType type = createType();
+ store.updateType(type);
+ type = store.getType();
+ Feature feature1 = createFeature1(type);
+ Feature feature2 = createFeature2(type);
+ store.add(List.of(feature1, feature2).iterator());
+
+ //remove first feature
+ final FilterFactory<Feature, Object, Object> ff =
DefaultFilterFactory.forFeatures();
+ final BinaryComparisonOperator<Feature> filter =
ff.equal(ff.property("id"), ff.literal(1));
+ store.replaceIf(filter, new UnaryOperator<Feature>() {
+ @Override
+ public Feature apply(Feature feature) {
+ feature.setPropertyValue("id",45);
+ return feature;
+ }
+ });
+
+ Object[] result = store.features(false).toArray();
+ assertEquals(2, result.length);
+ Feature f1 = (Feature) result[0];
+ assertEquals(45, f1.getPropertyValue("id"));
+ assertEquals(feature2, result[1]);
+ } finally {
+ deleteDirectory(folder);
+ }
}
private static FeatureType createType() {
@@ -317,4 +370,12 @@ public class ShapefileStoreTest {
return feature;
}
+ private static void deleteDirectory(Path path) throws IOException{
+ try (Stream<Path> stream = Files.walk(path)) {
+ stream.sorted(Comparator.reverseOrder())
+ .map(Path::toFile)
+ .forEach(File::delete);
+ }
+ }
+
}