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 14 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,66 @@
/**
* 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(a -> checkFileExtension(a)).collect(Collectors.toList());
if (candidates.size() > 1) {
throw new NonUniqueResultException();
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved
} 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(getDataFormatId()) && main.isPresent() && checkFileExtension(main.get().getName());
}

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

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

public abstract String getDataFormatId();

public abstract List<String> getExtensions();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* 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.DataSourceUtil;

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

private final Path path;

public Bzip2FileDataStore(Path path) {
Objects.requireNonNull(path);
this.path = path;
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved
}

@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"));
}
}
38 changes: 38 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,38 @@
/**
* 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.List;
import java.util.Objects;

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

private String name;
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved

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 tags;
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* 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;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public interface DataFormat {
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved

public String getId();
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved

public String getDescription();

public DataResolver getDataResolver();

}
76 changes: 76 additions & 0 deletions commons/src/main/java/com/powsybl/commons/datastore/DataPack.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* 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.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import com.google.common.io.ByteStreams;

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

public static final String MAIN_ENTRY_TAG = "MAIN_ENTRY";

private final String dataFormatId;

private final ReadOnlyDataStore source;

private final List<DataEntry> entries;

public DataPack(ReadOnlyDataStore source, String formatId) {
this.source = Objects.requireNonNull(source);
this.dataFormatId = Objects.requireNonNull(formatId);
this.entries = new ArrayList<>();
}

public List<DataEntry> getEntries() {
return entries;
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved
}

public void addEntry(DataEntry entry) {
entries.add(entry);
}

public Optional<DataEntry> getEntry(String entryName) {
Objects.requireNonNull(entryName);
return entries.stream().filter(e -> e.getName().equals(entryName)).findFirst();
}

public Optional<DataEntry> getMainEntry() {
return entries.stream().filter(e -> e.getTags().contains(MAIN_ENTRY_TAG)).findFirst();
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved
}

public ReadOnlyDataStore getSource() {
return source;
}

public DataPack copyTo(DataStore target) throws IOException {
Objects.requireNonNull(target);
DataPack copy = new DataPack(target, dataFormatId);
for (DataEntry e : entries) {
try (InputStream in = source.newInputStream(e.getName()); OutputStream out = target.newOutputStream(e.getName(), false)) {
ByteStreams.copy(in, out);
}
copy.addEntry(e);
}

return copy;
}

public String getDataFormatId() {
return dataFormatId;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* 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.Optional;
import java.util.Properties;

import javax.annotation.Nullable;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public interface DataResolver {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add javadoc to explain the contract of this interface.


public Optional<DataPack> resolve(ReadOnlyDataStore store, @Nullable String mainFileName, @Nullable Properties parameters) throws IOException, NonUniqueResultException;
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved

public boolean validate(DataPack pack, @Nullable Properties parameters);
}
19 changes: 19 additions & 0 deletions commons/src/main/java/com/powsybl/commons/datastore/DataStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* 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.OutputStream;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public interface DataStore extends ReadOnlyDataStore {

public OutputStream newOutputStream(String entryName, boolean append) throws IOException;
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* 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.nio.file.Files;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.util.Objects;

/**
* @author Giovanni Ferrari <giovanni.ferrari at techrain.eu>
*/
public interface DataStoreUtil {
sylvlecl marked this conversation as resolved.
Show resolved Hide resolved

static DataStore createDataStore(Path fileName) throws IOException {
Objects.requireNonNull(fileName);
DataStore ds = null;
if (Files.isDirectory(fileName)) {
ds = new DirectoryDataStore(fileName);
} else {
String extension = getExtension(fileName.getFileName().toString());
if (extension.equals("zip")) {
ds = new ZipFileDataStore(fileName);
} else if (extension.equals("gz")) {
ds = new GzipFileDataStore(fileName);
} else if (extension.equals("bz2")) {
ds = new Bzip2FileDataStore(fileName);
} else {
Path parent = fileName.toAbsolutePath().getParent();
if (parent == null) {
throw new NotDirectoryException("null");
}
ds = new DirectoryDataStore(parent);
}
}
return ds;
}

static String getExtension(String filename) {
int dotIndex = filename.lastIndexOf(".");
return dotIndex < 0 ? "" : filename.substring(dotIndex + 1);
}

static String getBasename(String filename) {
int dotIndex = filename.lastIndexOf(".");
return dotIndex < 0 ? filename : filename.substring(0, dotIndex);
}
}
Loading