diff --git a/ccm-core/src/main/java/org/libreccm/imexport/DependencyException.java b/ccm-core/src/main/java/org/libreccm/imexport/DependencyException.java
new file mode 100644
index 000000000..d2ef26784
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/imexport/DependencyException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.imexport;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class DependencyException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of DependencyException without detail
+ * message.
+ */
+ public DependencyException() {
+ super();
+ //Nothing more
+ }
+
+ /**
+ * Constructs an instance of DependencyException with the
+ * specified detail message.
+ *
+ * @param msg the detail message.
+ */
+ public DependencyException(final String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an instance of DependencyException which wraps
+ * the specified exception.
+ *
+ * @param exception The exception to wrap.
+ */
+ public DependencyException(final Exception exception) {
+ super(exception);
+ }
+
+ /**
+ * Constructs an instance of DependencyException with the
+ * specified message which also wraps the specified exception.
+ *
+ * @param msg The detail message.
+ * @param exception The exception to wrap.
+ */
+ public DependencyException(final String msg, final Exception exception) {
+ super(msg, exception);
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/EntityImporter.java b/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporter.java
similarity index 65%
rename from ccm-core/src/main/java/org/libreccm/imexport/EntityImporter.java
rename to ccm-core/src/main/java/org/libreccm/imexport/EntityImExporter.java
index d1099fa35..7653cf748 100644
--- a/ccm-core/src/main/java/org/libreccm/imexport/EntityImporter.java
+++ b/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporter.java
@@ -18,19 +18,23 @@
*/
package org.libreccm.imexport;
+import javax.enterprise.context.RequestScoped;
import javax.json.JsonObject;
/**
- * Imports an entity. Implementations must be annotated with {@link Imports} to
- * register the implementation in the Import/Export system.
- *
- * Implementations must be CDI beans with annotated with {@link RequestScoped}.
- *
+ * Interface for importers/exporters. Implementations must be annotated with
+ * {@link Procsses} to register the implementation in the Import/Export service.
+ *
+ * Implementations must also be CDI beans. It is recommended that the beans
+ * are {@link RequestScoped}.
+ *
* @author Jens Pelzetter
- * @param The entity type which can processed by the implementation.
+ * @param The type of the entity which is processed by the implementation.
*/
-public interface EntityImporter {
-
+public interface EntityImExporter {
+
T importEntity(JsonObject data);
-
+
+ JsonObject exportEntity(T entity);
+
}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporterTreeManager.java b/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporterTreeManager.java
new file mode 100644
index 000000000..23445348c
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporterTreeManager.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.imexport;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+final class EntityImExporterTreeManager {
+
+ public List generateTree(
+ final List> imExporters)
+ throws DependencyException {
+
+ final Map nodes = imExporters
+ .stream()
+ .map(EntityImExporterTreeNode::new)
+ .collect(Collectors
+ .toMap(
+ node -> node
+ .getEntityImExporter()
+ .getClass()
+ .getAnnotation(Processes.class)
+ .type()
+ .getName(),
+ node -> node));
+
+ for (final EntityImExporter> imExporter : imExporters) {
+ addDependencyRelations(imExporter, nodes);
+ }
+
+ final List nodeList = new ArrayList<>();
+ for (final Map.Entry entry
+ : nodes.entrySet()) {
+
+ nodeList.add(entry.getValue());
+ }
+
+ return nodeList;
+ }
+
+ private void addDependencyRelations(
+ final EntityImExporter> imExporter,
+ final Map nodes)
+ throws DependencyException {
+
+ final Processes processes = imExporter
+ .getClass()
+ .getAnnotation(Processes.class);
+ final String className = imExporter.getClass().getName();
+
+ if (!nodes.containsKey(className)) {
+
+ throw new IllegalArgumentException(String.format(
+ "The nodes map does not contain a node for "
+ + "EntityImExporter \"%s\"."
+ + "This should not happen.",
+ className));
+ }
+
+ final EntityImExporterTreeNode node = nodes.get(className);
+
+ for (final Class extends Exportable> clazz : processes.dependsOn()) {
+
+ addDependencyRelation(nodes, node, clazz);
+ }
+ }
+
+ private void addDependencyRelation(
+ final Map nodes,
+ EntityImExporterTreeNode node,
+ Class extends Exportable> clazz)
+ throws DependencyException {
+
+ if (!nodes.containsKey(clazz.getName())) {
+
+ throw new DependencyException(String.format(
+ "EntityImExporter for type \"%s\" depends on type \"%s\" "
+ + "but no EntityImExporter for type \"%s\" is available.",
+ node.getEntityImExporter().getClass().getAnnotation(
+ Processes.class).type().getName(),
+ clazz.getName(),
+ clazz.getName()));
+ }
+
+ final EntityImExporterTreeNode dependencyNode = nodes
+ .get(clazz.getName());
+
+ node.addDependsOn(dependencyNode);
+ dependencyNode.addDependentImExporter(node);
+ }
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporterTreeNode.java b/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporterTreeNode.java
new file mode 100644
index 000000000..cb921689b
--- /dev/null
+++ b/ccm-core/src/main/java/org/libreccm/imexport/EntityImExporterTreeNode.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 LibreCCM Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+package org.libreccm.imexport;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+final class EntityImExporterTreeNode {
+
+ private EntityImExporter> entityImExporter;
+
+ private List dependentImExporters;
+
+ private List dependsOn;
+
+ public EntityImExporterTreeNode() {
+
+ super();
+
+ dependentImExporters = new ArrayList<>();
+ dependsOn = new ArrayList<>();
+ }
+
+ public EntityImExporterTreeNode(
+ final EntityImExporter> entityImExporter) {
+
+ this();
+ this.entityImExporter = entityImExporter;
+ }
+
+ public EntityImExporter> getEntityImExporter() {
+
+ return entityImExporter;
+ }
+
+ void setEntityImExporter(final EntityImExporter> entityImExporter) {
+
+ this.entityImExporter = entityImExporter;
+ }
+
+ public List getDependentImExporters() {
+ return Collections.unmodifiableList(dependentImExporters);
+ }
+
+ void setDependentImExporters(
+ final List dependentImExporters) {
+
+ this.dependentImExporters = new ArrayList<>(dependentImExporters);
+ }
+
+ void addDependentImExporter(final EntityImExporterTreeNode node) {
+
+ dependentImExporters.add(node);
+ }
+
+ void removeDependentImExporter(final EntityImExporterTreeNode node) {
+
+ dependentImExporters.remove(node);
+ }
+
+ public List getDependsOn() {
+
+ return Collections.unmodifiableList(dependsOn);
+ }
+
+ void setDependsOn(final List dependsOn) {
+
+ this.dependsOn = new ArrayList<>(dependsOn);
+ }
+
+ void addDependsOn(final EntityImExporterTreeNode node) {
+
+ dependsOn.add(node);
+ }
+
+ void removeDependsOn(final EntityImExporterTreeNode node) {
+
+ dependsOn.remove(node);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 47
+ * hash
+ + Objects.hashCode(this.entityImExporter.getClass().getName());
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof EntityImExporterTreeNode)) {
+ return false;
+ }
+ final EntityImExporterTreeNode other = (EntityImExporterTreeNode) obj;
+ return Objects.equals(
+ this.entityImExporter.getClass().getName(),
+ other.getEntityImExporter().getClass().getName());
+ }
+
+
+
+}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/ExportedEntity.java b/ccm-core/src/main/java/org/libreccm/imexport/ExportedEntity.java
deleted file mode 100644
index 71e55b6f0..000000000
--- a/ccm-core/src/main/java/org/libreccm/imexport/ExportedEntity.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 LibreCCM Foundation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-package org.libreccm.imexport;
-
-import java.util.Objects;
-import java.util.Optional;
-
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-
-/**
- * A transfer object used by {@link Exporter} to wrap the exported object and
- * optionally the associations extracted from the object.
- *
- * @author Jens Pelzetter
- */
-public class ExportedEntity {
-
- private final JsonObject entity;
- private final JsonArray associations;
-
- public ExportedEntity(final JsonObject entity) {
-
- this.entity = Objects.requireNonNull(entity);
- this.associations = null;
- }
-
- public ExportedEntity(final JsonObject entity,
- final JsonArray associations) {
-
- this.entity = Objects.requireNonNull(entity);
- this.associations = Objects.requireNonNull(associations);
- }
-
- public JsonObject getEntity() {
- return entity;
- }
-
- public Optional getAssociations() {
- return Optional.of(associations);
- }
-
-}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/Exports.java b/ccm-core/src/main/java/org/libreccm/imexport/Exports.java
deleted file mode 100644
index f26eb27bb..000000000
--- a/ccm-core/src/main/java/org/libreccm/imexport/Exports.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 LibreCCM Foundation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-package org.libreccm.imexport;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import javax.inject.Qualifier;
-
-/**
- * Declares which entity type a implementation of {@link Exporter} can process.
- *
- * @author Jens Pelzetter
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Qualifier
-@Target({ElementType.TYPE,
- ElementType.PARAMETER,
- ElementType.FIELD,
- ElementType.METHOD})
-public @interface Exports {
-
- Class extends Exportable> value();
-
-}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/ImportExport.java b/ccm-core/src/main/java/org/libreccm/imexport/ImportExport.java
index 3bb73655c..816cd5f03 100644
--- a/ccm-core/src/main/java/org/libreccm/imexport/ImportExport.java
+++ b/ccm-core/src/main/java/org/libreccm/imexport/ImportExport.java
@@ -18,15 +18,29 @@
*/
package org.libreccm.imexport;
-
+import org.libreccm.core.UnexpectedErrorException;
+import org.libreccm.files.CcmFiles;
import org.libreccm.files.CcmFilesConfiguration;
+import org.libreccm.files.FileAccessException;
+import org.libreccm.files.FileDoesNotExistException;
+import org.libreccm.files.InsufficientPermissionsException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
+import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
/**
* Central service for importing and exporting entities.
@@ -37,12 +51,11 @@ import javax.inject.Inject;
public class ImportExport {
@Inject
- @Any
- private Instance> importers;
+ private CcmFiles ccmFiles;
@Inject
@Any
- private Instance> exporters;
+ private Instance> imExporters;
/**
* Exports the provided entities. The export will be written to a to the
@@ -53,36 +66,154 @@ public class ImportExport {
* file the provided name will be used.
*
*
- * @param entities The entities to export.
+ * @param entities The entities to export.
* @param exportName The name file to which the export is written.
- * @param split Split the entities by package?
*
* @see CcmFilesConfiguration#dataPath
*/
public void exportEntities(final List entities,
- final String exportName,
- final boolean split) {
+ final String exportName) {
throw new UnsupportedOperationException();
}
-
+
/**
- * Imports all entities from the files in the {@link imports} directory inside
- * the CCM files data directory. The data to import can either be a file with
- * the provided name or a directory with the provided name. If it is a directory
- * the entry file must also use the provided name.
- *
+ * Imports all entities from the files in the {@link imports} directory
+ * inside the CCM files data directory. The data to import can either be a
+ * file with the provided name or a directory with the provided name. If it
+ * is a directory the entry file must also use the provided name.
+ *
* If an entity which is part of the import already exists in the database
* the values from the import are used to update the entity.
- *
+ *
* @param importName The name of the import.
- *
+ *
* @see CcmFilesConfiguration#dataPath
*/
public void importEntities(final String importName) {
-
+
+ final String importsPath = String.format("imports/%s", importName);
+
+ try {
+ if (!ccmFiles.isDirectory(importsPath)) {
+
+ throw new IllegalArgumentException(String.format(
+ "No imports with name \"%s\" available.",
+ importName));
+ }
+ } catch (FileAccessException
+ | FileDoesNotExistException
+ | InsufficientPermissionsException ex) {
+
+ throw new UnexpectedErrorException(ex);
+ }
+
+ final String manifestPath = String.format("%s/ccm-export.json",
+ importsPath);
+ try (final InputStream manifestInputStream = ccmFiles
+ .createInputStream(importsPath)) {
+
+ final JsonReader manifestReader = Json
+ .createReader(manifestInputStream);
+ final JsonObject manifest = manifestReader.readObject();
+
+ } catch (IOException
+ | FileDoesNotExistException
+ | FileAccessException
+ | InsufficientPermissionsException ex) {
+
+ }
+
throw new UnsupportedOperationException();
-
+
+ }
+
+ public List listAvailableImportArchivies() {
+
+ final List importArchivePaths;
+ try {
+ importArchivePaths = ccmFiles.listFiles("imports");
+ } catch (FileAccessException
+ | FileDoesNotExistException
+ | InsufficientPermissionsException ex) {
+
+ throw new UnexpectedErrorException(ex);
+ }
+
+ return importArchivePaths.
+ stream()
+ .filter(this::isImportArchive)
+ .map(this::createImportManifest)
+ .collect(Collectors.toList());
+ }
+
+ private boolean isImportArchive(final String path) {
+
+ final String manifestPath = String.format("imports/%s/ccm-export.json",
+ path);
+
+ final boolean result;
+ try {
+ result = ccmFiles.existsFile(manifestPath);
+ } catch (FileAccessException | InsufficientPermissionsException ex) {
+
+ throw new UnexpectedErrorException(ex);
+ }
+
+ return result;
+ }
+
+ private ImportManifest createImportManifest(final String path) {
+
+ final String manifestPath = String.format("imports/%s/ccm-export.json",
+ path);
+
+ final InputStream inputStream;
+ try {
+ inputStream = ccmFiles.createInputStream(manifestPath);
+ } catch (FileAccessException
+ | FileDoesNotExistException
+ | InsufficientPermissionsException ex) {
+
+ throw new UnexpectedErrorException(ex);
+ }
+
+ final JsonReader reader = Json.createReader(inputStream);
+ final JsonObject manifestJson = reader.readObject();
+
+ if (!manifestJson.containsKey("created")) {
+ throw new IllegalArgumentException(String.format(
+ "The manifest file \"%s\" is malformed. "
+ + "Key \"created\" is missing.",
+ manifestPath));
+ }
+
+ if (!manifestJson.containsKey("onServer")) {
+ throw new IllegalArgumentException(String.format(
+ "The manifest file \"%s\" is malformed. "
+ + "Key \"onServer\" is missing.",
+ manifestPath));
+ }
+
+ if (!manifestJson.containsKey("types")) {
+ throw new IllegalArgumentException(String.format(
+ "The manifest file \"%s\" is malformed. "
+ + "Key \"types\" is missing.",
+ manifestPath));
+ }
+
+ final LocalDateTime created = LocalDateTime
+ .parse(manifestJson.getString("created"));
+ final String onServer = manifestJson.getString("onServer");
+ final List types = manifestJson.getJsonArray("types")
+ .stream()
+ .map(value -> value.toString())
+ .collect(Collectors.toList());
+
+ return new ImportManifest(
+ Date.from(created.atZone(ZoneId.of("UTC")).toInstant()),
+ onServer,
+ types);
}
}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/EntityExporter.java b/ccm-core/src/main/java/org/libreccm/imexport/ImportManifest.java
similarity index 56%
rename from ccm-core/src/main/java/org/libreccm/imexport/EntityExporter.java
rename to ccm-core/src/main/java/org/libreccm/imexport/ImportManifest.java
index a4e31e6cd..140e551f1 100644
--- a/ccm-core/src/main/java/org/libreccm/imexport/EntityExporter.java
+++ b/ccm-core/src/main/java/org/libreccm/imexport/ImportManifest.java
@@ -18,27 +18,39 @@
*/
package org.libreccm.imexport;
-import javax.enterprise.context.RequestScoped;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
/**
- * Interface for exporters. Implementation must be annotated with
- * {@link Exports} to register the implementation in the Import/Export system.
- *
- * Implementations must be CDI beans with annotated with {@link RequestScoped}.
*
* @author Jens Pelzetter
- * @param The type of the entity which is processed by the implementation.
*/
-public interface EntityExporter {
+public class ImportManifest {
- /**
- * Converts the provided entity to a JSON object and an optional array of
- * associations.
- *
- * @param entity The entity to export.
- *
- * @return The JSON representation of the entity.
- */
- ExportedEntity exportEntity(T entity);
+ private final Date created;
+ private final String onServer;
+ private final List types;
+
+ public ImportManifest(final Date created,
+ final String onServer,
+ final List types) {
+
+ this.created = created;
+ this.onServer = onServer;
+ this.types = types;
+ }
+
+ public Date getCreated() {
+ return new Date(created.getTime());
+ }
+
+ public String getOnServer() {
+ return onServer;
+ }
+
+ public List getTypes() {
+ return Collections.unmodifiableList(types);
+ }
}
diff --git a/ccm-core/src/main/java/org/libreccm/imexport/Imports.java b/ccm-core/src/main/java/org/libreccm/imexport/Processes.java
similarity index 80%
rename from ccm-core/src/main/java/org/libreccm/imexport/Imports.java
rename to ccm-core/src/main/java/org/libreccm/imexport/Processes.java
index 31a30778f..d0dcb5c79 100644
--- a/ccm-core/src/main/java/org/libreccm/imexport/Imports.java
+++ b/ccm-core/src/main/java/org/libreccm/imexport/Processes.java
@@ -23,22 +23,26 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
/**
- * Declares which entity types an implementation of {@link Importer} can
- * process.
+ * Declares which entity types an implementation of {@link Importer} and/or
+ * {@link Exporter} can process.
*
* @author Jens Pelzetter
*/
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@Target({ElementType.TYPE,
- ElementType.PARAMETER,
- ElementType.FIELD,
- ElementType.METHOD})
-public @interface Imports {
+ ElementType.PARAMETER,
+ ElementType.FIELD,
+ ElementType.METHOD})
+public @interface Processes {
- Class extends Exportable> value();
+ Class extends Exportable> type();
+
+ @Nonbinding
+ Class extends Exportable>[] dependsOn();
}
diff --git a/ccm-core/src/main/java/org/libreccm/modules/TreeNode.java b/ccm-core/src/main/java/org/libreccm/modules/TreeNode.java
index 7b7bcc1db..e3feae1fc 100644
--- a/ccm-core/src/main/java/org/libreccm/modules/TreeNode.java
+++ b/ccm-core/src/main/java/org/libreccm/modules/TreeNode.java
@@ -86,7 +86,7 @@ final class TreeNode {
}
void setDependentModules(final List dependentModules) {
- this.dependentModules = dependentModules;
+ this.dependentModules = new ArrayList<>(dependentModules);
}
void addDependentModule(final TreeNode node) {
@@ -102,7 +102,7 @@ final class TreeNode {
}
void setDependsOn(final List dependsOn) {
- this.dependsOn = dependsOn;
+ this.dependsOn = new ArrayList<>(dependsOn);
}
void addDependsOn(final TreeNode node) {