From 74ce596a3fce65f61c4fa7deacd6059f392ac665 Mon Sep 17 00:00:00 2001 From: yichen88 Date: Fri, 18 Dec 2020 02:38:45 +0100 Subject: [PATCH] Mixed storage and local data storage Signed-off-by: yichen88 --- .../java/com/powsybl/afs/AppFileSystem.java | 4 +- afs-distribution/pom.xml | 5 + afs-mixed/pom.xml | 37 +++ .../afs/mixed/LocalDataAppFileSystem.java | 20 ++ .../mixed/LocalDataAppFileSystemConfig.java | 101 +++++++ .../mixed/LocalDataAppFileSystemProvider.java | 38 +++ .../powsybl/afs/mixed/MixedAppFileSystem.java | 28 ++ .../afs/mixed/MixedAppFileSystemConfig.java | 56 ++++ .../afs/mixed/MixedAppFileSystemProvider.java | 38 +++ .../mixed/storage/LocalDataAppStorage.java | 241 +++++++++++++++++ .../afs/mixed/storage/MixedAppStorage.java | 255 ++++++++++++++++++ .../mixed/MixedAppFileSystemConfigTest.java | 58 ++++ .../mixed/storage/MixedAppStorageTest.java | 37 +++ .../afs/storage/AbstractAppStorage.java | 2 +- pom.xml | 16 ++ 15 files changed, 933 insertions(+), 3 deletions(-) create mode 100644 afs-mixed/pom.xml create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystem.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemConfig.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemProvider.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystem.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemConfig.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemProvider.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/LocalDataAppStorage.java create mode 100644 afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/MixedAppStorage.java create mode 100644 afs-mixed/src/test/java/com/powsybl/afs/mixed/MixedAppFileSystemConfigTest.java create mode 100644 afs-mixed/src/test/java/com/powsybl/afs/mixed/storage/MixedAppStorageTest.java diff --git a/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java b/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java index 153fa9c3..42341b42 100644 --- a/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java +++ b/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java @@ -43,7 +43,7 @@ public class AppFileSystem implements AutoCloseable { private final boolean remotelyAccessible; - private final AppStorage storage; + protected final AppStorage storage; private final Supplier rootNodeInfo; @@ -232,7 +232,7 @@ public AppData getData() { return data; } - void setData(AppData data) { + protected void setData(AppData data) { this.data = Objects.requireNonNull(data); } diff --git a/afs-distribution/pom.xml b/afs-distribution/pom.xml index f03ef560..8799b8a3 100644 --- a/afs-distribution/pom.xml +++ b/afs-distribution/pom.xml @@ -53,6 +53,11 @@ powsybl-afs-local ${project.version} + + ${project.groupId} + powsybl-afs-mixed + ${project.version} + ${project.groupId} powsybl-afs-mapdb diff --git a/afs-mixed/pom.xml b/afs-mixed/pom.xml new file mode 100644 index 00000000..fa6c08b8 --- /dev/null +++ b/afs-mixed/pom.xml @@ -0,0 +1,37 @@ + + + + powsybl-afs + com.powsybl + 3.5.0-SNAPSHOT + + 4.0.0 + + powsybl-afs-mixed + + + com.powsybl + powsybl-afs-core + + + + + com.google.jimfs + jimfs + test + + + junit + junit + test + + + org.mockito + mockito-core + test + + + + diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystem.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystem.java new file mode 100644 index 00000000..eaf77cc2 --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystem.java @@ -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.afs.mixed; + +import com.powsybl.afs.AppFileSystem; +import com.powsybl.afs.mixed.storage.LocalDataAppStorage; + +/** + * @author Yichen TANG + */ +public class LocalDataAppFileSystem extends AppFileSystem { + + LocalDataAppFileSystem(LocalDataAppFileSystemConfig config) { + super(config.getDriveName(), config.isRemotelyAccessible(), new LocalDataAppStorage(config)); + } +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemConfig.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemConfig.java new file mode 100644 index 00000000..6798e38e --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemConfig.java @@ -0,0 +1,101 @@ +/** + * 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.afs.mixed; + +import com.powsybl.afs.AfsException; +import com.powsybl.afs.storage.AbstractAppFileSystemConfig; +import com.powsybl.commons.config.ModuleConfig; +import com.powsybl.commons.config.PlatformConfig; + +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * @author Yichen TANG + */ +public class LocalDataAppFileSystemConfig extends AbstractAppFileSystemConfig { + + private static final String DRIVE_NAME = "drive-name"; + private static final String ROOT_DIR = "root-dir"; + + private Path rootDir; + + public static List load() { + return load(PlatformConfig.defaultConfig()); + } + + private static void load(ModuleConfig moduleConfig, int num, List configs) { + StringBuilder driveNameTag = new StringBuilder(DRIVE_NAME); + StringBuilder rootDirTag = new StringBuilder(ROOT_DIR); + driveNameTag.append("-").append(num); + rootDirTag.append("-").append(num); + if (moduleConfig.hasProperty(driveNameTag.toString()) + && moduleConfig.hasProperty(rootDirTag.toString())) { + String driveName = moduleConfig.getStringProperty(driveNameTag.toString()); + Path rootDir = moduleConfig.getPathProperty(rootDirTag.toString()); + configs.add(new LocalDataAppFileSystemConfig(driveName, rootDir)); + } + } + + private static void load(ModuleConfig moduleConfig, List configs) { + if (moduleConfig.hasProperty(DRIVE_NAME) + && moduleConfig.hasProperty(ROOT_DIR)) { + String driveName = moduleConfig.getStringProperty(DRIVE_NAME); + Path rootDir = moduleConfig.getPathProperty(ROOT_DIR); + configs.add(new LocalDataAppFileSystemConfig(driveName, rootDir)); + } + } + + public static List load(PlatformConfig platformConfig) { + return platformConfig.getOptionalModuleConfig("local-data-app-file-system") + .map(moduleConfig -> { + List configs = new ArrayList<>(); + load(moduleConfig, configs); + int maxAdditionalDriveCount = moduleConfig.getIntProperty("max-additional-drive-count", 0); + for (int i = 0; i < maxAdditionalDriveCount; i++) { + load(moduleConfig, i, configs); + } + return configs; + }) + .orElseGet(() -> { + List configs = new ArrayList<>(); + for (Path rootDir : FileSystems.getDefault().getRootDirectories()) { + if (Files.isDirectory(rootDir)) { + configs.add(new LocalDataAppFileSystemConfig(rootDir.toString(), rootDir)); + } + } + return configs; + }); + + } + + private static Path checkRootDir(Path rootDir) { + Objects.requireNonNull(rootDir); + if (!Files.isDirectory(rootDir)) { + throw new AfsException("Root path " + rootDir + " is not a directory"); + } + return rootDir; + } + + public LocalDataAppFileSystemConfig(String driveName, Path rootDir) { + super(driveName, false); + this.rootDir = checkRootDir(rootDir).toAbsolutePath(); + } + + public Path getRootDir() { + return rootDir; + } + + public LocalDataAppFileSystemConfig setRootDir(Path rootDir) { + this.rootDir = checkRootDir(rootDir); + return this; + } +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemProvider.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemProvider.java new file mode 100644 index 00000000..17e22f3e --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/LocalDataAppFileSystemProvider.java @@ -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.afs.mixed; + +import com.google.auto.service.AutoService; +import com.powsybl.afs.AppFileSystem; +import com.powsybl.afs.AppFileSystemProvider; +import com.powsybl.afs.AppFileSystemProviderContext; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author Yichen TANG + */ +@AutoService(AppFileSystemProvider.class) +public class LocalDataAppFileSystemProvider implements AppFileSystemProvider { + + private final List configs; + + public LocalDataAppFileSystemProvider() { + this(LocalDataAppFileSystemConfig.load()); + } + + public LocalDataAppFileSystemProvider(List configs) { + this.configs = Objects.requireNonNull(configs); + } + + @Override + public List getFileSystems(AppFileSystemProviderContext context) { + return configs.stream().map(LocalDataAppFileSystem::new).collect(Collectors.toList()); + } +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystem.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystem.java new file mode 100644 index 00000000..7893df50 --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystem.java @@ -0,0 +1,28 @@ +/** + * 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.afs.mixed; + +import com.powsybl.afs.AppData; +import com.powsybl.afs.AppFileSystem; +import com.powsybl.afs.mixed.storage.MixedAppStorage; + +/** + * @author Yichen TANG + */ +public class MixedAppFileSystem extends AppFileSystem { + + MixedAppFileSystem(MixedAppFileSystemConfig config) { + super(config.getDriveName(), config.isRemotelyAccessible(), new MixedAppStorage(config)); + } + + @Override + protected void setData(AppData data) { + super.setData(data); + ((MixedAppStorage) storage).setAppData(data); + } + +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemConfig.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemConfig.java new file mode 100644 index 00000000..bc91a4f8 --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemConfig.java @@ -0,0 +1,56 @@ +/** + * 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.afs.mixed; + +import com.powsybl.afs.storage.AbstractAppFileSystemConfig; +import com.powsybl.commons.config.PlatformConfig; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * @author Yichen TANG + */ +public class MixedAppFileSystemConfig extends AbstractAppFileSystemConfig { + + private final String nodeStorageDriveName; + private final String dataStorageDriveName; + + static List load() { + return load(PlatformConfig.defaultConfig()); + } + + static List load(PlatformConfig config) { + return config.getOptionalModuleConfig("mixed-app-file-system").map(moduleConfig -> { + List configs = new ArrayList<>(); + final String driveName = moduleConfig.getStringProperty("drive-name"); + final String nodeStorage = moduleConfig.getStringProperty("node-storage"); + final String dataStorage = moduleConfig.getStringProperty("data-storage"); + // TODO remote access + final MixedAppFileSystemConfig c = new MixedAppFileSystemConfig(driveName, true, nodeStorage, dataStorage); + configs.add(c); + return configs; + }).orElse(Collections.emptyList()); + } + + public MixedAppFileSystemConfig(String driveName, boolean remotelyAccessible, String nodeStorageDriveName, String dataStorageDriveName) { + super(driveName, remotelyAccessible); + this.nodeStorageDriveName = Objects.requireNonNull(nodeStorageDriveName); + this.dataStorageDriveName = Objects.requireNonNull(dataStorageDriveName); + } + + public String getNodeStorageDriveName() { + return nodeStorageDriveName; + } + + public String getDataStorageDriveName() { + return dataStorageDriveName; + } + +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemProvider.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemProvider.java new file mode 100644 index 00000000..7743658b --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/MixedAppFileSystemProvider.java @@ -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.afs.mixed; + +import com.google.auto.service.AutoService; +import com.powsybl.afs.AppFileSystem; +import com.powsybl.afs.AppFileSystemProvider; +import com.powsybl.afs.AppFileSystemProviderContext; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author Yichen TANG + */ +@AutoService(AppFileSystemProvider.class) +public class MixedAppFileSystemProvider implements AppFileSystemProvider { + + private final List configs; + + public MixedAppFileSystemProvider() { + this(MixedAppFileSystemConfig.load()); + } + + public MixedAppFileSystemProvider(List configs) { + this.configs = Objects.requireNonNull(configs); + } + + @Override + public List getFileSystems(AppFileSystemProviderContext context) { + return configs.stream().map(MixedAppFileSystem::new).collect(Collectors.toList()); + } +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/LocalDataAppStorage.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/LocalDataAppStorage.java new file mode 100644 index 00000000..a3184784 --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/LocalDataAppStorage.java @@ -0,0 +1,241 @@ +/** + * 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.afs.mixed.storage; + +import com.powsybl.afs.mixed.LocalDataAppFileSystemConfig; +import com.powsybl.afs.storage.AbstractAppStorage; +import com.powsybl.afs.storage.NodeDependency; +import com.powsybl.afs.storage.NodeGenericMetadata; +import com.powsybl.afs.storage.NodeInfo; +import com.powsybl.timeseries.DoubleDataChunk; +import com.powsybl.timeseries.StringDataChunk; +import com.powsybl.timeseries.TimeSeriesMetadata; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +/** + * @author Yichen TANG + */ +public class LocalDataAppStorage extends AbstractAppStorage { + + private static final String UNSUPPORTED_MSG = "LocalDataAppStorage not support node/time-series operation."; + private static final UnsupportedOperationException UNSUPPORTED_OPERATION_EXCEPTION = new UnsupportedOperationException(UNSUPPORTED_MSG); + + private final LocalDataAppFileSystemConfig config; + private final Path rootDir; + + public LocalDataAppStorage(LocalDataAppFileSystemConfig config) { + this.config = Objects.requireNonNull(config); + rootDir = config.getRootDir(); + } + + @Override + public String getFileSystemName() { + return config.getDriveName(); + } + + @Override + public boolean isRemote() { + return false; + } + + @Override + public NodeInfo createRootNodeIfNotExists(String name, String nodePseudoClass) { + return null; + } + + @Override + public NodeInfo createNode(String parentNodeId, String name, String nodePseudoClass, String description, int version, NodeGenericMetadata genericMetadata) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public boolean isWritable(String nodeId) { + return false; + } + + @Override + public NodeInfo getNodeInfo(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void setDescription(String nodeId, String description) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void updateModificationTime(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public List getChildNodes(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Optional getChildNode(String nodeId, String name) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Optional getParentNode(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void setParentNode(String nodeId, String newParentNodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public String deleteNode(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Optional readBinaryData(String nodeId, String name) { + final Path resolve = rootDir.resolve(config.getDriveName()).resolve(nodeId).resolve(name); + if (Files.exists(resolve)) { + try { + return Optional.of(new FileInputStream(resolve.toFile())); + } catch (FileNotFoundException e) { + throw new UncheckedIOException(e); + } + } + return Optional.empty(); + } + + @Override + public OutputStream writeBinaryData(String nodeId, String name) { + final Path resolve = rootDir.resolve(config.getDriveName()).resolve(nodeId); + try { + Files.createDirectories(resolve); + return new FileOutputStream(resolve.resolve(name).toFile()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public boolean dataExists(String nodeId, String name) { + return false; + } + + @Override + public Set getDataNames(String nodeId) { + return null; + } + + @Override + public boolean removeData(String nodeId, String name) { + return false; + } + + @Override + public void createTimeSeries(String nodeId, TimeSeriesMetadata metadata) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Set getTimeSeriesNames(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public boolean timeSeriesExists(String nodeId, String timeSeriesName) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public List getTimeSeriesMetadata(String nodeId, Set timeSeriesNames) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Set getTimeSeriesDataVersions(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Set getTimeSeriesDataVersions(String nodeId, String timeSeriesName) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Map> getDoubleTimeSeriesData(String nodeId, Set timeSeriesNames, int version) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void addDoubleTimeSeriesData(String nodeId, int version, String timeSeriesName, List chunks) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Map> getStringTimeSeriesData(String nodeId, Set timeSeriesNames, int version) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void addStringTimeSeriesData(String nodeId, int version, String timeSeriesName, List chunks) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void clearTimeSeries(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void addDependency(String nodeId, String name, String toNodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Set getDependencies(String nodeId, String name) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Set getDependencies(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public Set getBackwardDependencies(String nodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void removeDependency(String nodeId, String name, String toNodeId) { + throw UNSUPPORTED_OPERATION_EXCEPTION; + } + + @Override + public void flush() { + + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void close() { + flush(); + } + + private Void throwUnsupportedOperation() { + throw new UnsupportedOperationException("LocalDataAppStorage not support node/time-series operation."); + } +} diff --git a/afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/MixedAppStorage.java b/afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/MixedAppStorage.java new file mode 100644 index 00000000..667c6999 --- /dev/null +++ b/afs-mixed/src/main/java/com/powsybl/afs/mixed/storage/MixedAppStorage.java @@ -0,0 +1,255 @@ +/** + * 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.afs.mixed.storage; + +import com.powsybl.afs.AppData; +import com.powsybl.afs.mixed.MixedAppFileSystemConfig; +import com.powsybl.afs.storage.*; +import com.powsybl.timeseries.DoubleDataChunk; +import com.powsybl.timeseries.StringDataChunk; +import com.powsybl.timeseries.TimeSeriesMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.*; + +/** + * @author Yichen TANG + */ +public class MixedAppStorage extends AbstractAppStorage { + + private static final Logger LOGGER = LoggerFactory.getLogger(MixedAppStorage.class); + + private final String nodeStorageName; + private final String dataStorageName; + + private AppStorage nodeStorage; + private AppStorage dataStorage; + + private AppData appData; + + public MixedAppStorage(MixedAppFileSystemConfig config) { + Objects.requireNonNull(config); + this.nodeStorageName = config.getNodeStorageDriveName(); + this.dataStorageName = config.getDataStorageDriveName(); + } + + public void setAppData(AppData appData) { + this.appData = appData; + } + + private AppStorage getNodeStorage() { + if (nodeStorage == null) { + nodeStorage = appData.getRemotelyAccessibleStorage(nodeStorageName); + } + return nodeStorage; + } + + private AppStorage getDataStorage() { + if (dataStorage == null) { + dataStorage = appData.getRemotelyAccessibleStorage(dataStorageName); + } + return dataStorage; + } + + @Override + public String getFileSystemName() { + return getNodeStorage().getFileSystemName(); + } + + @Override + public boolean isRemote() { + return getNodeStorage().isRemote(); + } + + @Override + public NodeInfo createRootNodeIfNotExists(String name, String nodePseudoClass) { + return getNodeStorage().createRootNodeIfNotExists(name, nodePseudoClass); + } + + @Override + public NodeInfo createNode(String parentNodeId, String name, String nodePseudoClass, String description, int version, NodeGenericMetadata genericMetadata) { + return getNodeStorage().createNode(parentNodeId, name, nodePseudoClass, description, version, genericMetadata); + } + + @Override + public boolean isWritable(String nodeId) { + return getNodeStorage().isWritable(nodeId) && getDataStorage().isWritable(nodeId); + } + + @Override + public NodeInfo getNodeInfo(String nodeId) { + return getNodeStorage().getNodeInfo(nodeId); + } + + @Override + public void setDescription(String nodeId, String description) { + getNodeStorage().setDescription(nodeId, description); + } + + @Override + public void updateModificationTime(String nodeId) { + getNodeStorage().updateModificationTime(nodeId); + } + + @Override + public List getChildNodes(String nodeId) { + return getNodeStorage().getChildNodes(nodeId); + } + + @Override + public Optional getChildNode(String nodeId, String name) { + return getNodeStorage().getChildNode(nodeId, name); + } + + @Override + public Optional getParentNode(String nodeId) { + return getNodeStorage().getParentNode(nodeId); + } + + @Override + public void setParentNode(String nodeId, String newParentNodeId) { + getNodeStorage().setParentNode(nodeId, newParentNodeId); + } + + @Override + public void setConsistent(String nodeId) { + getNodeStorage().setConsistent(nodeId); + } + + @Override + public String deleteNode(String nodeId) { + return getNodeStorage().deleteNode(nodeId); + } + + @Override + public Optional readBinaryData(String nodeId, String name) { + return getDataStorage().readBinaryData(nodeId, name); + } + + @Override + public OutputStream writeBinaryData(String nodeId, String name) { + return getDataStorage().writeBinaryData(nodeId, name); + } + + @Override + public boolean dataExists(String nodeId, String name) { + return getDataStorage().dataExists(nodeId, name); + } + + @Override + public Set getDataNames(String nodeId) { + return null; + } + + @Override + public boolean removeData(String nodeId, String name) { + return false; + } + + @Override + public void createTimeSeries(String nodeId, TimeSeriesMetadata metadata) { + + } + + @Override + public Set getTimeSeriesNames(String nodeId) { + return null; + } + + @Override + public boolean timeSeriesExists(String nodeId, String timeSeriesName) { + return false; + } + + @Override + public List getTimeSeriesMetadata(String nodeId, Set timeSeriesNames) { + return null; + } + + @Override + public Set getTimeSeriesDataVersions(String nodeId) { + return null; + } + + @Override + public Set getTimeSeriesDataVersions(String nodeId, String timeSeriesName) { + return null; + } + + @Override + public Map> getDoubleTimeSeriesData(String nodeId, Set timeSeriesNames, int version) { + return null; + } + + @Override + public void addDoubleTimeSeriesData(String nodeId, int version, String timeSeriesName, List chunks) { + + } + + @Override + public Map> getStringTimeSeriesData(String nodeId, Set timeSeriesNames, int version) { + return null; + } + + @Override + public void addStringTimeSeriesData(String nodeId, int version, String timeSeriesName, List chunks) { + + } + + @Override + public void clearTimeSeries(String nodeId) { + + } + + @Override + public void addDependency(String nodeId, String name, String toNodeId) { + + } + + @Override + public Set getDependencies(String nodeId, String name) { + return null; + } + + @Override + public Set getDependencies(String nodeId) { + return null; + } + + @Override + public Set getBackwardDependencies(String nodeId) { + return null; + } + + @Override + public void removeDependency(String nodeId, String name, String toNodeId) { + + } + + @Override + public EventsBus getEventsBus() { + return null; + } + + @Override + public void flush() { + + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void close() { + + } +} diff --git a/afs-mixed/src/test/java/com/powsybl/afs/mixed/MixedAppFileSystemConfigTest.java b/afs-mixed/src/test/java/com/powsybl/afs/mixed/MixedAppFileSystemConfigTest.java new file mode 100644 index 00000000..026995ac --- /dev/null +++ b/afs-mixed/src/test/java/com/powsybl/afs/mixed/MixedAppFileSystemConfigTest.java @@ -0,0 +1,58 @@ +/** + * 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.afs.mixed; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.powsybl.commons.config.InMemoryPlatformConfig; +import com.powsybl.commons.config.MapModuleConfig; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author Yichen TANG + */ +public class MixedAppFileSystemConfigTest { + + private FileSystem fileSystem; + + private InMemoryPlatformConfig platformConfig; + + @Before + public void setUp() throws Exception { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + Files.createDirectories(fileSystem.getPath("/tmp")); + Files.createFile(fileSystem.getPath("/test")); + platformConfig = new InMemoryPlatformConfig(fileSystem); + MapModuleConfig moduleConfig = platformConfig.createModuleConfig("mixed-app-file-system"); + moduleConfig.setStringProperty("drive-name", "mixed"); + moduleConfig.setStringProperty("node-storage", "n"); + moduleConfig.setStringProperty("data-storage", "d"); + } + + @After + public void tearDown() throws Exception { + fileSystem.close(); + } + + @Test + public void testLoad() { + final List configs = MixedAppFileSystemConfig.load(platformConfig); + assertEquals(1, configs.size()); + final MixedAppFileSystemConfig config = configs.get(0); + assertEquals("mixed", config.getDriveName()); + assertEquals("n", config.getNodeStorageDriveName()); + assertEquals("d", config.getDataStorageDriveName()); + } +} diff --git a/afs-mixed/src/test/java/com/powsybl/afs/mixed/storage/MixedAppStorageTest.java b/afs-mixed/src/test/java/com/powsybl/afs/mixed/storage/MixedAppStorageTest.java new file mode 100644 index 00000000..13d4f703 --- /dev/null +++ b/afs-mixed/src/test/java/com/powsybl/afs/mixed/storage/MixedAppStorageTest.java @@ -0,0 +1,37 @@ +/** + * 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.afs.mixed.storage; + +import com.powsybl.afs.AppData; +import com.powsybl.afs.mixed.MixedAppFileSystemConfig; +import com.powsybl.afs.storage.AppStorage; +import org.junit.Test; + +import static org.mockito.Mockito.*; + +/** + * @author Yichen TANG + */ +public class MixedAppStorageTest { + + @Test + public void test() { + MixedAppFileSystemConfig config = mock(MixedAppFileSystemConfig.class); + when(config.getDriveName()).thenReturn("mixed"); + when(config.getDataStorageDriveName()).thenReturn("d"); + when(config.getNodeStorageDriveName()).thenReturn("n"); + AppStorage das = mock(AppStorage.class); + AppStorage nas = mock(AppStorage.class); + AppData appData = mock(AppData.class); + when(appData.getRemotelyAccessibleStorage("d")).thenReturn(das); + when(appData.getRemotelyAccessibleStorage("n")).thenReturn(nas); + final MixedAppStorage mixedAppStorage = new MixedAppStorage(config); + mixedAppStorage.setAppData(appData); + mixedAppStorage.getChildNodes("a"); + verify(nas, times(1)).getChildNodes(eq("a")); + } +} diff --git a/afs-storage-api/src/main/java/com/powsybl/afs/storage/AbstractAppStorage.java b/afs-storage-api/src/main/java/com/powsybl/afs/storage/AbstractAppStorage.java index e1009272..4709b23e 100644 --- a/afs-storage-api/src/main/java/com/powsybl/afs/storage/AbstractAppStorage.java +++ b/afs-storage-api/src/main/java/com/powsybl/afs/storage/AbstractAppStorage.java @@ -21,7 +21,7 @@ public abstract class AbstractAppStorage implements AppStorage { protected EventsBus eventsBus; - private final Logger logger = LoggerFactory.getLogger(AbstractAppStorage.class); + private final Logger logger = LoggerFactory.getLogger(AbstractAppStorage.class); protected void pushEvent(NodeEvent event, String topic) { if (eventsBus == null) { diff --git a/pom.xml b/pom.xml index dd92bf74..98c76d61 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ afs-local afs-mapdb afs-mapdb-storage + afs-mixed afs-network afs-scripting afs-security-analysis @@ -207,6 +208,21 @@ powsybl-tools ${powsyblcore.version} + + ${project.groupId} + powsybl-afs-core + ${project.version} + + + ${project.groupId} + powsybl-afs-mixed-storage + ${project.version} + + + ${project.groupId} + powsybl-afs-storage-api + ${project.version} + io.jsonwebtoken jjwt