This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/sis.git
commit fafbe8a7b643a4994eb5fe2917721e380d381af2 Merge: ed9308d56c 2bffeac5a6 Author: Martin Desruisseaux <[email protected]> AuthorDate: Mon Nov 6 12:37:23 2023 +0100 Merge branch 'geoapi-3.1' endorsed/build.gradle.kts | 3 +- .../org.apache.sis.feature/main/module-info.java | 1 + .../grid/BandAggregateGridCoverageTest.java | 4 +- .../coverage/grid/ConvertedGridCoverageTest.java | 6 +- .../coverage/grid/DimensionalityReductionTest.java | 2 +- .../sis/coverage/grid/GridCoverage2DTest.java | 4 +- .../sis/coverage/grid/GridCoverageBuilderTest.java | 2 +- .../sis/coverage/grid/GridDerivationTest.java | 8 +- .../apache/sis/coverage/grid/GridExtentTest.java | 2 +- .../apache/sis/coverage/grid/GridGeometryTest.java | 8 +- .../coverage/grid/ResampledGridCoverageTest.java | 8 +- .../sis/coverage/grid/ReshapedImageTest.java | 6 +- .../coverage/grid/TranslatedGridCoverageTest.java | 2 +- .../apache/sis/feature/EnvelopeOperationTest.java | 2 +- .../apache/sis/feature/FeatureOperationsTest.java | 6 +- .../feature/builder/FeatureTypeBuilderTest.java | 8 +- .../feature/internal/AttributeConventionTest.java | 2 +- .../sis/filter/BinarySpatialFilterTestCase.java | 4 +- .../apache/sis/filter/sqlmm/RegistryTestCase.java | 4 +- .../org/apache/sis/filter/sqlmm/SQLMMTest.java | 2 +- .../sis/geometry/wrapper/GeometriesTestCase.java | 4 +- .../org/apache/sis/image/ResamplingGridTest.java | 4 +- .../apache/sis/metadata/MetadataCopierTest.java | 4 +- .../apache/sis/metadata/MetadataStandardTest.java | 6 +- .../apache/sis/metadata/PropertyAccessorTest.java | 14 +- .../sis/metadata/PropertyInformationTest.java | 2 +- .../org/apache/sis/metadata/SpecialCasesTest.java | 6 +- .../sis/metadata/sql/IdentifierGeneratorTest.java | 1 - .../sis/metadata/sql/MetadataWriterTest.java | 4 +- .../xml/bind/fra/DirectReferenceSystemTest.java | 4 +- .../apache/sis/geometry/AbstractEnvelopeTest.java | 6 +- .../org/apache/sis/geometry/ArrayEnvelopeTest.java | 4 +- .../apache/sis/geometry/CoordinateFormatTest.java | 6 +- .../org/apache/sis/geometry/Envelope2DTest.java | 2 +- .../org/apache/sis/geometry/EnvelopesTest.java | 2 +- .../sis/geometry/GeneralDirectPositionTest.java | 2 +- .../apache/sis/geometry/GeneralEnvelopeTest.java | 4 +- .../apache/sis/geometry/ImmutableEnvelopeTest.java | 2 +- .../org/apache/sis/geometry/SubEnvelopeTest.java | 2 +- .../org/apache/sis/geometry/TransformTestCase.java | 8 +- .../sis/geometry/WraparoundAdjustmentTest.java | 4 +- .../sis/referencing/AuthorityFactoriesTest.java | 4 +- .../test/org/apache/sis/referencing/CRSTest.java | 6 +- .../sis/referencing/GeodesicsOnEllipsoidTest.java | 2 +- .../sis/referencing/GeodeticCalculatorTest.java | 2 +- .../sis/referencing/IdentifiedObjectsTest.java | 2 +- .../sis/referencing/StandardDefinitionsTest.java | 10 +- .../sis/referencing/crs/AbstractCRSTest.java | 4 +- .../referencing/crs/DefaultCompoundCRSTest.java | 4 +- .../sis/referencing/crs/DefaultDerivedCRSTest.java | 4 +- .../referencing/crs/DefaultEngineeringCRSTest.java | 2 +- .../sis/referencing/crs/DefaultImageCRSTest.java | 4 +- .../referencing/crs/DefaultProjectedCRSTest.java | 2 +- .../referencing/crs/DefaultTemporalCRSTest.java | 2 +- .../apache/sis/referencing/crs/HardCodedCRS.java | 4 +- .../sis/referencing/crs/HardCodedCRSTest.java | 2 +- .../datum/DefaultTemporalDatumTest.java | 2 +- .../sis/referencing/datum/HardCodedDatum.java | 4 +- .../referencing/factory/AuthorityFactoryMock.java | 2 + .../factory/MultiAuthoritiesFactoryTest.java | 6 +- .../internal/ServicesForMetadataTest.java | 2 +- .../operation/CoordinateOperationFinderTest.java | 4 +- .../DefaultConcatenatedOperationTest.java | 4 +- .../operation/DefaultConversionTest.java | 12 +- .../operation/DefaultTransformationTest.java | 8 +- .../operation/HardCodedConversions.java | 2 + .../builder/LinearTransformBuilderTest.java | 6 +- .../operation/builder/LinearizerTest.java | 4 +- .../operation/provider/GeographicOffsetsTest.java | 2 +- .../transform/AbridgedMolodenskyTransformTest.java | 4 +- .../transform/CoordinateSystemTransformTest.java | 2 +- .../transform/DefaultMathTransformFactoryTest.java | 8 +- .../InterpolatedGeocentricTransformTest.java | 2 +- .../transform/MathTransformFactoryBase.java | 2 + .../transform/MolodenskyTransformTest.java | 4 +- .../transform/TransformSeparatorTest.java | 6 +- .../transform/WraparoundTransformTest.java | 2 +- .../sis/referencing/util/AxesMapperTest.java | 2 +- .../sis/referencing/util/AxisDirectionsTest.java | 4 +- .../referencing/util/CoordinateOperationsTest.java | 10 +- .../referencing/util/DefinitionVerifierTest.java | 10 +- .../util/EllipsoidalHeightCombinerTest.java | 8 +- .../apache/sis/referencing/util/FormulasTest.java | 2 +- .../referencing/util/ReferencingUtilitiesTest.java | 4 +- .../sis/referencing/util/WKTUtilitiesTest.java | 4 +- .../referencing/util/WraparoundApplicatorTest.java | 3 +- .../main/module-info.java | 2 +- .../apache/sis/storage/geotiff/Compression.java | 241 ++++++++ .../{GeoTiffOption.java => FormatModifier.java} | 39 +- .../apache/sis/storage/geotiff/GeoTiffStore.java | 66 +- .../sis/storage/geotiff/GeoTiffStoreProvider.java | 16 +- .../org/apache/sis/storage/geotiff/IOBase.java | 6 +- .../org/apache/sis/storage/geotiff/Reader.java | 6 +- .../org/apache/sis/storage/geotiff/Writer.java | 80 ++- .../sis/storage/geotiff/base/Compression.java | 15 +- .../apache/sis/storage/geotiff/base/Predictor.java | 41 +- .../storage/geotiff/inflater/CopyFromBytes.java | 91 ++- .../geotiff/inflater/HorizontalPredictor.java | 4 +- .../sis/storage/geotiff/inflater/Inflater.java | 2 +- .../storage/geotiff/inflater/PredictorChannel.java | 2 + .../storage/geotiff/writer/CompressionChannel.java | 116 ++++ .../geotiff/writer/HorizontalPredictor.java | 390 ++++++++++++ .../sis/storage/geotiff/writer/PixelChannel.java | 60 ++ .../storage/geotiff/writer/PredictorChannel.java | 86 +++ .../sis/storage/geotiff/writer/TileMatrix.java | 185 ++++-- .../org/apache/sis/storage/geotiff/writer/ZIP.java | 120 ++++ .../org/apache/sis/storage/geotiff/WriterTest.java | 76 +-- .../storage/sql/feature/GeometryGetterTest.java | 2 +- .../sql/feature/SelectionClauseWriterTest.java | 2 +- .../sql/feature/TemporalValueGetterTest.java | 4 +- .../sis/storage/sql/postgis/PostgresTest.java | 2 +- .../org.apache.sis.storage/main/module-info.java | 1 + .../main/org/apache/sis/io/stream/ChannelData.java | 4 + .../apache/sis/io/stream/ChannelDataOutput.java | 10 + .../sis/io/stream/ChannelImageOutputStream.java | 14 + .../apache/sis/io/stream/FileCacheByteChannel.java | 5 +- .../apache/sis/io/stream/HyperRectangleWriter.java | 361 ++++++++--- .../apache/sis/io/stream/RewindableLineReader.java | 2 +- .../org/apache/sis/storage/StorageConnector.java | 141 +++-- .../main/org/apache/sis/storage/csv/Store.java | 6 +- .../apache/sis/storage/wkt/FirstKeywordPeek.java | 4 +- .../org/apache/sis/storage/CoverageQueryTest.java | 2 +- .../org/apache/sis/storage/CoverageSubsetTest.java | 2 +- .../aggregate/BandAggregateGridResourceTest.java | 2 +- .../sis/storage/base/MemoryGridResourceTest.java | 2 +- .../sis/storage/esri/BSQConsistencyTest.java | 2 +- .../apache/sis/storage/esri/WritableStoreTest.java | 2 +- .../src/org.apache.sis.util/main/module-info.java | 1 + .../main/org/apache/sis/util/ArgumentChecks.java | 22 +- .../org/apache/sis/util/resources/Vocabulary.java | 5 + .../sis/util/resources/Vocabulary.properties | 1 + .../sis/util/resources/Vocabulary_fr.properties | 1 + .../main/module-info.java | 2 + .../sis/storage/shapefile/ShapefileProvider.java | 82 +++ .../sis/storage/shapefile/ShapefileStore.java | 385 ++++++++++++ .../apache/sis/storage/shapefile/dbf/DBFField.java | 120 ++++ .../sis/storage/shapefile/dbf/DBFFieldEncoder.java | 206 +++++++ .../sis/storage/shapefile/dbf/DBFHeader.java | 78 +++ .../sis/storage/shapefile/dbf/DBFReader.java | 87 +++ .../sis/storage/shapefile/dbf/DBFRecord.java} | 20 +- .../shapefile/shp/ShapeGeometryEncoder.java | 677 +++++++++++++++++++++ .../sis/storage/shapefile/shp/ShapeHeader.java | 113 ++++ .../sis/storage/shapefile/shp/ShapeReader.java | 66 ++ .../sis/storage/shapefile/shp/ShapeRecord.java | 78 +++ .../sis/storage/shapefile/shp/ShapeType.java | 89 +++ .../sis/storage/shapefile/shp/ShapeWriter.java | 65 ++ .../sis/storage/shapefile/shx/IndexReader.java | 66 ++ .../sis/storage/shapefile/ShapefileStoreTest.java | 90 +++ .../sis/storage/shapefile/dbf/DBFIOTest.java | 104 ++++ .../apache/sis/storage/shapefile/multipoint.cpg | 1 + .../apache/sis/storage/shapefile/multipoint.dbf | Bin 0 -> 88 bytes .../apache/sis/storage/shapefile/multipoint.prj | 1 + .../apache/sis/storage/shapefile/multipoint.shp | Bin 0 -> 260 bytes .../apache/sis/storage/shapefile/multipoint.shx | Bin 0 -> 116 bytes .../org/apache/sis/storage/shapefile/point.cpg | 1 + .../org/apache/sis/storage/shapefile/point.dbf | Bin 0 -> 434 bytes .../org/apache/sis/storage/shapefile/point.prj | 1 + .../org/apache/sis/storage/shapefile/point.shp | Bin 0 -> 156 bytes .../org/apache/sis/storage/shapefile/point.shx | Bin 0 -> 116 bytes .../org/apache/sis/storage/shapefile/polygon.cpg | 1 + .../org/apache/sis/storage/shapefile/polygon.dbf | Bin 0 -> 88 bytes .../org/apache/sis/storage/shapefile/polygon.prj | 1 + .../org/apache/sis/storage/shapefile/polygon.shp | Bin 0 -> 456 bytes .../org/apache/sis/storage/shapefile/polygon.shx | Bin 0 -> 116 bytes .../org/apache/sis/storage/shapefile/polyline.cpg | 1 + .../org/apache/sis/storage/shapefile/polyline.dbf | Bin 0 -> 88 bytes .../org/apache/sis/storage/shapefile/polyline.prj | 1 + .../org/apache/sis/storage/shapefile/polyline.shp | Bin 0 -> 328 bytes .../org/apache/sis/storage/shapefile/polyline.shx | Bin 0 -> 116 bytes .../sis/storage/shapefile/shp/ShapeIOTest.java | 319 ++++++++++ .../apache/sis/gui/coverage/CoverageCanvasApp.java | 4 +- .../org/apache/sis/gui/coverage/GridViewApp.java | 4 +- 172 files changed, 4715 insertions(+), 556 deletions(-) diff --cc endorsed/src/org.apache.sis.referencing/test/org/apache/sis/geometry/AbstractEnvelopeTest.java index 7495875e05,4b14655648..57d0622432 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/geometry/AbstractEnvelopeTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/geometry/AbstractEnvelopeTest.java @@@ -32,10 -31,8 +31,11 @@@ import static org.junit.Assert.* import static org.opengis.test.Validators.validate; import static org.apache.sis.referencing.Assertions.assertContains; import static org.apache.sis.referencing.Assertions.assertDisjoint; + import static org.apache.sis.referencing.crs.HardCodedCRS.WGS84; +// Specific to the main branch: +import static org.apache.sis.test.GeoapiAssert.PENDING_NEXT_GEOAPI_RELEASE; + /** * Tests the methods defined in the {@link AbstractEnvelope} class. diff --cc endorsed/src/org.apache.sis.util/main/module-info.java index 3394402ebf,afebada7be..29dc1fd8dd --- a/endorsed/src/org.apache.sis.util/main/module-info.java +++ b/endorsed/src/org.apache.sis.util/main/module-info.java @@@ -127,6 -127,8 +127,7 @@@ module org.apache.sis.util org.apache.sis.storage.netcdf, org.apache.sis.storage.geotiff, org.apache.sis.storage.earthobservation, + org.apache.sis.storage.shapefile, // In the "incubator" sub-project. - org.apache.sis.cql, // In the "incubator" sub-project. org.apache.sis.portrayal, org.apache.sis.cloud.aws, org.apache.sis.console, diff --cc incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java index 0000000000,33c46f120d..04774dfc66 mode 000000,100644..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 @@@ -1,0 -1,385 +1,385 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.sis.storage.shapefile; + + import java.io.IOException; + import java.nio.ByteBuffer; + import java.nio.channels.SeekableByteChannel; + import java.nio.channels.WritableByteChannel; + import java.nio.charset.Charset; + import java.nio.charset.StandardCharsets; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.StandardOpenOption; + import java.util.Iterator; + import java.util.Optional; + import java.util.Spliterator; + import java.util.Spliterators; + import java.util.concurrent.locks.ReadWriteLock; + import java.util.concurrent.locks.ReentrantReadWriteLock; + import java.util.function.Consumer; + import java.util.function.Predicate; + import java.util.function.UnaryOperator; + import java.util.stream.Stream; + import java.util.stream.StreamSupport; + import org.opengis.geometry.Envelope; + import org.opengis.metadata.Metadata; + import org.opengis.parameter.ParameterValueGroup; + import org.opengis.referencing.crs.CoordinateReferenceSystem; + import org.opengis.util.FactoryException; + import org.opengis.util.GenericName; + import org.apache.sis.feature.builder.AttributeRole; + import org.apache.sis.feature.builder.AttributeTypeBuilder; + import org.apache.sis.feature.builder.FeatureTypeBuilder; + import org.apache.sis.io.stream.ChannelDataInput; + import org.apache.sis.io.stream.ChannelDataOutput; + import org.apache.sis.io.stream.IOUtilities; + import org.apache.sis.parameter.Parameters; + import org.apache.sis.referencing.CRS; + import org.apache.sis.referencing.CommonCRS; + import org.apache.sis.storage.AbstractFeatureSet; + import org.apache.sis.storage.DataStore; + import org.apache.sis.storage.DataStoreException; + import org.apache.sis.storage.FeatureSet; + import org.apache.sis.storage.Query; + import org.apache.sis.storage.UnsupportedQueryException; + import org.apache.sis.storage.WritableFeatureSet; + import org.apache.sis.storage.shapefile.cpg.CpgFiles; + import org.apache.sis.storage.shapefile.dbf.DBFField; + import org.apache.sis.storage.shapefile.dbf.DBFHeader; + import org.apache.sis.storage.shapefile.dbf.DBFReader; + import org.apache.sis.storage.shapefile.dbf.DBFRecord; + import org.apache.sis.storage.shapefile.shp.ShapeGeometryEncoder; + import org.apache.sis.storage.shapefile.shp.ShapeHeader; + import org.apache.sis.storage.shapefile.shp.ShapeReader; + import org.apache.sis.storage.shapefile.shp.ShapeRecord; + import org.apache.sis.util.collection.BackingStoreException; + -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.feature.Feature; -import org.opengis.feature.FeatureType; ++// Specific to the main branch: ++import org.apache.sis.feature.AbstractFeature; ++import org.apache.sis.feature.DefaultFeatureType; + + + /** + * Shapefile datastore. + * + * @author Johann Sorel (Geomatys) + */ + public final class ShapefileStore extends DataStore implements FeatureSet { + + private static final String GEOMETRY_NAME = "geometry"; + + private final Path shpPath; + private final ShpFiles files; + /** + * Internal class to inherit AbstractFeatureSet. + */ + private final AsFeatureSet featureSetView = new AsFeatureSet(); - private FeatureType type; ++ private DefaultFeatureType type; + private Charset charset; + + /** + * Lock to control read and write operations. + */ + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + public ShapefileStore(Path path) { + this.shpPath = path; + this.files = new ShpFiles(shpPath); + } + + @Override + public Optional<ParameterValueGroup> getOpenParameters() { + final Parameters parameters = Parameters.castOrWrap(ShapefileProvider.PARAMETERS_DESCRIPTOR.createValue()); + parameters.parameter(ShapefileProvider.LOCATION).setValue(shpPath.toUri()); + return Optional.of(parameters); + } + + @Override + public void close() throws DataStoreException { + } + + + /* + Redirect FeatureSet interface to View + */ + @Override + public Optional<GenericName> getIdentifier() throws DataStoreException { + return featureSetView.getIdentifier(); + } + + @Override + public Metadata getMetadata() throws DataStoreException { + return featureSetView.getMetadata(); + } + + @Override - public FeatureType getType() throws DataStoreException { ++ public DefaultFeatureType getType() throws DataStoreException { + return featureSetView.getType(); + } + + @Override + public FeatureSet subset(Query query) throws UnsupportedQueryException, DataStoreException { + return featureSetView.subset(query); + } + + @Override - public Stream<Feature> features(boolean parallel) throws DataStoreException { ++ public Stream<AbstractFeature> features(boolean parallel) throws DataStoreException { + return featureSetView.features(parallel); + } + + @Override + public Optional<Envelope> getEnvelope() throws DataStoreException { + return featureSetView.getEnvelope(); + } + + private class AsFeatureSet extends AbstractFeatureSet implements WritableFeatureSet { + + private AsFeatureSet() { + super(null); + } + + @Override - public synchronized FeatureType getType() throws DataStoreException { ++ public synchronized DefaultFeatureType getType() throws DataStoreException { + if (type == null) { + if (!Files.isRegularFile(shpPath)) { + throw new DataStoreException("Shape files do not exist. Update FeatureType first to initialize this empty datastore"); + } + + final FeatureTypeBuilder ftb = new FeatureTypeBuilder(); + ftb.setName(files.baseName); + + //read shp header to obtain geometry type + final Class geometryClass; + try (final ShapeReader reader = new ShapeReader(ShpFiles.openReadChannel(shpPath))) { + final ShapeHeader header = reader.getHeader(); + geometryClass = ShapeGeometryEncoder.getEncoder(header.shapeType).getValueClass(); + } catch (IOException ex) { + throw new DataStoreException("Failed to parse shape file header.", ex); + } + + //read prj file for projection + final Path prjFile = files.getPrj(false); + final CoordinateReferenceSystem crs; + if (prjFile != null) { + try { + crs = CRS.fromWKT(Files.readString(prjFile, StandardCharsets.UTF_8)); + } catch (IOException | FactoryException ex) { + throw new DataStoreException("Failed to parse prj file.", ex); + } + } else { + //shapefile often do not have a .prj, mostly those are in CRS:84. + //we do not raise an error otherwise we would not be able to read a lot of data. + crs = CommonCRS.WGS84.normalizedGeographic(); + } + + ftb.addAttribute(geometryClass).setName(GEOMETRY_NAME).setCRS(crs).addRole(AttributeRole.DEFAULT_GEOMETRY); + + //read cpg for dbf file charset + final Path cpgFile = files.getCpg(false); + if (cpgFile != null) { + try (final SeekableByteChannel channel = Files.newByteChannel(cpgFile, StandardOpenOption.READ)) { + charset = CpgFiles.read(channel); + } catch (IOException ex) { + throw new DataStoreException("Failed to parse cpg file.", ex); + } + } else { + charset = StandardCharsets.UTF_8; + } + + //read dbf for attributes + final Path dbfFile = files.getDbf(false); + if (dbfFile != null) { + try (DBFReader reader = new DBFReader(ShpFiles.openReadChannel(dbfFile), charset)) { + final DBFHeader header = reader.getHeader(); + boolean hasId = false; + for (DBFField field : header.fields) { + final AttributeTypeBuilder atb = ftb.addAttribute(field.getEncoder().getValueClass()).setName(field.fieldName); + //no official but 'id' field is common + if (!hasId && "id".equalsIgnoreCase(field.fieldName) || "identifier".equalsIgnoreCase(field.fieldName)) { + atb.addRole(AttributeRole.IDENTIFIER_COMPONENT); + hasId = true; + } + } + } catch (IOException ex) { + throw new DataStoreException("Failed to parse dbf file header.", ex); + } + } else { + throw new DataStoreException("DBF file is missing."); + } + + type = ftb.build(); + } + return type; + } + + @Override - public Stream<Feature> features(boolean parallel) throws DataStoreException { - final FeatureType type = getType(); ++ public Stream<AbstractFeature> features(boolean parallel) throws DataStoreException { ++ final DefaultFeatureType type = getType(); + final ShapeReader shpreader; + final DBFReader dbfreader; + try { + shpreader = new ShapeReader(ShpFiles.openReadChannel(files.shpFile)); + dbfreader = new DBFReader(ShpFiles.openReadChannel(files.getDbf(false)), charset); + } catch (IOException ex) { + throw new DataStoreException("Faild to open shp and dbf files.", ex); + } + final DBFHeader header = dbfreader.getHeader(); + + final Spliterator spliterator = new Spliterators.AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { + @Override + public boolean tryAdvance(Consumer action) { + try { + final ShapeRecord shpRecord = shpreader.next(); + if (shpRecord == null) return false; + final DBFRecord dbfRecord = dbfreader.next(); - final Feature next = type.newInstance(); ++ final AbstractFeature next = type.newInstance(); + next.setPropertyValue(GEOMETRY_NAME, shpRecord.geometry); + for (int i = 0; i < header.fields.length; i++) { + next.setPropertyValue(header.fields[i].fieldName, dbfRecord.fields[i]); + } + action.accept(next); + return true; + } catch (IOException ex) { + throw new BackingStoreException(ex.getMessage(), ex); + } + } + }; - final Stream<Feature> stream = StreamSupport.stream(spliterator, false); ++ final Stream<AbstractFeature> stream = StreamSupport.stream(spliterator, false); + return stream.onClose(new Runnable() { + @Override + public void run() { + try { + shpreader.close(); + dbfreader.close(); + } catch (IOException ex) { + throw new BackingStoreException(ex.getMessage(), ex); + } + } + }); + + } + + @Override - public void updateType(FeatureType newType) throws DataStoreException { ++ public void updateType(DefaultFeatureType newType) throws DataStoreException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override - public void add(Iterator<? extends Feature> features) throws DataStoreException { ++ public void add(Iterator<? extends AbstractFeature> features) throws DataStoreException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override - public void removeIf(Predicate<? super Feature> filter) throws DataStoreException { ++ public void removeIf(Predicate<? super AbstractFeature> filter) throws DataStoreException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override - public void replaceIf(Predicate<? super Feature> filter, UnaryOperator<Feature> updater) throws DataStoreException { ++ public void replaceIf(Predicate<? super AbstractFeature> filter, UnaryOperator<AbstractFeature> updater) throws DataStoreException { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + /** + * Manipulate the different shape files. + */ + private static class ShpFiles { + + private final String baseName; + private final boolean baseUpper; + private final Path shpFile; + private Path shxFile; + private Path dbfFile; + private Path prjFile; + private Path cpgFile; + + public ShpFiles(Path shpFile) { + this.shpFile = shpFile; + final String fileName = shpFile.getFileName().toString(); + baseUpper = Character.isUpperCase(fileName.codePointAt(fileName.length()-1)); + this.baseName = IOUtilities.filenameWithoutExtension(fileName); + shxFile = findSibling("shx"); + dbfFile = findSibling("dbf"); + prjFile = findSibling("prj"); + cpgFile = findSibling("cpg"); + } + + /** + * @param create true to create the path even if file do not exist. + * @return file if it exist or create is true, null otherwise + */ + public Path getShx(boolean create) { + if (create && shxFile == null) { + return shpFile.getParent().resolve(baseName + "." + (baseUpper ? "SHX" : "shx")); + } + return shxFile; + } + + /** + * @param create true to create the path even if file do not exist. + * @return file if it exist or create is true, null otherwise + */ + public Path getDbf(boolean create) { + if (create && dbfFile == null) { + return shpFile.getParent().resolve(baseName + "." + (baseUpper ? "DBF" : "dbf")); + } + return dbfFile; + } + + /** + * @param create true to create the path even if file do not exist. + * @return file if it exist or create is true, null otherwise + */ + public Path getPrj(boolean create) { + if (create && prjFile == null) { + return shpFile.getParent().resolve(baseName + "." + (baseUpper ? "PRJ" : "prj")); + } + return prjFile; + } + + /** + * @param create true to create the path even if file do not exist. + * @return file if it exist or create is true, null otherwise + */ + public Path getCpg(boolean create) { + if (create && cpgFile == null) { + return shpFile.getParent().resolve(baseName + "." + (baseUpper ? "CPG" : "cpg")); + } + return cpgFile; + } + + private Path findSibling(String extension) { + Path candidate = shpFile.getParent().resolve(baseName + "." + extension); + if (java.nio.file.Files.isRegularFile(candidate)) return candidate; + candidate = shpFile.getParent().resolve(baseName + "." + extension.toUpperCase()); + if (java.nio.file.Files.isRegularFile(candidate)) return candidate; + return null; + } + + private static ChannelDataInput openReadChannel(Path path) throws IOException { + final SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.READ); + return new ChannelDataInput(path.getFileName().toString(), channel, ByteBuffer.allocate(8192), false); + } + + private static ChannelDataOutput openWriteChannel(Path path) throws IOException, IllegalArgumentException, DataStoreException { + final WritableByteChannel wbc = Files.newByteChannel(path, StandardOpenOption.WRITE); + return new ChannelDataOutput(path.getFileName().toString(), wbc, ByteBuffer.allocate(8000)); + } + } + + } diff --cc incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java index 0000000000,0cdb00b890..9eb5e07bea mode 000000,100644..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 @@@ -1,0 -1,90 +1,90 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.sis.storage.shapefile; + + import java.net.URISyntaxException; + import java.net.URL; + import java.nio.file.Paths; + import java.time.LocalDate; + import java.util.Iterator; + import java.util.stream.Stream; + import static org.junit.jupiter.api.Assertions.*; + import org.apache.sis.storage.DataStoreException; + import org.junit.Test; + import org.locationtech.jts.geom.Point; + -// Specific to the geoapi-3.1 and geoapi-4.0 branches: -import org.opengis.feature.AttributeType; -import org.opengis.feature.Feature; -import org.opengis.feature.FeatureType; ++// Specific to the main branch: ++import org.apache.sis.feature.AbstractFeature; ++import org.apache.sis.feature.DefaultFeatureType; ++import org.apache.sis.feature.DefaultAttributeType; + + + /** + * + * @author Johann Sorel (Geomatys) + */ + public class ShapefileStoreTest { + + @Test + public void testStream() throws URISyntaxException, DataStoreException { + final URL url = ShapefileStoreTest.class.getResource("/org/apache/sis/storage/shapefile/point.shp"); + final ShapefileStore store = new ShapefileStore(Paths.get(url.toURI())); + + //check feature type - final FeatureType type = store.getType(); ++ final DefaultFeatureType type = store.getType(); + assertEquals("point", type.getName().toString()); + assertEquals(9, type.getProperties(true).size()); + assertNotNull(type.getProperty("sis:identifier")); + assertNotNull(type.getProperty("sis:envelope")); + assertNotNull(type.getProperty("sis:geometry")); - final var geomProp = (AttributeType) type.getProperty("geometry"); - final var idProp = (AttributeType) type.getProperty("id"); - final var textProp = (AttributeType) type.getProperty("text"); - final var integerProp = (AttributeType) type.getProperty("integer"); - final var floatProp = (AttributeType) type.getProperty("float"); - final var dateProp = (AttributeType) type.getProperty("date"); ++ final var geomProp = (DefaultAttributeType) type.getProperty("geometry"); ++ final var idProp = (DefaultAttributeType) type.getProperty("id"); ++ final var textProp = (DefaultAttributeType) type.getProperty("text"); ++ final var integerProp = (DefaultAttributeType) type.getProperty("integer"); ++ final var floatProp = (DefaultAttributeType) type.getProperty("float"); ++ final var dateProp = (DefaultAttributeType) type.getProperty("date"); + assertEquals(Point.class, geomProp.getValueClass()); + assertEquals(Long.class, idProp.getValueClass()); + assertEquals(String.class, textProp.getValueClass()); + assertEquals(Long.class, integerProp.getValueClass()); + assertEquals(Double.class, floatProp.getValueClass()); + assertEquals(LocalDate.class, dateProp.getValueClass()); + - try (Stream<Feature> stream = store.features(false)) { - Iterator<Feature> iterator = stream.iterator(); ++ try (Stream<AbstractFeature> stream = store.features(false)) { ++ Iterator<AbstractFeature> iterator = stream.iterator(); + assertTrue(iterator.hasNext()); - Feature feature1 = iterator.next(); ++ AbstractFeature feature1 = iterator.next(); + assertEquals(1L, feature1.getPropertyValue("id")); + assertEquals("text1", feature1.getPropertyValue("text")); + assertEquals(10L, feature1.getPropertyValue("integer")); + assertEquals(20.0, feature1.getPropertyValue("float")); + assertEquals(LocalDate.of(2023, 10, 27), feature1.getPropertyValue("date")); + Point pt1 = (Point) feature1.getPropertyValue("geometry"); + + assertTrue(iterator.hasNext()); - Feature feature2 = iterator.next(); ++ AbstractFeature feature2 = iterator.next(); + assertEquals(2L, feature2.getPropertyValue("id")); + assertEquals("text2", feature2.getPropertyValue("text")); + assertEquals(40L, feature2.getPropertyValue("integer")); + assertEquals(60.0, feature2.getPropertyValue("float")); + assertEquals(LocalDate.of(2023, 10, 28), feature2.getPropertyValue("date")); + Point pt2 = (Point) feature2.getPropertyValue("geometry"); + + assertFalse(iterator.hasNext()); + } + } + }
