Aktueller Stand ImExport UI
parent
39358f6c02
commit
210c0e08bb
|
|
@ -85,7 +85,6 @@ public abstract class AbstractEntityImExporter<T extends Exportable> {
|
||||||
|
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String exportEntity(final Exportable entity) throws ExportException {
|
public String exportEntity(final Exportable entity) throws ExportException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return objectMapper.writeValueAsString(entity);
|
return objectMapper.writeValueAsString(entity);
|
||||||
} catch (JsonProcessingException ex) {
|
} catch (JsonProcessingException ex) {
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,10 @@ public final class EntityImExporterTreeNode {
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hash = 7;
|
int hash = 7;
|
||||||
hash = 47
|
hash = 47 * hash
|
||||||
* hash
|
+ Objects.hashCode(
|
||||||
+ Objects
|
this.entityImExporter.getClass().getName()
|
||||||
.hashCode(this.entityImExporter.getClass().getName());
|
);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -59,6 +60,7 @@ import javax.json.JsonObjectBuilder;
|
||||||
import javax.json.JsonReader;
|
import javax.json.JsonReader;
|
||||||
import javax.json.JsonString;
|
import javax.json.JsonString;
|
||||||
import javax.json.JsonWriter;
|
import javax.json.JsonWriter;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Central service for importing and exporting entities.
|
* Central service for importing and exporting entities.
|
||||||
|
|
@ -106,8 +108,9 @@ public class ImportExport {
|
||||||
*
|
*
|
||||||
* @see CcmFilesConfiguration#dataPath
|
* @see CcmFilesConfiguration#dataPath
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void exportEntities(
|
public void exportEntities(
|
||||||
final List<Exportable> entities, final String exportName
|
final Collection<Exportable> entities, final String exportName
|
||||||
) {
|
) {
|
||||||
final JsonObjectBuilder manifestBuilder = Json.createObjectBuilder();
|
final JsonObjectBuilder manifestBuilder = Json.createObjectBuilder();
|
||||||
manifestBuilder.add("created",
|
manifestBuilder.add("created",
|
||||||
|
|
@ -162,7 +165,6 @@ public class ImportExport {
|
||||||
|
|
||||||
for (final Map.Entry<String, List<Exportable>> entry
|
for (final Map.Entry<String, List<Exportable>> entry
|
||||||
: typeEntityMap.entrySet()) {
|
: typeEntityMap.entrySet()) {
|
||||||
|
|
||||||
createExportedEntities(exportName,
|
createExportedEntities(exportName,
|
||||||
entry.getKey(),
|
entry.getKey(),
|
||||||
entry.getValue());
|
entry.getValue());
|
||||||
|
|
@ -182,8 +184,8 @@ public class ImportExport {
|
||||||
*
|
*
|
||||||
* @see CcmFilesConfiguration#dataPath
|
* @see CcmFilesConfiguration#dataPath
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void importEntities(final String importName) {
|
public void importEntities(final String importName) {
|
||||||
|
|
||||||
final String importsPath = String.format("imports/%s", importName);
|
final String importsPath = String.format("imports/%s", importName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
package org.libreccm.security;
|
package org.libreccm.security;
|
||||||
|
|
||||||
import org.libreccm.imexport.AbstractEntityImExporter;
|
import org.libreccm.imexport.AbstractEntityImExporter;
|
||||||
|
import org.libreccm.imexport.ExportException;
|
||||||
import org.libreccm.imexport.Exportable;
|
import org.libreccm.imexport.Exportable;
|
||||||
import org.libreccm.imexport.Processes;
|
import org.libreccm.imexport.Processes;
|
||||||
|
|
||||||
|
|
@ -55,4 +56,6 @@ public class RoleImExporter extends AbstractEntityImExporter<Role> {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,23 +18,28 @@
|
||||||
*/
|
*/
|
||||||
package org.libreccm.ui.admin.imexport;
|
package org.libreccm.ui.admin.imexport;
|
||||||
|
|
||||||
import com.arsdigita.ui.admin.importexport.ImportExportMonitor;
|
|
||||||
|
|
||||||
import org.libreccm.core.CoreConstants;
|
import org.libreccm.core.CoreConstants;
|
||||||
import org.libreccm.imexport.AbstractEntityImExporter;
|
import org.libreccm.imexport.AbstractEntityImExporter;
|
||||||
import org.libreccm.imexport.EntityImExporterTreeNode;
|
import org.libreccm.imexport.EntityImExporterTreeNode;
|
||||||
|
import org.libreccm.imexport.Exportable;
|
||||||
import org.libreccm.imexport.ImportExport;
|
import org.libreccm.imexport.ImportExport;
|
||||||
import org.libreccm.security.AuthorizationRequired;
|
import org.libreccm.security.AuthorizationRequired;
|
||||||
import org.libreccm.security.RequiresPrivilege;
|
import org.libreccm.security.RequiresPrivilege;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.mvc.Controller;
|
import javax.mvc.Controller;
|
||||||
import javax.mvc.Models;
|
import javax.mvc.Models;
|
||||||
|
import javax.ws.rs.FormParam;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,7 +55,7 @@ public class ImExportController {
|
||||||
private ImportExport importExport;
|
private ImportExport importExport;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ImportExportMonitor importExportMonitor;
|
private ImportExportTaskManager taskManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Models models;
|
private Models models;
|
||||||
|
|
@ -77,12 +82,65 @@ public class ImExportController {
|
||||||
.map(AbstractEntityImExporter::getEntityClass)
|
.map(AbstractEntityImExporter::getEntityClass)
|
||||||
.map(Class::getName)
|
.map(Class::getName)
|
||||||
.sorted()
|
.sorted()
|
||||||
.collect(Collectors.toList())
|
.collect(
|
||||||
|
Collectors.toMap(
|
||||||
|
clazz -> clazz,
|
||||||
|
clazz -> clazz,
|
||||||
|
this::noDuplicateKeys,
|
||||||
|
TreeMap::new
|
||||||
|
)
|
||||||
|
)
|
||||||
|
//.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
|
||||||
return "org/libreccm/ui/admin/imexport/export.xhtml";
|
return "org/libreccm/ui/admin/imexport/export.xhtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/export")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
public String exportEntities(
|
||||||
|
@FormParam("selectedEntities") final String[] selectedEntitiesParam,
|
||||||
|
@FormParam("exportName") final String exportName
|
||||||
|
) {
|
||||||
|
final Set<String> selectedEntities = Arrays
|
||||||
|
.stream(selectedEntitiesParam)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
final Set<EntityImExporterTreeNode> selectedNodes = importExport
|
||||||
|
.getExportableEntityTypes()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
node -> selectedEntities.contains(
|
||||||
|
node.getEntityImExporter().getEntityClass().getName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
final Set<EntityImExporterTreeNode> exportNodes = addRequiredEntities(
|
||||||
|
new HashSet<>(selectedNodes)
|
||||||
|
);
|
||||||
|
|
||||||
|
final Set<Class<? extends Exportable>> exportTypes = exportNodes
|
||||||
|
.stream()
|
||||||
|
.map(node -> node.getEntityImExporter().getEntityClass())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
taskManager.exportEntities(exportTypes, exportName);
|
||||||
|
|
||||||
|
// models.put(
|
||||||
|
// "exportEntities",
|
||||||
|
// exportNodes
|
||||||
|
// .stream()
|
||||||
|
// .map(node -> node.getEntityImExporter().getEntityClass().getName())
|
||||||
|
// .sorted()
|
||||||
|
// .collect(Collectors.joining("\n"))
|
||||||
|
// );
|
||||||
|
// return "org/libreccm/ui/admin/imexport/exporting.xhtml";
|
||||||
|
return "redirect:imexport";
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/import")
|
@Path("/import")
|
||||||
@AuthorizationRequired
|
@AuthorizationRequired
|
||||||
|
|
@ -91,4 +149,31 @@ public class ImExportController {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String noDuplicateKeys(final String str1, final String str2) {
|
||||||
|
throw new RuntimeException("No duplicate keys allowed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<EntityImExporterTreeNode> addRequiredEntities(
|
||||||
|
final Set<EntityImExporterTreeNode> selectedNodes
|
||||||
|
) {
|
||||||
|
boolean foundRequiredNodes = false;
|
||||||
|
final Set<EntityImExporterTreeNode> exportNodes = new HashSet<>(
|
||||||
|
selectedNodes
|
||||||
|
);
|
||||||
|
for (final EntityImExporterTreeNode node : selectedNodes) {
|
||||||
|
if (node.getDependsOn() != null
|
||||||
|
&& !node.getDependsOn().isEmpty()
|
||||||
|
&& !exportNodes.containsAll(node.getDependsOn())) {
|
||||||
|
exportNodes.addAll(node.getDependsOn());
|
||||||
|
foundRequiredNodes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundRequiredNodes) {
|
||||||
|
return addRequiredEntities(exportNodes);
|
||||||
|
} else {
|
||||||
|
return exportNodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.ui.admin.imexport;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class ImExportTask implements Comparable<ImExportTask> {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private LocalDateTime started;
|
||||||
|
|
||||||
|
private Future<?> status;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getStarted() {
|
||||||
|
return started;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStartedAsIso() {
|
||||||
|
return DateTimeFormatter.ISO_DATE_TIME.withZone(
|
||||||
|
ZoneId.systemDefault()).format(started
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setStarted(final LocalDateTime started) {
|
||||||
|
this.started = started;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<?> getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setStatus(final Future<?> status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDone() {
|
||||||
|
return status.isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void cancel() {
|
||||||
|
status.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 7;
|
||||||
|
hash = 23 * hash + Objects.hashCode(this.name);
|
||||||
|
hash = 23 * hash + Objects.hashCode(this.started);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof ImExportTask)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ImExportTask other = (ImExportTask) obj;
|
||||||
|
if (!other.canEqual(this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.name, other.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Objects.equals(this.started, other.getStarted());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canEqual(final Object obj) {
|
||||||
|
return obj instanceof ImExportTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final ImExportTask other) {
|
||||||
|
return Comparator
|
||||||
|
.nullsFirst(Comparator
|
||||||
|
.comparing(ImExportTask::getName)
|
||||||
|
.thenComparing(ImExportTask::getStarted)
|
||||||
|
)
|
||||||
|
.compare(this, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"%s{ "
|
||||||
|
+ "name = %s, "
|
||||||
|
+ "started = %s, "
|
||||||
|
+ "status = %s"
|
||||||
|
+ " }",
|
||||||
|
super.toString(),
|
||||||
|
name,
|
||||||
|
DateTimeFormatter.ISO_DATE_TIME.withZone(
|
||||||
|
ZoneId.systemDefault()
|
||||||
|
).format(started),
|
||||||
|
Objects.toString(status)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.ui.admin.imexport;
|
||||||
|
|
||||||
|
import org.libreccm.imexport.Exportable;
|
||||||
|
import org.libreccm.imexport.ImportExport;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import javax.ejb.AsyncResult;
|
||||||
|
import javax.ejb.Asynchronous;
|
||||||
|
import javax.ejb.Stateless;
|
||||||
|
import javax.ejb.TransactionAttribute;
|
||||||
|
import javax.ejb.TransactionAttributeType;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@Stateless
|
||||||
|
public class ImExportTasks {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ImportExport importExport;
|
||||||
|
|
||||||
|
@Asynchronous
|
||||||
|
@Transactional(Transactional.TxType.REQUIRES_NEW)
|
||||||
|
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
|
||||||
|
public Future<?> startExport(
|
||||||
|
final Collection<Exportable> entities,
|
||||||
|
final String exportName
|
||||||
|
) {
|
||||||
|
importExport.exportEntities(entities, exportName);
|
||||||
|
return new AsyncResult<>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Asynchronous
|
||||||
|
@Transactional(Transactional.TxType.REQUIRES_NEW)
|
||||||
|
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
|
||||||
|
public Future<?> startImport(final String importName) {
|
||||||
|
importExport.importEntities(importName);
|
||||||
|
return new AsyncResult<>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.ui.admin.imexport;
|
||||||
|
|
||||||
|
import org.libreccm.imexport.Exportable;
|
||||||
|
import org.libreccm.imexport.ImportExport;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import javax.ejb.AsyncResult;
|
||||||
|
import javax.ejb.Asynchronous;
|
||||||
|
import javax.ejb.Schedule;
|
||||||
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
import javax.persistence.criteria.Root;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
@Named("ImportExportTaskManager")
|
||||||
|
public class ImportExportTaskManager {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private EntityManager entityManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ImExportTasks imExportTasks;
|
||||||
|
|
||||||
|
private SortedSet<ImExportTask> exportTasks;
|
||||||
|
|
||||||
|
private SortedSet<ImExportTask> importTasks;
|
||||||
|
|
||||||
|
public ImportExportTaskManager() {
|
||||||
|
exportTasks = new TreeSet<>(
|
||||||
|
Comparator.comparing(
|
||||||
|
ImExportTask::getStarted)
|
||||||
|
.thenComparing(ImExportTask::getName)
|
||||||
|
);
|
||||||
|
importTasks = new TreeSet<>(
|
||||||
|
Comparator.comparing(
|
||||||
|
ImExportTask::getStarted)
|
||||||
|
.thenComparing(ImExportTask::getName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SortedSet<ImExportTask> getExportTasks() {
|
||||||
|
return Collections.unmodifiableSortedSet(exportTasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SortedSet<ImExportTask> getImportTasks() {
|
||||||
|
return Collections.unmodifiableSortedSet(importTasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public void exportEntities(
|
||||||
|
final Set<Class<? extends Exportable>> exportTypes,
|
||||||
|
final String exportName
|
||||||
|
) {
|
||||||
|
final Set<Exportable> entities = new HashSet<>();
|
||||||
|
for (final Class<? extends Exportable> type : exportTypes) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final Set<? extends Exportable> entitiesOfType = collectEntities(
|
||||||
|
(Class<Exportable>) type
|
||||||
|
);
|
||||||
|
entities.addAll(entitiesOfType);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ImExportTask task = new ImExportTask();
|
||||||
|
task.setName(exportName);
|
||||||
|
task.setStarted(LocalDateTime.now());
|
||||||
|
final Future<?> status = imExportTasks.startExport(
|
||||||
|
entities, exportName
|
||||||
|
);
|
||||||
|
task.setStatus(status);
|
||||||
|
exportTasks.add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void exportEntities(
|
||||||
|
// final Collection<Exportable> entities, final String exportName
|
||||||
|
// ) {
|
||||||
|
// final ImExportTask task = new ImExportTask();
|
||||||
|
// task.setName(exportName);
|
||||||
|
// task.setStarted(LocalDate.now());
|
||||||
|
// final Future<?> status = startExport(entities, exportName);
|
||||||
|
// task.setStatus(status);
|
||||||
|
// exportTasks.add(task);
|
||||||
|
// }
|
||||||
|
public void importEntities(final String importName) {
|
||||||
|
final ImExportTask task = new ImExportTask();
|
||||||
|
task.setName(importName);
|
||||||
|
task.setStarted(LocalDateTime.now());
|
||||||
|
final Future<?> status = imExportTasks.startImport(importName);
|
||||||
|
task.setStatus(status);
|
||||||
|
importTasks.add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schedule(hour = "*", minute = "*/5", persistent = false)
|
||||||
|
protected void removeFinishedTasks() {
|
||||||
|
exportTasks.removeIf(ImExportTask::isDone);
|
||||||
|
importTasks.removeIf(ImExportTask::isDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelTask(final ImExportTask task) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<? extends Exportable> collectEntities(
|
||||||
|
final Class<Exportable> ofType
|
||||||
|
) {
|
||||||
|
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
|
final CriteriaQuery<Exportable> query = builder.createQuery(ofType);
|
||||||
|
final Root<Exportable> from = query.from(ofType);
|
||||||
|
|
||||||
|
return new HashSet<>(
|
||||||
|
entityManager.createQuery(
|
||||||
|
query.select(from)
|
||||||
|
).getResultList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -36,7 +36,8 @@
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
id="#{cc.attrs.inputId}"
|
id="#{cc.attrs.inputId}"
|
||||||
name="#{cc.attrs.name}"
|
name="#{cc.attrs.name}"
|
||||||
type="checkbox" />
|
type="checkbox"
|
||||||
|
value="#{value}" />
|
||||||
<label for="#{cc.attrs.inputId}">#{cc.attrs.label}</label>
|
<label for="#{cc.attrs.inputId}">#{cc.attrs.label}</label>
|
||||||
</div>
|
</div>
|
||||||
</cc:implementation>
|
</cc:implementation>
|
||||||
|
|
|
||||||
|
|
@ -26,23 +26,31 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>#{AdminMessages['imexport.export.label']}</h1>
|
<h1>#{AdminMessages['imexport.export.label']}</h1>
|
||||||
|
|
||||||
<form action="#"
|
<form action="#{mvc.uri('ImExportController#exportEntities')}"
|
||||||
aria-describedby="export-help">
|
aria-describedby="export-help"
|
||||||
|
method="post">
|
||||||
<p id="export-help">#{AdminMessages['imexport.export.help']}</p>
|
<p id="export-help">#{AdminMessages['imexport.export.help']}</p>
|
||||||
|
|
||||||
<c:forEach items="#{exportableEntities}" var="entity">
|
<!-- <c:forEach items="#{exportableEntities}" var="entity">
|
||||||
<bootstrap:formCheck
|
<bootstrap:formCheck
|
||||||
inputId="#{entity.replace('.', '-')}"
|
inputId="#{entity.replace('.', '-')}"
|
||||||
label="#{entity}"
|
label="#{entity}"
|
||||||
name="#{entity.replace('.', '-')}"
|
name="selectedEntities"
|
||||||
value="#{entity}" />
|
value="#{entity}" />
|
||||||
</c:forEach>
|
</c:forEach>-->
|
||||||
|
|
||||||
|
<bootstrap:formGroupChecks options="#{exportableEntities}"
|
||||||
|
help="#{AdminMessages['imexport.export.exportentities.help']}"
|
||||||
|
inputId="exportentity"
|
||||||
|
label="#{AdminMessages['imexport.export.exportentities.label']}"
|
||||||
|
name="selectedEntities" />
|
||||||
|
|
||||||
<bootstrap:formGroupText
|
<bootstrap:formGroupText
|
||||||
help="#{AdminMessages['imexport.export.export_name.help']}"
|
help="#{AdminMessages['imexport.export.export_name.help']}"
|
||||||
inputId="exportName"
|
inputId="exportName"
|
||||||
label="#{AdminMessages['imexport.export.export_name.label']}"
|
label="#{AdminMessages['imexport.export.export_name.label']}"
|
||||||
name="exportName" />
|
name="exportName"
|
||||||
|
required="treu" />
|
||||||
|
|
||||||
<a class="btn btn-warning"
|
<a class="btn btn-warning"
|
||||||
href="#{mvc.uri('ImExportController#getImExportDashboard')}">
|
href="#{mvc.uri('ImExportController#getImExportDashboard')}">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
|
||||||
|
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
||||||
|
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||||
|
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
|
||||||
|
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
|
||||||
|
<ui:composition template="/WEB-INF/views/org/libreccm/ui/admin/ccm-admin.xhtml">
|
||||||
|
|
||||||
|
<ui:param name="activePage" value="imexport" />
|
||||||
|
<ui:param name="title" value="#{AdminMessages['imexport.label']}" />
|
||||||
|
|
||||||
|
<ui:define name="breadcrumb">
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
<a href="#{mvc.uri('ImExportController#getImExportDashboard')}">
|
||||||
|
#{AdminMessages['imexport.label']}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="breadcrumb-item active">
|
||||||
|
#{AdminMessages['imexport.export.label']}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ui:define>
|
||||||
|
|
||||||
|
<ui:define name="main">
|
||||||
|
<div class="container">
|
||||||
|
<h1>#{AdminMessages['imexport.export.label']}</h1>
|
||||||
|
|
||||||
|
<pre>#{exportEntities}</pre>
|
||||||
|
</div>
|
||||||
|
</ui:define>
|
||||||
|
|
||||||
|
</ui:composition>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col mb-4">
|
<div class="col mb-4">
|
||||||
<div aria-describedby="export-card-body"
|
<div aria-describedby="export-card-body"
|
||||||
class="card pt-2"
|
class="card pt-2"
|
||||||
|
|
@ -67,6 +67,100 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>#{AdminMessages['imexport.activeexports.heading']}</h2>
|
||||||
|
|
||||||
|
<c:choose>
|
||||||
|
<c:when test="#{ImportExportTaskManager.exportTasks.isEmpty()}">
|
||||||
|
<p>
|
||||||
|
#{AdminMessages['imexport.activeexports.none']}
|
||||||
|
</p>
|
||||||
|
</c:when>
|
||||||
|
<c:otherwise>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#{AdminMessages['imexport.activeexports.table.columns.name.heading']}</th>
|
||||||
|
<th>#{AdminMessages['imexport.activeexports.table.columns.started.heading']}</th>
|
||||||
|
<th>#{AdminMessages['imexport.activeexports.table.columns.status.heading']}</th>
|
||||||
|
<th>#{AdminMessages['imexport.activeexports.table.columns.actions.heading']}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<c:forEach items="#{ImportExportTaskManager.exportTasks}" var="task">
|
||||||
|
<tr>
|
||||||
|
<td>#{task.name}</td>
|
||||||
|
<td>#{task.started}</td>
|
||||||
|
<td>
|
||||||
|
<c:choose>
|
||||||
|
<c:when test="#{task.done}">
|
||||||
|
#{AdminMessages['imexport.activeexports.table.columns.status.finished']}
|
||||||
|
</c:when>
|
||||||
|
<c:otherwise>
|
||||||
|
#{AdminMessages['imexport.activeexports.table.columns.status.running']}
|
||||||
|
</c:otherwise>
|
||||||
|
</c:choose>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-warning" href="#">
|
||||||
|
#{AdminMessages['imexport.activeexports.table.columns.actions.button_label']}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</c:forEach>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</c:otherwise>
|
||||||
|
</c:choose>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>#{AdminMessages['imexport.activeimports.heading']}</h2>
|
||||||
|
|
||||||
|
<c:choose>
|
||||||
|
<c:when test="#{ImportExportTaskManager.importTasks.isEmpty()}">
|
||||||
|
<p>
|
||||||
|
#{AdminMessages['imexport.activeimports.none']}
|
||||||
|
</p>
|
||||||
|
</c:when>
|
||||||
|
<c:otherwise>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#{AdminMessages['imexport.activeimports.table.columns.name.heading']}</th>
|
||||||
|
<th>#{AdminMessages['imexport.activeimports.table.columns.started.heading']}</th>
|
||||||
|
<th>#{AdminMessages['imexport.activeimports.table.columns.status.heading']}</th>
|
||||||
|
<th>#{AdminMessages['imexport.activeimports.table.columns.actions.heading']}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<c:forEach items="#{ImportExportTaskManager.importTasks}" var="task">
|
||||||
|
<tr>
|
||||||
|
<td>#{task.name}</td>
|
||||||
|
<td>#{task.started}</td>
|
||||||
|
<td>
|
||||||
|
<c:choose>
|
||||||
|
<c:when test="#{task.done}">
|
||||||
|
#{AdminMessages['imexport.activeimports.table.columns.status.finished']}
|
||||||
|
</c:when>
|
||||||
|
<c:otherwise>
|
||||||
|
#{AdminMessages['imexport.activeimports.table.columns.status.running']}
|
||||||
|
</c:otherwise>
|
||||||
|
</c:choose>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-warning" href="#">
|
||||||
|
#{AdminMessages['imexport.activeimports.table.columns.actions.button_label']}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</c:forEach>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</c:otherwise>
|
||||||
|
</c:choose>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ui:define>
|
</ui:define>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -536,3 +536,23 @@ imexport.export.export_name.help=Name of the export archive
|
||||||
imexport.export.export_name.label=to
|
imexport.export.export_name.label=to
|
||||||
imexport.export.submit=Export
|
imexport.export.submit=Export
|
||||||
imexport.export.cancel=Cancel
|
imexport.export.cancel=Cancel
|
||||||
|
imexport.export.exportentities.help=Select the entity types to export. Additional required types will be selected automatically
|
||||||
|
imexport.export.exportentities.label=Export types
|
||||||
|
imexport.activeexports.heading=Active Exports
|
||||||
|
imexport.activeexports.table.columns.name.heading=Name
|
||||||
|
imexport.activeexports.table.columns.started.heading=Started
|
||||||
|
imexport.activeexports.table.columns.status.heading=Status
|
||||||
|
imexport.activeexports.table.columns.actions.heading=Actions
|
||||||
|
imexport.activeexports.table.columns.status.finished=Finished
|
||||||
|
imexport.activeexports.table.columns.status.running=In progress
|
||||||
|
imexport.activeexports.table.columns.actions.button_label=Cancel
|
||||||
|
imexport.activeexports.none=No active exports
|
||||||
|
imexport.activeimports.heading=Active Imports
|
||||||
|
imexport.activeimports.none=No active imports
|
||||||
|
imexport.activeimports.table.columns.name.heading=Name
|
||||||
|
imexport.activeimports.table.columns.started.heading=Started
|
||||||
|
imexport.activeimports.table.columns.status.heading=Status
|
||||||
|
imexport.activeimports.table.columns.actions.heading=Actions
|
||||||
|
imexport.activeimports.table.columns.status.finished=Finished
|
||||||
|
imexport.activeimports.table.columns.status.running=In progress
|
||||||
|
imexport.activeimports.table.columns.actions.button_label=Cancel
|
||||||
|
|
|
||||||
|
|
@ -536,3 +536,23 @@ imexport.export.export_name.help=Name des Export Archives
|
||||||
imexport.export.export_name.label=nach
|
imexport.export.export_name.label=nach
|
||||||
imexport.export.submit=Exportieren
|
imexport.export.submit=Exportieren
|
||||||
imexport.export.cancel=Abbrechen
|
imexport.export.cancel=Abbrechen
|
||||||
|
imexport.export.exportentities.help=W\u00e4hlen Sie die zu exportierenden Typen aus. Weitere ben\u00f6tigte Typen werden automatisch ausgew\u00e4hlt.
|
||||||
|
imexport.export.exportentities.label=Exportiere
|
||||||
|
imexport.activeexports.heading=Aktive Exporte
|
||||||
|
imexport.activeexports.table.columns.name.heading=Name
|
||||||
|
imexport.activeexports.table.columns.started.heading=Gestartet
|
||||||
|
imexport.activeexports.table.columns.status.heading=Status
|
||||||
|
imexport.activeexports.table.columns.actions.heading=Aktionen
|
||||||
|
imexport.activeexports.table.columns.status.finished=Abgeschlossen
|
||||||
|
imexport.activeexports.table.columns.status.running=In Arbeit
|
||||||
|
imexport.activeexports.table.columns.actions.button_label=Abbrechen
|
||||||
|
imexport.activeexports.none=Keine aktiven Exporte
|
||||||
|
imexport.activeimports.heading=Aktive Importe
|
||||||
|
imexport.activeimports.none=Keine aktiven Importe
|
||||||
|
imexport.activeimports.table.columns.name.heading=Name
|
||||||
|
imexport.activeimports.table.columns.started.heading=Gestartet
|
||||||
|
imexport.activeimports.table.columns.status.heading=Status
|
||||||
|
imexport.activeimports.table.columns.actions.heading=Aktionen
|
||||||
|
imexport.activeimports.table.columns.status.finished=Abgeschlossen
|
||||||
|
imexport.activeimports.table.columns.status.running=In Arbeit
|
||||||
|
imexport.activeimports.table.columns.actions.button_label=Abbrechen
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue