CCM NG: Revised import/export system
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5697 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
a902504fe3
commit
1bd1c69ed4
|
|
@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class DependencyException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of <code>DependencyException</code> without detail
|
||||||
|
* message.
|
||||||
|
*/
|
||||||
|
public DependencyException() {
|
||||||
|
super();
|
||||||
|
//Nothing more
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>DependencyException</code> with the
|
||||||
|
* specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public DependencyException(final String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>DependencyException</code> which wraps
|
||||||
|
* the specified exception.
|
||||||
|
*
|
||||||
|
* @param exception The exception to wrap.
|
||||||
|
*/
|
||||||
|
public DependencyException(final Exception exception) {
|
||||||
|
super(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>DependencyException</code> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -18,19 +18,23 @@
|
||||||
*/
|
*/
|
||||||
package org.libreccm.imexport;
|
package org.libreccm.imexport;
|
||||||
|
|
||||||
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports an entity. Implementations must be annotated with {@link Imports} to
|
* Interface for importers/exporters. Implementations must be annotated with
|
||||||
* register the implementation in the Import/Export system.
|
* {@link Procsses} to register the implementation in the Import/Export service.
|
||||||
*
|
*
|
||||||
* Implementations must be CDI beans with annotated with {@link RequestScoped}.
|
* Implementations must also be CDI beans. It is recommended that the beans
|
||||||
|
* are {@link RequestScoped}.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
* @param <T> The entity type which can processed by the implementation.
|
* @param <T> The type of the entity which is processed by the implementation.
|
||||||
*/
|
*/
|
||||||
public interface EntityImporter<T extends Exportable> {
|
public interface EntityImExporter<T extends Exportable> {
|
||||||
|
|
||||||
T importEntity(JsonObject data);
|
T importEntity(JsonObject data);
|
||||||
|
|
||||||
|
JsonObject exportEntity(T entity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
final class EntityImExporterTreeManager {
|
||||||
|
|
||||||
|
public List<EntityImExporterTreeNode> generateTree(
|
||||||
|
final List<EntityImExporter<?>> imExporters)
|
||||||
|
throws DependencyException {
|
||||||
|
|
||||||
|
final Map<String, EntityImExporterTreeNode> 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<EntityImExporterTreeNode> nodeList = new ArrayList<>();
|
||||||
|
for (final Map.Entry<String, EntityImExporterTreeNode> entry
|
||||||
|
: nodes.entrySet()) {
|
||||||
|
|
||||||
|
nodeList.add(entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDependencyRelations(
|
||||||
|
final EntityImExporter<?> imExporter,
|
||||||
|
final Map<String, EntityImExporterTreeNode> 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<String, EntityImExporterTreeNode> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
final class EntityImExporterTreeNode {
|
||||||
|
|
||||||
|
private EntityImExporter<?> entityImExporter;
|
||||||
|
|
||||||
|
private List<EntityImExporterTreeNode> dependentImExporters;
|
||||||
|
|
||||||
|
private List<EntityImExporterTreeNode> 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<EntityImExporterTreeNode> getDependentImExporters() {
|
||||||
|
return Collections.unmodifiableList(dependentImExporters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDependentImExporters(
|
||||||
|
final List<EntityImExporterTreeNode> dependentImExporters) {
|
||||||
|
|
||||||
|
this.dependentImExporters = new ArrayList<>(dependentImExporters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addDependentImExporter(final EntityImExporterTreeNode node) {
|
||||||
|
|
||||||
|
dependentImExporters.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeDependentImExporter(final EntityImExporterTreeNode node) {
|
||||||
|
|
||||||
|
dependentImExporters.remove(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EntityImExporterTreeNode> getDependsOn() {
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(dependsOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDependsOn(final List<EntityImExporterTreeNode> 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
|
||||||
*/
|
|
||||||
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<JsonArray> getAssociations() {
|
|
||||||
return Optional.of(associations);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Qualifier
|
|
||||||
@Target({ElementType.TYPE,
|
|
||||||
ElementType.PARAMETER,
|
|
||||||
ElementType.FIELD,
|
|
||||||
ElementType.METHOD})
|
|
||||||
public @interface Exports {
|
|
||||||
|
|
||||||
Class<? extends Exportable> value();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -18,15 +18,29 @@
|
||||||
*/
|
*/
|
||||||
package org.libreccm.imexport;
|
package org.libreccm.imexport;
|
||||||
|
|
||||||
|
import org.libreccm.core.UnexpectedErrorException;
|
||||||
|
import org.libreccm.files.CcmFiles;
|
||||||
import org.libreccm.files.CcmFilesConfiguration;
|
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.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.enterprise.inject.Any;
|
import javax.enterprise.inject.Any;
|
||||||
import javax.enterprise.inject.Instance;
|
import javax.enterprise.inject.Instance;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.json.JsonReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Central service for importing and exporting entities.
|
* Central service for importing and exporting entities.
|
||||||
|
|
@ -37,12 +51,11 @@ import javax.inject.Inject;
|
||||||
public class ImportExport {
|
public class ImportExport {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Any
|
private CcmFiles ccmFiles;
|
||||||
private Instance<EntityImporter<?>> importers;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Any
|
@Any
|
||||||
private Instance<EntityExporter<?>> exporters;
|
private Instance<EntityImExporter<?>> imExporters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports the provided entities. The export will be written to a to the
|
* Exports the provided entities. The export will be written to a to the
|
||||||
|
|
@ -55,22 +68,20 @@ public class ImportExport {
|
||||||
*
|
*
|
||||||
* @param entities The entities to export.
|
* @param entities The entities to export.
|
||||||
* @param exportName The name file to which the export is written.
|
* @param exportName The name file to which the export is written.
|
||||||
* @param split Split the entities by package?
|
|
||||||
*
|
*
|
||||||
* @see CcmFilesConfiguration#dataPath
|
* @see CcmFilesConfiguration#dataPath
|
||||||
*/
|
*/
|
||||||
public void exportEntities(final List<Exportable> entities,
|
public void exportEntities(final List<Exportable> entities,
|
||||||
final String exportName,
|
final String exportName) {
|
||||||
final boolean split) {
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports all entities from the files in the {@link imports} directory inside
|
* Imports all entities from the files in the {@link imports} directory
|
||||||
* the CCM files data directory. The data to import can either be a file with
|
* inside the CCM files data directory. The data to import can either be a
|
||||||
* the provided name or a directory with the provided name. If it is a directory
|
* file with the provided name or a directory with the provided name. If it
|
||||||
* the entry file must also use the provided name.
|
* 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
|
* 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.
|
* the values from the import are used to update the entity.
|
||||||
|
|
@ -81,8 +92,128 @@ public class ImportExport {
|
||||||
*/
|
*/
|
||||||
public void importEntities(final String importName) {
|
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();
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ImportManifest> listAvailableImportArchivies() {
|
||||||
|
|
||||||
|
final List<String> 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<String> 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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,39 @@
|
||||||
*/
|
*/
|
||||||
package org.libreccm.imexport;
|
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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
* @param <T> The type of the entity which is processed by the implementation.
|
|
||||||
*/
|
*/
|
||||||
public interface EntityExporter<T extends Exportable> {
|
public class ImportManifest {
|
||||||
|
|
||||||
/**
|
private final Date created;
|
||||||
* Converts the provided entity to a JSON object and an optional array of
|
private final String onServer;
|
||||||
* associations.
|
private final List<String> types;
|
||||||
*
|
|
||||||
* @param entity The entity to export.
|
public ImportManifest(final Date created,
|
||||||
*
|
final String onServer,
|
||||||
* @return The JSON representation of the entity.
|
final List<String> types) {
|
||||||
*/
|
|
||||||
ExportedEntity exportEntity(T entity);
|
this.created = created;
|
||||||
|
this.onServer = onServer;
|
||||||
|
this.types = types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreated() {
|
||||||
|
return new Date(created.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOnServer() {
|
||||||
|
return onServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTypes() {
|
||||||
|
return Collections.unmodifiableList(types);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -23,11 +23,12 @@ import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.enterprise.util.Nonbinding;
|
||||||
import javax.inject.Qualifier;
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declares which entity types an implementation of {@link Importer} can
|
* Declares which entity types an implementation of {@link Importer} and/or
|
||||||
* process.
|
* {@link Exporter} can process.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*/
|
*/
|
||||||
|
|
@ -37,8 +38,11 @@ import javax.inject.Qualifier;
|
||||||
ElementType.PARAMETER,
|
ElementType.PARAMETER,
|
||||||
ElementType.FIELD,
|
ElementType.FIELD,
|
||||||
ElementType.METHOD})
|
ElementType.METHOD})
|
||||||
public @interface Imports {
|
public @interface Processes {
|
||||||
|
|
||||||
Class<? extends Exportable> value();
|
Class<? extends Exportable> type();
|
||||||
|
|
||||||
|
@Nonbinding
|
||||||
|
Class<? extends Exportable>[] dependsOn();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@ final class TreeNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDependentModules(final List<TreeNode> dependentModules) {
|
void setDependentModules(final List<TreeNode> dependentModules) {
|
||||||
this.dependentModules = dependentModules;
|
this.dependentModules = new ArrayList<>(dependentModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addDependentModule(final TreeNode node) {
|
void addDependentModule(final TreeNode node) {
|
||||||
|
|
@ -102,7 +102,7 @@ final class TreeNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDependsOn(final List<TreeNode> dependsOn) {
|
void setDependsOn(final List<TreeNode> dependsOn) {
|
||||||
this.dependsOn = dependsOn;
|
this.dependsOn = new ArrayList<>(dependsOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addDependsOn(final TreeNode node) {
|
void addDependsOn(final TreeNode node) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue