Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data store implementation #1327

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0cbefb9
First data store implementation
quinarygio Mar 27, 2020
4807466
Small refactoring
quinarygio Apr 9, 2020
483741c
XmlDataFormat implementation
quinarygio Apr 21, 2020
7ffaea1
Rename DirectoryDataStore
quinarygio Apr 22, 2020
31e07be
Xiidm import from data store
quinarygio Apr 30, 2020
3e4043c
MemDataStore implementation
quinarygio Apr 30, 2020
f868992
Merge branch 'master' into data_store
quinarygio May 4, 2020
327e144
XMLExporter export to data store
quinarygio May 6, 2020
8aed2a8
Compressed archive data store implementation
quinarygio May 7, 2020
5809716
Fix import from directory path
quinarygio May 13, 2020
b4113e9
Remove unused parameters
quinarygio May 19, 2020
aad07dc
UcteDtaFormat implementation
quinarygio May 19, 2020
f59bb6f
Merge branch 'master' into data_store
quinarygio Jun 10, 2020
c1f62f9
Fix sonar vulnerabilities
quinarygio Jun 10, 2020
78c6741
Fix review remarks and code smells
quinarygio Jun 10, 2020
b13c5df
Fix sonar issues
quinarygio Jun 10, 2020
142d8ab
Handle XIIDM mapping file
quinarygio Jun 11, 2020
83451a0
Increase code coverage
quinarygio Jun 11, 2020
1ced3fb
Fix bug exporting mapping file
quinarygio Jun 12, 2020
abf1cd2
Increase code coverage
quinarygio Jun 12, 2020
7ae1555
Fix copyright and author
quinarygio Jun 26, 2020
4bbb06a
Check for unique main entry.
quinarygio Jun 26, 2020
7613a58
Convert DataStore to DataSource for backward compatibility
quinarygio Jun 26, 2020
478fc8a
Subfolders not supported
quinarygio Jun 26, 2020
d9535d5
Data stores refactoring
quinarygio Jun 26, 2020
60e30c6
Fix code smells
quinarygio Jun 26, 2020
df56cf5
Merge branch 'master' into data_store
quinarygio Jul 1, 2020
64856f8
Export to data store takes a basename as input instead of filename
quinarygio Jul 3, 2020
334e55c
Avoid unnecessary zip file rewriting
quinarygio Jul 15, 2020
b91fe8d
Merge branch 'master' into data_store
quinarygio Jul 15, 2020
e781808
Merge branch 'master' into data_store
quinarygio Aug 17, 2020
6184a5c
Declare entryFilename as final
quinarygio Aug 18, 2020
884f8e0
Add javadoc
quinarygio Aug 18, 2020
8d1c9de
Remove trailing spaces in javadoc
quinarygio Aug 18, 2020
2463a3b
DataSource wrapper for a DataStore
quinarygio Aug 18, 2020
597de37
Remove toDataSource method from DataStore
quinarygio Aug 20, 2020
aa6471e
Check entry name for Gzip and Bzip stores and throw IOException if do…
quinarygio Aug 20, 2020
71f029f
Throw NetworkImportException in case of errors in network import
quinarygio Aug 20, 2020
11388c9
importDataStore methods default implementation
quinarygio Aug 25, 2020
6212993
Fix code duplication issue
quinarygio Aug 25, 2020
2c47bd0
Add importDataPack method
quinarygio Aug 31, 2020
428a52d
Fix code smell
quinarygio Aug 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
*/
class ObservableInputStream extends ForwardingInputStream<InputStream> {
public class ObservableInputStream extends ForwardingInputStream<InputStream> {

private final String streamName;

private final DataSourceObserver observer;

ObservableInputStream(InputStream is, String streamName, DataSourceObserver observer) {
public ObservableInputStream(InputStream is, String streamName, DataSourceObserver observer) {
super(is);
this.streamName = streamName;
this.observer = observer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2020, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.commons.datasource;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import com.powsybl.commons.datastore.DataStore;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public class StoreDataSource implements DataSource {

private final DataStore store;
private final String baseName;

public StoreDataSource(DataStore store, String baseName) {
this.store = Objects.requireNonNull(store);
this.baseName = Objects.requireNonNull(baseName);
}

@Override
public String getBaseName() {
return baseName;
}

@Override
public boolean exists(String suffix, String ext) throws IOException {
return store.exists(DataSourceUtil.getFileName(baseName, suffix, ext));
}

@Override
public boolean exists(String fileName) throws IOException {
return store.exists(fileName);
}

@Override
public InputStream newInputStream(String suffix, String ext) throws IOException {
return store.newInputStream(DataSourceUtil.getFileName(baseName, suffix, ext));
}

@Override
public InputStream newInputStream(String fileName) throws IOException {
return store.newInputStream(fileName);
}

@Override
public Set<String> listNames(String regex) throws IOException {
return new HashSet<>(store.getEntryNames());
}

@Override
public OutputStream newOutputStream(String fileName, boolean append) throws IOException {
return store.newOutputStream(fileName, append);
}

@Override
public OutputStream newOutputStream(String suffix, String ext, boolean append) throws IOException {
return store.newOutputStream(DataSourceUtil.getFileName(baseName, suffix, ext), append);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,17 @@
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;

import com.google.common.io.ByteStreams;
import com.powsybl.commons.io.ForwardingInputStream;
import com.powsybl.commons.io.ForwardingOutputStream;
import com.powsybl.commons.util.ZipEntryInputStream;
import com.powsybl.commons.util.ZipEntryOutputStream;

import net.java.truevfs.comp.zip.ZipEntry;
import net.java.truevfs.comp.zip.ZipFile;
import net.java.truevfs.comp.zip.ZipOutputStream;

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
Expand Down Expand Up @@ -99,23 +96,6 @@ public InputStream newInputStream(String suffix, String ext) throws IOException
return newInputStream(DataSourceUtil.getFileName(baseName, suffix, ext));
}

private static final class ZipEntryInputStream extends ForwardingInputStream<InputStream> {

private final ZipFile zipFile;

public ZipEntryInputStream(ZipFile zipFile, String fileName) throws IOException {
super(zipFile.getInputStream(fileName));
this.zipFile = zipFile;
}

@Override
public void close() throws IOException {
super.close();

zipFile.close();
}
}

@Override
public InputStream newInputStream(String fileName) throws IOException {
Objects.requireNonNull(fileName);
Expand All @@ -127,71 +107,14 @@ public InputStream newInputStream(String fileName) throws IOException {
return null;
}

private static final class ZipEntryOutputStream extends ForwardingOutputStream<ZipOutputStream> {

private final Path zipFilePath;

private final String fileName;

private boolean closed;

private ZipEntryOutputStream(Path zipFilePath, String fileName) throws IOException {
super(new ZipOutputStream(Files.newOutputStream(getTmpZipFilePath(zipFilePath))));
this.zipFilePath = zipFilePath;
this.fileName = fileName;
this.closed = false;

// create new entry
os.putNextEntry(new ZipEntry(fileName));
}

private static Path getTmpZipFilePath(Path zipFilePath) {
return zipFilePath.getParent().resolve(zipFilePath.getFileName() + ".tmp");
}

@Override
public void close() throws IOException {
if (!closed) {
// close new entry
os.closeEntry();

// copy existing entries
if (Files.exists(zipFilePath)) {
try (ZipFile zipFile = new ZipFile(zipFilePath)) {
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry zipEntry = e.nextElement();
if (!zipEntry.getName().equals(fileName)) {
os.putNextEntry(zipEntry);
try (InputStream zis = zipFile.getInputStream(zipEntry.getName())) {
ByteStreams.copy(zis, os);
}
os.closeEntry();
}
}
}
}

// close zip
super.close();

// swap with tmp zip
Path tmpZipFilePath = getTmpZipFilePath(zipFilePath);
Files.move(tmpZipFilePath, zipFilePath, StandardCopyOption.REPLACE_EXISTING);

closed = true;
}
}
}

@Override
public OutputStream newOutputStream(String fileName, boolean append) throws IOException {
Objects.requireNonNull(fileName);
if (append) {
throw new UnsupportedOperationException("append not supported in zip file data source");
}
Path zipFilePath = getZipFilePath();
OutputStream os = new ZipEntryOutputStream(zipFilePath, fileName);
OutputStream os = new ZipEntryOutputStream(zipFilePath, fileName, entryExists(zipFilePath, fileName));
return observer != null ? new ObservableOutputStream(os, zipFilePath + ":" + fileName, observer) : os;
}

Expand All @@ -217,4 +140,5 @@ public Set<String> listNames(String regex) throws IOException {
}
return names;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2020, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.commons.datastore;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;

import com.google.common.io.Files;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public abstract class AbstractDataResolver implements DataResolver {

@Override
public Optional<DataPack> resolve(ReadOnlyDataStore store, String mainFileName, Properties parameters)
throws IOException, NonUniqueResultException {
Objects.requireNonNull(store);

DataPack dp = null;
if (mainFileName != null) {
if (store.exists(mainFileName) && checkFileExtension(mainFileName)) {
dp = buildDataPack(store, mainFileName);
}
} else {
List<String> candidates = store.getEntryNames().stream().filter(this::checkFileExtension).collect(Collectors.toList());
if (candidates.size() > 1) {
throw new NonUniqueResultException("Non unique data pack found");
} else if (candidates.size() == 1) {
String entryName = candidates.get(0);
dp = buildDataPack(store, entryName);
}
}
return Optional.ofNullable(dp);
}

@Override
public boolean validate(DataPack pack, Properties properties) {
Optional<DataEntry> main = pack.getMainEntry();
return pack.getDataFormatId().equals(getDataFormat().getId()) && main.isPresent() && checkFileExtension(main.get().getName());
}

public boolean checkFileExtension(String filename) {
return getDataFormat().getExtensions().contains(Files.getFileExtension(filename));
}

private DataPack buildDataPack(ReadOnlyDataStore store, String mainFileName) {
DataPack dp = new DataPack(store, getDataFormat().getId());
DataEntry entry = new DataEntry(mainFileName, DataPack.MAIN_ENTRY_TAG);
dp.addEntry(entry);
return dp;
}

public abstract DataFormat getDataFormat();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2020, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.commons.datastore;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;

import com.powsybl.commons.datasource.Bzip2FileDataSource;
import com.powsybl.commons.datasource.DataSource;
import com.powsybl.commons.datasource.DataSourceUtil;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public class Bzip2FileDataStore implements DataStore {

private final Path path;

public Bzip2FileDataStore(Path path) {
this.path = Objects.requireNonNull(path);
}

@Override
public List<String> getEntryNames() throws IOException {
return Collections.singletonList(getEntryName());
}

@Override
public boolean exists(String entryName) {
return getEntryName().equals(entryName);
}

@Override
public InputStream newInputStream(String entryName) throws IOException {
return new BZip2CompressorInputStream(Files.newInputStream(path));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in gzip implementation, I think we should throw an IOException if the entryName does not match the registered one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

@Override
public OutputStream newOutputStream(String entryName, boolean append) throws IOException {
return new BZip2CompressorOutputStream(Files.newOutputStream(path, DataSourceUtil.getOpenOptions(append)));
}

private String getEntryName() {
String fileName = path.getFileName().toString();
return fileName.substring(0, fileName.lastIndexOf(".bz2"));
}

@Override
public DataSource toDataSource(String filename) {
return new Bzip2FileDataSource(path.getParent(), filename);
}
}
39 changes: 39 additions & 0 deletions commons/src/main/java/com/powsybl/commons/datastore/DataEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2020, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.commons.datastore;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public class DataEntry {

private final String name;

private final List<String> tags = new ArrayList<>();

public DataEntry(String name, String... tags) {
this.name = Objects.requireNonNull(name);
if (tags != null) {
mathbagu marked this conversation as resolved.
Show resolved Hide resolved
this.tags.addAll(Arrays.asList(tags));
}
}

public String getName() {
return name;
}

public List<String> getTags() {
return Collections.unmodifiableList(tags);
}

}
Loading