Author: jsorel Date: Wed Feb 14 15:18:02 2018 New Revision: 1824245 URL: http://svn.apache.org/viewvc?rev=1824245&view=rev Log: Storage : improve folder store to support add and remove operations if a specific provider is given
Added: sis/branches/JDK8/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/folder/test-data/proj.prj Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/AbstractProvider.java sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/folder/StoreTest.java Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -158,6 +158,16 @@ public final class Resources extends Ind public static final short FeatureNotFound_2 = 17; /** + * Restricted store provider identifier to use for resource discovery and creation. + */ + public static final short FolderStoreProviderParameter = 40; + + /** + * Unknown provider identifier {0}. + */ + public static final short FolderStoreProviderUnknown_1 = 41; + + /** * Whether to assemble trajectory fragments (lines in CSV file) in a single feature instance. */ public static final short FoliationRepresentation = 38; Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] Wed Feb 14 15:18:02 2018 @@ -16,7 +16,7 @@ # # -# Resources in this file are for "sis-netcdf" usage only and should not be used by any other module. +# Resources in this file are for "sis-storage" usage only and should not be used by any other module. # For resources shared by all modules in the Apache SIS project, see "org.apache.sis.util.resources" package. # AmbiguousName_4 = Name \u201c{3}\u201d is ambiguous because it can be understood as either \u201c{1}\u201d or \u201c{2}\u201d in the context of \u201c{0}\u201d data. @@ -37,6 +37,8 @@ DataStoreTimeZone = Time DirectoryContent_1 = Content of \u201c{0}\u201d directory. FeatureAlreadyPresent_2 = A feature named \u201c{1}\u201d is already present in the \u201c{0}\u201d data store. FeatureNotFound_2 = Feature \u201c{1}\u201d has not been found in the \u201c{0}\u201d data store. +FolderStoreProviderParameter = Restricted store provider identifier to use for resource discovery and creation. +FolderStoreProviderUnknown_1 = Unknown provider identifier {0}. FoliationRepresentation = Whether to assemble trajectory fragments (lines in CSV file) in a single feature instance. ExcessiveStringSize_3 = Character string in the \u201c{0}\u201d file is too long. The string has {2} characters while the limit is {1}. IllegalFeatureType_2 = The {0} data store does not accept features of type \u201c{1}\u201d. Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] Wed Feb 14 15:18:02 2018 @@ -43,6 +43,8 @@ DirectoryContent_1 = Cont ExcessiveStringSize_3 = La cha\u00eene de caract\u00e8res dans le fichier \u00ab\u202f{0}\u202f\u00bb est trop longue. La cha\u00eene fait {2} caract\u00e8res alors que la limite est {1}. FeatureAlreadyPresent_2 = Une entit\u00e9 nomm\u00e9e \u00ab\u202f{1}\u202f\u00bb est d\u00e9j\u00e0 pr\u00e9sente dans les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb. FeatureNotFound_2 = L\u2019entit\u00e9 \u00ab\u202f{1}\u202f\u00bb n\u2019a pas \u00e9t\u00e9 trouv\u00e9e dans les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb. +FolderStoreProviderParameter = Identifiant du fournisseur de donn\u00e9es unique \u00e0 utiliser pour la d\u00e9tection et la cr\u00e9ation. +FolderStoreProviderUnknown_1 = L'identifiant de fournisseur de donn\u00e9es {0} est inconnu. FoliationRepresentation = Indique s\u2019il faut assembler les fragments de trajectoires (lignes dans un fichier CSV) dans une entit\u00e9 unique. IllegalFeatureType_2 = Le format {0} ne stocke pas de donn\u00e9es de type \u00ab\u202f{1}\u202f\u00bb. IllegalInputTypeForReader_2 = Le lecteur {0} n\u2019accepte pas des entr\u00e9s de type \u2018{1}\u2019. Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -18,6 +18,9 @@ package org.apache.sis.internal.storage; import java.net.URI; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterDescriptorGroup; @@ -29,6 +32,7 @@ import org.apache.sis.storage.DataStoreP import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.IllegalOpenParameterException; import org.apache.sis.internal.storage.io.IOUtilities; +import org.apache.sis.internal.util.UnmodifiableArrayList; /** @@ -123,6 +127,12 @@ public abstract class URIDataStore exten private volatile ParameterDescriptorGroup openDescriptor; /** + * List of main file suffixes used. + */ + protected final List<String> suffix = new ArrayList<>(); + private final List<String> unSuffix = Collections.unmodifiableList(suffix); + + /** * Creates a new provider. */ protected Provider() { @@ -145,6 +155,15 @@ public abstract class URIDataStore exten } /** + * Get the list of this format mainly used file suffixes. + * + * @return list of suffix, case insensitive, never null, can be empty. + */ + public final List<String> getSuffix() { + return unSuffix; + } + + /** * Invoked by {@link #getOpenParameters()} the first time that a parameter descriptor needs * to be created. When invoked, the parameter group name is set to a name derived from the * {@link #getShortName()} value. The default implementation creates a group containing only Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -126,6 +126,7 @@ public final class StoreProvider extends * Creates a new provider. */ public StoreProvider() { + suffix.add("csv"); } /** Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -39,7 +39,7 @@ import org.apache.sis.util.logging.Loggi import org.apache.sis.internal.system.Modules; import org.apache.sis.internal.storage.Resources; import org.apache.sis.internal.storage.URIDataStore; -import org.apache.sis.setup.OptionKey; +import org.apache.sis.internal.storage.io.IOUtilities; /** @@ -60,33 +60,43 @@ public final class FolderStoreProvider e private static final String NAME = "folder"; /** + * Description of the parameter for folder location. + */ + static final ParameterDescriptor<Path> LOCATION; + + /** * Description of the parameter for formating conventions of dates and numbers. */ - private static final ParameterDescriptor<Locale> LOCALE; + static final ParameterDescriptor<Locale> LOCALE; /** * Description of the parameter for timezone of dates in the data store. */ - private static final ParameterDescriptor<TimeZone> TIMEZONE; + static final ParameterDescriptor<TimeZone> TIMEZONE; /** * Description of the parameter for character encoding used by the data store. */ - private static final ParameterDescriptor<Charset> ENCODING; + static final ParameterDescriptor<Charset> ENCODING; + + /** + * Description of the parameter for restricting searched factories. + */ + static final ParameterDescriptor<String> PROVIDER; /** * The group of parameter descriptors to be returned by {@link #getOpenParameters()}. */ static final ParameterDescriptorGroup PARAMETERS; static { - final ParameterDescriptor<Path> location; final ParameterBuilder builder = new ParameterBuilder(); final InternationalString remark = Resources.formatInternational(Resources.Keys.UsedOnlyIfNotEncoded); ENCODING = annotate(builder, URIDataStore.Provider.ENCODING, remark); LOCALE = builder.addName("locale" ).setDescription(Resources.formatInternational(Resources.Keys.DataStoreLocale )).setRemarks(remark).create(Locale.class, null); TIMEZONE = builder.addName("timezone").setDescription(Resources.formatInternational(Resources.Keys.DataStoreTimeZone)).setRemarks(remark).create(TimeZone.class, null); - location = new ParameterBuilder(URIDataStore.Provider.LOCATION_PARAM).create(Path.class, null); - PARAMETERS = builder.addName(NAME).createGroup(location, LOCALE, TIMEZONE, ENCODING); + PROVIDER = builder.addName("provider").setDescription(Resources.formatInternational(Resources.Keys.FolderStoreProviderParameter)).create(String.class, null); + LOCATION = new ParameterBuilder(URIDataStore.Provider.LOCATION_PARAM).create(Path.class, null); + PARAMETERS = builder.addName(NAME).createGroup(LOCATION, LOCALE, TIMEZONE, ENCODING, PROVIDER); } /** @@ -178,12 +188,17 @@ public final class FolderStoreProvider e @Override public DataStore open(final ParameterValueGroup parameters) throws DataStoreException { ArgumentChecks.ensureNonNull("parameter", parameters); - final StorageConnector connector = URIDataStore.Provider.connector(this, parameters); - final Parameters pg = Parameters.castOrWrap(parameters); - connector.setOption(OptionKey.LOCALE, pg.getValue(LOCALE)); - connector.setOption(OptionKey.TIMEZONE, pg.getValue(TIMEZONE)); - connector.setOption(OptionKey.ENCODING, pg.getValue(ENCODING)); - return open(connector); + final Parameters params = Parameters.castOrWrap(parameters); + try { + if (params.getValue(PROVIDER) != null) { + return new Store.Writable(this, params); + } else { + return new Store(this, params); + } + } catch (IOException e) { + throw new DataStoreException(Resources.format(Resources.Keys.CanNotReadDirectory_1, + IOUtilities.filename(params.getValue(LOCATION))), e); + } } /** Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -29,8 +29,15 @@ import java.nio.file.DirectoryStream; import java.nio.file.DirectoryIteratorException; import java.io.IOException; import java.io.UncheckedIOException; +import java.nio.file.FileVisitResult; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Map.Entry; import java.util.logging.Level; import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; +import java.util.stream.Stream; +import org.apache.sis.internal.storage.FileSystemResource; import org.opengis.metadata.Metadata; import org.opengis.metadata.maintenance.ScopeCode; import org.opengis.parameter.ParameterValueGroup; @@ -47,6 +54,16 @@ import org.apache.sis.util.collection.Ba import org.apache.sis.internal.util.UnmodifiableArrayList; import org.apache.sis.internal.storage.MetadataBuilder; import org.apache.sis.internal.storage.Resources; +import org.apache.sis.internal.storage.URIDataStore; +import org.apache.sis.metadata.iso.citation.Citations; +import org.apache.sis.parameter.Parameters; +import org.apache.sis.storage.FeatureSet; +import org.apache.sis.storage.ProbeResult; +import org.apache.sis.storage.ReadOnlyStorageException; +import org.apache.sis.storage.WritableAggregate; +import org.apache.sis.storage.WritableFeatureSet; +import org.opengis.feature.Feature; +import org.opengis.metadata.identification.Identification; /** @@ -71,32 +88,55 @@ import org.apache.sis.internal.storage.R * @since 0.8 * @module */ -final class Store extends DataStore implements Aggregate, DirectoryStream.Filter<Path> { +class Store extends DataStore implements Aggregate, DirectoryStream.Filter<Path> { + + /** + * File walker to delete file and folder recursively. + */ + private static final SimpleFileVisitor<Path> FILE_DELETE = new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }; + /** * The {@link FolderStoreProvider#LOCATION} parameter value, or {@code null} if none. */ - private final Path location; + protected final Path location; /** * Formating conventions of dates and numbers, or {@code null} if unspecified. */ - private final Locale locale; + protected final Locale locale; /** * Timezone of dates in the data store, or {@code null} if unspecified. */ - private final TimeZone timezone; + protected final TimeZone timezone; /** * Character encoding used by the data store, or {@code null} if unspecified. */ - private final Charset encoding; + protected final Charset encoding; + + /** + * Single provider to use in searches and creation operations, or {@code null} if unspecified. + */ + protected final String providerName; /** * All data stores (including sub-folders) found in the directory structure, including the root directory. * This is used for avoiding never-ending loop with symbolic links. */ - private final Map<Path,DataStore> children; + protected final Map<Path,DataStore> children; /** * Information about the data store as a whole, created when first needed. @@ -110,7 +150,7 @@ final class Store extends DataStore impl * * @see #components() */ - private transient Collection<Resource> components; + protected transient Collection<Resource> components; /** * {@code true} if {@link #sharedRepository(Path)} has already been invoked for {@link #location} path. @@ -119,6 +159,11 @@ final class Store extends DataStore impl private transient boolean sharedRepositoryReported; /** + * Cached search and create provider to use. + */ + private transient DataStoreProvider searchProvider; + + /** * Creates a new folder store from the given file, path or URI. * * @param provider the factory that created this {@code DataStore} instance, or {@code null} if unspecified. @@ -134,6 +179,18 @@ final class Store extends DataStore impl encoding = connector.getOption(OptionKey.ENCODING); children = new ConcurrentHashMap<>(); children.put(location.toRealPath(), this); + providerName = null; + } + + Store(final DataStoreProvider provider, final Parameters params) throws DataStoreException, IOException { + super(provider, new StorageConnector(params)); + location = params.getValue(FolderStoreProvider.LOCATION); + locale = params.getValue(FolderStoreProvider.LOCALE); + timezone = params.getValue(FolderStoreProvider.TIMEZONE); + encoding = params.getValue(FolderStoreProvider.ENCODING); + providerName = params.getValue(FolderStoreProvider.PROVIDER); + children = new ConcurrentHashMap<>(); + children.put(location.toRealPath(), this); } /** @@ -145,11 +202,13 @@ final class Store extends DataStore impl */ private Store(final Store parent, final StorageConnector connector) throws DataStoreException { super(parent, connector); - location = connector.getStorageAs(Path.class); - locale = connector.getOption(OptionKey.LOCALE); - timezone = connector.getOption(OptionKey.TIMEZONE); - encoding = connector.getOption(OptionKey.ENCODING); - children = parent.children; + location = connector.getStorageAs(Path.class); + locale = connector.getOption(OptionKey.LOCALE); + timezone = connector.getOption(OptionKey.TIMEZONE); + encoding = connector.getOption(OptionKey.ENCODING); + children = parent.children; + providerName = parent.providerName; + searchProvider = parent.searchProvider; } /** @@ -158,10 +217,11 @@ final class Store extends DataStore impl @Override public ParameterValueGroup getOpenParameters() { final ParameterValueGroup pg = (provider != null ? provider.getOpenParameters() : FolderStoreProvider.PARAMETERS).createValue(); - pg.parameter(FolderStoreProvider.LOCATION).setValue(location); - if (locale != null) pg.parameter("locale" ).setValue(locale ); - if (timezone != null) pg.parameter("timezone").setValue(timezone); - if (encoding != null) pg.parameter("encoding").setValue(encoding); + pg.parameter(DataStoreProvider.LOCATION).setValue(location); + if (locale != null) pg.parameter("locale" ).setValue(locale ); + if (timezone != null) pg.parameter("timezone").setValue(timezone); + if (encoding != null) pg.parameter("encoding").setValue(encoding); + if (providerName != null) pg.parameter("provider").setValue(providerName); return pg; } @@ -227,8 +287,20 @@ final class Store extends DataStore impl connector.setOption(OptionKey.LOCALE, locale); connector.setOption(OptionKey.TIMEZONE, timezone); connector.setOption(OptionKey.ENCODING, encoding); + + final DataStoreProvider provider = getSearchAndCreateProvider(); try { - next = DataStores.open(connector); + if (provider != null) { + final ProbeResult result = provider.probeContent(connector); + if (result.isSupported()) { + next = provider.open(connector); + } else { + throw new UnsupportedStorageException(); + } + } else { + next = DataStores.open(connector); + } + } catch (UnsupportedStorageException ex) { if (!Files.isDirectory(candidate)) { connector.closeAllExcept(null); @@ -273,6 +345,25 @@ final class Store extends DataStore impl } /** + * + * @return search and create provider, can be null + * @throws DataStoreException + */ + protected DataStoreProvider getSearchAndCreateProvider() throws DataStoreException { + if (searchProvider == null && providerName != null) { + for (DataStoreProvider provider : DataStores.providers()) { + if (providerName.equals(provider.getShortName())) { + searchProvider = provider; + break; + } + } + if (searchProvider == null) { + throw new DataStoreException(message(Resources.Keys.FolderStoreProviderUnknown_1, providerName)); + } + } + return searchProvider; + } + /** * Builds an error message for an error occurring while reading files in the directory. */ private String canNotRead() { @@ -327,4 +418,160 @@ final class Store extends DataStore impl } } } + + /** + * Writable version of the store which rely on given datastore provider to create new types. + * + * Note 1 : this implementation is experimental. + * Note 2 : it has not been tested since we do not have writable feature sets yet. + */ + static class Writable extends Store implements WritableAggregate { + + public Writable(DataStoreProvider provider, Parameters params) throws DataStoreException, IOException { + super(provider, params); + } + + /** + * Create a new resource. + * This implementation uses the provider given in store creation parameters. + * + * @param resource + * @return + * @throws DataStoreException + */ + @Override + public synchronized Resource add(Resource resource) throws DataStoreException { + if (!(resource instanceof FeatureSet)) { + throw new DataStoreException("Only FeatureSet resources can be imported in this store."); + } + + if (components().contains(resource)) { + throw new DataStoreException("Resource is already in this aggregate."); + } + + //we know it is not null in this instance + final DataStoreProvider provider = getSearchAndCreateProvider(); + if (!(provider instanceof URIDataStore.Provider)) { + throw new DataStoreException("Resource creation is possible only with URIProviders"); + } + + final URIDataStore.Provider p = (URIDataStore.Provider) provider; + + //build location + String fileName = null; + for (Identification id : resource.getMetadata().getIdentificationInfo()) { + fileName = Citations.getIdentifier(id.getCitation()); + if (fileName!=null && !fileName.isEmpty()) break; + } + if (fileName == null || fileName.isEmpty()) { + throw new DataStoreException("Resource does not have an identifier."); + } + + //some format may have no suffix at all + if (!p.getSuffix().isEmpty()) { + fileName += "."+ p.getSuffix().get(0); + } + + //create new store/resource + final Path location = this.location.resolve(fileName); + final StorageConnector connector = new StorageConnector(location); + connector.setOption(OptionKey.LOCALE, locale); + connector.setOption(OptionKey.TIMEZONE, timezone); + connector.setOption(OptionKey.ENCODING, encoding); + final DataStore store = p.open(connector); + + //check we can write datas + if (!(store instanceof WritableFeatureSet)) { + try { + //remove any created file + if (resource instanceof FileSystemResource) { + //delete resource files + final Path[] resourcePaths = ((FileSystemResource) resource).getResourcePaths(); + for (Path path : resourcePaths) { + Files.walkFileTree(path, FILE_DELETE); + } + } + Files.deleteIfExists(location); + } catch(IOException ex) { + //do nothing + } finally { + store.close(); + } + throw new DataStoreException("Created resource is not a WritableFeatureSet."); + } + + //copy datas between resources + children.put(location, store); + final FeatureSet source = (FeatureSet) resource; + final WritableFeatureSet target = (WritableFeatureSet) store; + target.updateType(source.getType()); + try (Stream<Feature> stream = source.features(false)) { + target.add(stream.iterator()); + } + + + //clear cache + components = null; + + return store; + } + + /** + * Note : in this implementation we clear the cache after closing the stores and before deleting the files. + * This ensure in the worse case scenario a new store will be created on the possible remaining files. + * + * @param resource + * @throws ReadOnlyStorageException + * @throws DataStoreException + */ + @Override + public synchronized void remove(Resource resource) throws ReadOnlyStorageException, DataStoreException { + if (!(components().contains(resource))) { + throw new DataStoreException("Unknown resource, verify it is part of this aggregate."); + } + + //clear cache + components = null; + + if (resource instanceof Store) { + final Store store = (Store) resource; + store.close(); + //clear cache + children.remove(store.location); + + try { + Files.walkFileTree(store.location, FILE_DELETE); + } catch (IOException ex) { + throw new DataStoreException(ex.getMessage(), ex); + } + } else { + //resource is a datastore, we are sure of it + final DataStore store = (DataStore) resource; + store.close(); + + //clear cache, we need to do this loop in case the resource is + //not a FileSystemResource or wrongly declares the used files + for (Entry<Path,DataStore> entry : children.entrySet()) { + if (entry.getValue() == store) { + children.remove(entry.getKey()); + break; + } + } + + if (resource instanceof FileSystemResource) { + //delete resource files + final Path[] resourcePaths = ((FileSystemResource) resource).getResourcePaths(); + for (Path path : resourcePaths) { + try { + Files.walkFileTree(path, FILE_DELETE); + } catch (IOException ex) { + throw new DataStoreException(ex.getMessage(), ex); + } + } + } + } + } + + } + } Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/AbstractProvider.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/AbstractProvider.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/AbstractProvider.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/AbstractProvider.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -80,6 +80,7 @@ public abstract class AbstractProvider e protected AbstractProvider(final String name, final int initialCapacity) { super(name); types = new HashMap<>(initialCapacity); + suffix.add("xml"); } /** Modified: sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/folder/StoreTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/folder/StoreTest.java?rev=1824245&r1=1824244&r2=1824245&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/folder/StoreTest.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/folder/StoreTest.java [UTF-8] Wed Feb 14 15:18:02 2018 @@ -26,6 +26,7 @@ import java.util.HashSet; import java.util.Set; import org.opengis.metadata.identification.Identification; import org.apache.sis.metadata.iso.citation.Citations; +import org.apache.sis.parameter.Parameters; import org.apache.sis.storage.Aggregate; import org.apache.sis.storage.Resource; import org.apache.sis.storage.DataStoreException; @@ -68,9 +69,9 @@ public final strictfp class StoreTest ex */ @Test public void testComponents() throws URISyntaxException, DataStoreException, IOException { - final Set<String> identifiers = new HashSet<>(Arrays.asList("Sample 1", "Sample 2", "Sample 3", "data4")); + final Set<String> identifiers = new HashSet<>(Arrays.asList("proj", "Sample 1", "Sample 2", "Sample 3", "data4")); try (Store store = new Store(null, new StorageConnector(testDirectory()))) { - assertEquals("Expected three data stores.", 3, store.components().size()); + assertEquals("Expected three data stores.", 4, store.components().size()); verifyContent(store, identifiers); } if (!identifiers.isEmpty()) { @@ -78,6 +79,31 @@ public final strictfp class StoreTest ex } } + /** + * Verify that the restricting provider parameter is used. + * + * @throws URISyntaxException if the URL to test data can not be converted to a path of the file system. + * @throws DataStoreException if an error occurred while reading the resources. + * @throws IOException if an I/O error occurs. + */ + @Test + public void testSearchProviderParameter() throws URISyntaxException, DataStoreException, IOException { + + { + final Set<String> identifiers = new HashSet<>(Arrays.asList("Sample 1", "Sample 2", "Sample 3", "data4")); + final Parameters params = Parameters.castOrWrap(FolderStoreProvider.PARAMETERS.createValue()); + params.parameter("location").setValue(testDirectory()); + params.parameter("provider").setValue("XML"); + try (Store store = new Store(null, params)) { + assertEquals("Expected three data stores.", 3, store.components().size()); + verifyContent(store, identifiers); + } + if (!identifiers.isEmpty()) { + fail("Missing resources: " + identifiers); + } + } + } + /** * Verifies that the given metadata contains one of the given identifiers. * The identifiers that are found are removed from the given set. Added: sis/branches/JDK8/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/folder/test-data/proj.prj URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/folder/test-data/proj.prj?rev=1824245&view=auto ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/folder/test-data/proj.prj (added) +++ sis/branches/JDK8/storage/sis-storage/src/test/resources/org/apache/sis/internal/storage/folder/test-data/proj.prj Wed Feb 14 15:18:02 2018 @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file