diff --git a/afs-core/src/main/java/com/powsybl/afs/ProjectNode.java b/afs-core/src/main/java/com/powsybl/afs/ProjectNode.java index 6d4e8299..0fb925ec 100644 --- a/afs-core/src/main/java/com/powsybl/afs/ProjectNode.java +++ b/afs-core/src/main/java/com/powsybl/afs/ProjectNode.java @@ -67,6 +67,12 @@ public List getBackwardDependencies() { return getBackwardDependencies(true); } + /** + * Retrieve backward dependencies
+ * Use connected to false if the node is used immediately in a local scope and if it doesn't need to update itself on events, as in {@link #invalidate()} + * @param connected connect the node to eventBus events + * @return dependencies + */ public List getBackwardDependencies(boolean connected) { return storage.getBackwardDependencies(info.getId()) .stream() diff --git a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java index 05b6f726..506c99d9 100644 --- a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java @@ -10,11 +10,8 @@ import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; -import com.powsybl.afs.storage.AfsStorageException; -import com.powsybl.afs.storage.AppStorage; -import com.powsybl.afs.storage.InMemoryEventsBus; -import com.powsybl.afs.storage.NodeGenericMetadata; -import com.powsybl.afs.storage.NodeInfo; +import com.powsybl.afs.storage.*; +import com.powsybl.afs.storage.events.NodeEvent; import com.powsybl.computation.ComputationManager; import com.powsybl.iidm.network.NetworkFactoryService; import com.powsybl.timeseries.RegularTimeSeriesIndex; @@ -57,7 +54,7 @@ public void setup() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); ComputationManager computationManager = Mockito.mock(ComputationManager.class); ad = new AppData(computationManager, computationManager, Collections.emptyList(), - Collections.emptyList(), Collections.singletonList(new FooFileExtension()), Collections.emptyList()); + Collections.emptyList(), List.of(new FooFileExtension(), new WithDependencyFileExtension()), Collections.emptyList()); storage = MapDbAppStorage.createMem("mem", ad.getEventsBus()); @@ -566,4 +563,40 @@ void hasDeepDependencyTest() { otherFile.setDependencies("dep", Collections.singletonList(createdFile)); assertTrue(createdFile.hasDeepDependency(createdFile, "dep")); } + + @Test + public void invalidate() { + Folder folder = afs.getRootFolder().createFolder("testFolder"); + Project project = folder.createProject("test"); + FooFile fooFile = project.getRootFolder().fileBuilder(FooFileBuilder.class).withName("Foo").build(); + WithDependencyFile fileWithDep = project.getRootFolder().fileBuilder(WithDependencyFileBuilder.class).build(); + fileWithDep.setFooDependency(fooFile); + + // Previous code add connected WithDependencyFile with listeners + storage.getEventsBus().flush(); + storage.getEventsBus().removeListeners(); + + fooFile.invalidate(); + + // WithDependencyFile is not connected => don't store event + String nodeEventType = "type"; + storage.getEventsBus().pushEvent(new NodeEvent("id", nodeEventType) { + }, "Topic"); + storage.getEventsBus().flush(); + Optional updateEvent = fileWithDep.events.stream().filter(nodeEvent -> nodeEventType.equals(nodeEvent.getType())).findFirst(); + assertTrue(updateEvent.isEmpty()); + + // WithDependencyFile is not connected => store event + List connectedBackwardDependencies = fooFile.getBackwardDependencies(true); + storage.getEventsBus().pushEvent(new NodeEvent("id", nodeEventType) { + }, "Topic"); + storage.getEventsBus().flush(); + assertEquals(1, connectedBackwardDependencies.size()); + assertEquals(WithDependencyFile.class, connectedBackwardDependencies.get(0).getClass()); + WithDependencyFile withDependencyFile = (WithDependencyFile) connectedBackwardDependencies.get(0); + Optional updateEvent2 = withDependencyFile.events.stream() + .filter(nodeEvent -> nodeEventType.equals(nodeEvent.getType())) + .findFirst(); + assertFalse(updateEvent2.isEmpty()); + } } diff --git a/afs-core/src/test/java/com/powsybl/afs/DependencyCacheTest.java b/afs-core/src/test/java/com/powsybl/afs/DependencyCacheTest.java index 492aa069..2fc52848 100644 --- a/afs-core/src/test/java/com/powsybl/afs/DependencyCacheTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/DependencyCacheTest.java @@ -10,11 +10,8 @@ import com.powsybl.afs.mapdb.storage.MapDbAppStorage; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; -import com.powsybl.afs.storage.NodeGenericMetadata; -import com.powsybl.afs.storage.NodeInfo; import org.junit.jupiter.api.Test; -import java.util.Collections; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -25,128 +22,6 @@ */ class DependencyCacheTest extends AbstractProjectFileTest { - class Tic extends ProjectFile { - - Tic(ProjectFileCreationContext context) { - super(context, 0); - } - } - - class TicBuilder implements ProjectFileBuilder { - - private final ProjectFileBuildContext context; - - private String name; - - TicBuilder(ProjectFileBuildContext context) { - this.context = context; - } - - public TicBuilder setName(String name) { - this.name = name; - return this; - } - - @Override - public Tic build() { - NodeInfo info = context.getStorage().createNode(context.getFolderInfo().getId(), name, "TIC", "", 0, new NodeGenericMetadata()); - context.getStorage().setConsistent(info.getId()); - return new Tic(new ProjectFileCreationContext(info, context.getStorage(), context.getProject())); - } - } - - class TicExtension implements ProjectFileExtension { - - @Override - public Class getProjectFileClass() { - return Tic.class; - } - - @Override - public String getProjectFilePseudoClass() { - return "TIC"; - } - - @Override - public Class getProjectFileBuilderClass() { - return TicBuilder.class; - } - - @Override - public Tic createProjectFile(ProjectFileCreationContext context) { - return new Tic(context); - } - - @Override - public ProjectFileBuilder createProjectFileBuilder(ProjectFileBuildContext context) { - return new TicBuilder(context); - } - } - - class Tac extends ProjectFile { - - private static final String DEP_NAME = "dep"; - - private final DependencyCache cache = new DependencyCache<>(this, DEP_NAME, ProjectFile.class); - - Tac(ProjectFileCreationContext context) { - super(context, 0); - } - - ProjectFile getTicDependency() { - return cache.getFirst().orElse(null); - } - - void setTicDependency(Tic tic) { - setDependencies(DEP_NAME, Collections.singletonList(tic)); - cache.invalidate(); - } - } - - class TacBuilder implements ProjectFileBuilder { - - private final ProjectFileBuildContext context; - - TacBuilder(ProjectFileBuildContext context) { - this.context = context; - } - - @Override - public Tac build() { - NodeInfo info = context.getStorage().createNode(context.getFolderInfo().getId(), "tac", "TAC", "", 0, new NodeGenericMetadata()); - context.getStorage().setConsistent(info.getId()); - return new Tac(new ProjectFileCreationContext(info, context.getStorage(), context.getProject())); - } - } - - class TacExtension implements ProjectFileExtension { - - @Override - public Class getProjectFileClass() { - return Tac.class; - } - - @Override - public String getProjectFilePseudoClass() { - return "TAC"; - } - - @Override - public Class getProjectFileBuilderClass() { - return TacBuilder.class; - } - - @Override - public Tac createProjectFile(ProjectFileCreationContext context) { - return new Tac(context); - } - - @Override - public ProjectFileBuilder createProjectFileBuilder(ProjectFileBuildContext context) { - return new TacBuilder(context); - } - } - @Override protected AppStorage createStorage() { return MapDbAppStorage.createMem("mem", new InMemoryEventsBus()); @@ -154,20 +29,20 @@ protected AppStorage createStorage() { @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new TicExtension(), new TacExtension()); + return ImmutableList.of(new FooFileExtension(), new WithDependencyFileExtension()); } @Test void test() { Project project = afs.getRootFolder().createProject("project"); - Tic tic = project.getRootFolder().fileBuilder(TicBuilder.class).setName("tic").build(); - Tic tic2 = project.getRootFolder().fileBuilder(TicBuilder.class).setName("tic2").build(); - Tac tac = project.getRootFolder().fileBuilder(TacBuilder.class).build(); + FooFile tic = project.getRootFolder().fileBuilder(FooFileBuilder.class).withName("tic").build(); + FooFile tic2 = project.getRootFolder().fileBuilder(FooFileBuilder.class).withName("tic2").build(); + WithDependencyFile tac = project.getRootFolder().fileBuilder(WithDependencyFileBuilder.class).build(); assertNull(tac.getTicDependency()); - tac.setTicDependency(tic); + tac.setFooDependency(tic); assertNotNull(tac.getTicDependency()); assertEquals(tic.getId(), tac.getTicDependency().getId()); - tac.setTicDependency(tic2); + tac.setFooDependency(tic2); assertNotNull(tac.getTicDependency()); assertEquals(tic2.getId(), tac.getTicDependency().getId()); } diff --git a/afs-core/src/test/java/com/powsybl/afs/WithDependencyFile.java b/afs-core/src/test/java/com/powsybl/afs/WithDependencyFile.java new file mode 100644 index 00000000..2c5d42fb --- /dev/null +++ b/afs-core/src/test/java/com/powsybl/afs/WithDependencyFile.java @@ -0,0 +1,31 @@ +package com.powsybl.afs; + +import com.powsybl.afs.storage.events.NodeEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class WithDependencyFile extends ProjectFile { + + private static final String DEP_NAME = "dep"; + + private final DependencyCache cache = new DependencyCache<>(this, DEP_NAME, ProjectFile.class); + final List events = new ArrayList<>(); + + WithDependencyFile(ProjectFileCreationContext context) { + super(context, 0); + if (context.isConnected()) { + context.getStorage().getEventsBus().addListener(eventList -> events.addAll(eventList.getEvents())); + } + } + + ProjectFile getTicDependency() { + return cache.getFirst().orElse(null); + } + + void setFooDependency(FooFile foo) { + setDependencies(DEP_NAME, Collections.singletonList(foo)); + cache.invalidate(); + } +} diff --git a/afs-core/src/test/java/com/powsybl/afs/WithDependencyFileBuilder.java b/afs-core/src/test/java/com/powsybl/afs/WithDependencyFileBuilder.java new file mode 100644 index 00000000..e4d12844 --- /dev/null +++ b/afs-core/src/test/java/com/powsybl/afs/WithDependencyFileBuilder.java @@ -0,0 +1,20 @@ +package com.powsybl.afs; + +import com.powsybl.afs.storage.NodeGenericMetadata; +import com.powsybl.afs.storage.NodeInfo; + +public class WithDependencyFileBuilder implements ProjectFileBuilder { + + private final ProjectFileBuildContext context; + + WithDependencyFileBuilder(ProjectFileBuildContext context) { + this.context = context; + } + + @Override + public WithDependencyFile build() { + NodeInfo info = context.getStorage().createNode(context.getFolderInfo().getId(), "WithDependencyFile", "WITH_DEPENDENCY_FILE", "", 0, new NodeGenericMetadata()); + context.getStorage().setConsistent(info.getId()); + return new WithDependencyFile(new ProjectFileCreationContext(info, context.getStorage(), context.getProject())); + } +} diff --git a/afs-core/src/test/java/com/powsybl/afs/WithDependencyFileExtension.java b/afs-core/src/test/java/com/powsybl/afs/WithDependencyFileExtension.java new file mode 100644 index 00000000..28180281 --- /dev/null +++ b/afs-core/src/test/java/com/powsybl/afs/WithDependencyFileExtension.java @@ -0,0 +1,29 @@ +package com.powsybl.afs; + +public class WithDependencyFileExtension implements ProjectFileExtension { + + @Override + public Class getProjectFileClass() { + return WithDependencyFile.class; + } + + @Override + public String getProjectFilePseudoClass() { + return "WITH_DEPENDENCY_FILE"; + } + + @Override + public Class getProjectFileBuilderClass() { + return WithDependencyFileBuilder.class; + } + + @Override + public WithDependencyFile createProjectFile(ProjectFileCreationContext context) { + return new WithDependencyFile(context); + } + + @Override + public ProjectFileBuilder createProjectFileBuilder(ProjectFileBuildContext context) { + return new WithDependencyFileBuilder(context); + } +}