Add restore for archived content
Change-Id: Ia4287a44eba2261f91fee87b901b319ac0c05874
Signed-off-by: Michael Ochmann <michael.ochmann@sap.com>
diff --git a/org.eclipse.skalli.core/src/main/java/org/eclipse/skalli/core/rest/admin/ProjectBackupResource.java b/org.eclipse.skalli.core/src/main/java/org/eclipse/skalli/core/rest/admin/ProjectBackupResource.java
index 3c62d82..4d680d3 100644
--- a/org.eclipse.skalli.core/src/main/java/org/eclipse/skalli/core/rest/admin/ProjectBackupResource.java
+++ b/org.eclipse.skalli.core/src/main/java/org/eclipse/skalli/core/rest/admin/ProjectBackupResource.java
@@ -25,7 +25,9 @@
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
import org.eclipse.skalli.commons.CollectionUtils;
+import org.eclipse.skalli.commons.FormatUtils;
import org.eclipse.skalli.commons.ThreadPool;
import org.eclipse.skalli.core.storage.FileStorageComponent;
import org.eclipse.skalli.services.BundleProperties;
@@ -136,7 +138,10 @@
setStatus(Status.SUCCESS_NO_CONTENT);
return null;
}
+ boolean withHistory = accepted.contains("History"); //$NON-NLS-1$
+ int countItems = 0;
+ int countHistoryItems = 0;
ZipInputStream zipStream = null;
try {
zipStream = new ZipInputStream(entity.getStream());
@@ -150,22 +155,42 @@
LOG.info(MessageFormat.format("Restore: {0} is not recognized as entity key", entryName));
continue;
}
+ String category = parts[0];
+ String name = parts[1];
+ if (name.endsWith(".xml")) { //$NON-NLS-1$
+ name = name.substring(0, name.length() - 4);
+ };
+ String[] nameParts = StringUtils.split(name, '_');
+ String key = nameParts[0];
+ long timestamp = NumberUtils.toLong(nameParts.length == 2 ? nameParts[1] : null, -1L);
+
// ensure that the category of the entry, i.e. the directory name,
// is in the set of accepted categories
- String category = parts[0];
- String key = parts[1];
if (accepted.contains(category)) {
- if (key.endsWith(".xml")) { //$NON-NLS-1$
- key = key.substring(0, key.length() - 4);
- }
- try {
- storageService.write(category, key, zipStream);
- } catch (IOException e) {
- LOG.error(MessageFormat.format(
- "Failed to store entity with key {0} and category {1} ({2})",
- key, category, ERROR_ID_FAILED_TO_STORE), e);
- return createErrorRepresentation(Status.SERVER_ERROR_INTERNAL, ERROR_ID_FAILED_TO_STORE,
- "Failed to store the attached backup");
+ if (timestamp < 0) {
+ try {
+ storageService.write(category, key, zipStream);
+ ++countItems;
+ } catch (IOException e) {
+ LOG.error(MessageFormat.format(
+ "Failed to store entity with key {0} and category {1} ({2})",
+ key, category, ERROR_ID_FAILED_TO_STORE), e);
+ return createErrorRepresentation(Status.SERVER_ERROR_INTERNAL, ERROR_ID_FAILED_TO_STORE,
+ "Failed to store the attached backup");
+ }
+ } else if (withHistory) {
+ try {
+ storageService.writeToArchive(category, key, timestamp, zipStream);
+ ++countHistoryItems;
+ } catch (IOException e) {
+ LOG.error(MessageFormat.format(
+ "Failed to store history entry for timestamp {0} with key {1} and category {2} ({3})",
+ FormatUtils.formatUTCWithMillis(timestamp), key, category,
+ ERROR_ID_FAILED_TO_STORE), e);
+ return createErrorRepresentation(Status.SERVER_ERROR_INTERNAL,
+ ERROR_ID_FAILED_TO_STORE,
+ "Failed to store the attached backup");
+ }
}
} else {
LOG.info(MessageFormat.format("Restore: Excluded {0} (category ''{1}'' not accepted)",
@@ -182,6 +207,9 @@
} finally {
IOUtils.closeQuietly(zipStream);
}
+ if (LOG.isInfoEnabled()) {
+ LOG.info(MessageFormat.format("Restored {0} items and {1} history items", countItems, countHistoryItems));
+ }
// ensure that the persistence service attached to the storage
// refreshes all caches and reloads all entities --- do that
diff --git a/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/HistoryStorageItem.java b/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/HistoryStorageItem.java
index 377666e..35921c6 100644
--- a/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/HistoryStorageItem.java
+++ b/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/HistoryStorageItem.java
@@ -18,6 +18,7 @@
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
+import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
@@ -27,7 +28,10 @@
import org.eclipse.persistence.annotations.Index;
@Table(name = "HistoryStorage")
-@NamedQuery(name = "getItemsByCompositeKey", query = "SELECT r FROM HistoryStorageItem r WHERE r.category = :category AND r.id = :id")
+@NamedQueries({
+ @NamedQuery(name = "getItemsByCompositeKey", query = "SELECT r FROM HistoryStorageItem r WHERE r.category = :category AND r.id = :id"),
+ @NamedQuery(name = "getItemByTimestamp", query = "SELECT r FROM HistoryStorageItem r WHERE r.category = :category AND r.id = :id AND r.dateCreated = :dateCreated")
+})
@Entity
public class HistoryStorageItem {
@Id
@@ -43,7 +47,6 @@
@Temporal(TemporalType.TIMESTAMP)
private Date dateCreated;
@Lob
- @Column(length = 100000)
private String content;
public String getCategory() {
diff --git a/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/JPAStorageComponent.java b/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/JPAStorageComponent.java
index 2c727e6..b5bbd04 100644
--- a/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/JPAStorageComponent.java
+++ b/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/JPAStorageComponent.java
@@ -147,12 +147,17 @@
EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
- HistoryStorageItem histItem = new HistoryStorageItem();
- histItem.setCategory(category);
- histItem.setId(id);
- histItem.setContent(IOUtils.toString(blob, "UTF-8")); //$NON-NLS-1$
- histItem.setDateCreated(new Date(timestamp));
- em.persist(histItem);
+ HistoryStorageItem item = findHistoryItem(category, id, timestamp, em);
+ if (item == null) {
+ HistoryStorageItem newItem = new HistoryStorageItem();
+ newItem.setCategory(category);
+ newItem.setId(id);
+ newItem.setContent(IOUtils.toString(blob, "UTF-8")); //$NON-NLS-1$
+ newItem.setDateCreated(new Date(timestamp));
+ em.persist(newItem);
+ } else {
+ item.setContent(IOUtils.toString(blob, "UTF-8")); //$NON-NLS-1$
+ }
em.getTransaction().commit();
} finally {
em.close();
@@ -205,6 +210,18 @@
return em.find(StorageItem.class, new StorageId(category, id));
}
+ private static HistoryStorageItem findHistoryItem(String category, String id, long timestamp, EntityManager em) {
+ TypedQuery<HistoryStorageItem> query = em.createNamedQuery("getItemByTimestamp", HistoryStorageItem.class); //$NON-NLS-1$
+ query.setParameter("category", category); //$NON-NLS-1$
+ query.setParameter("id", id); //$NON-NLS-1$
+ query.setParameter("dateCreated", new Date(timestamp)); //$NON-NLS-1$
+ List<HistoryStorageItem> resultList = query.getResultList();
+ if (resultList.size() > 1) {
+ throw new IllegalStateException();
+ }
+ return resultList.isEmpty() ? null : resultList.get(0);
+ }
+
private static InputStream asStream(String content) throws IOException {
return new ByteArrayInputStream(content.getBytes("UTF-8")); //$NON-NLS-1$
}
diff --git a/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/StorageItem.java b/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/StorageItem.java
index 97eecb9..5634ca5 100644
--- a/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/StorageItem.java
+++ b/org.eclipse.skalli.jpa/src/main/java/org/eclipse/skalli/core/storage/jpa/StorageItem.java
@@ -10,7 +10,6 @@
import java.util.Date;
-import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@@ -34,7 +33,6 @@
@Id
private String id;
@Lob
- @Column(length = 100000)
private String content;
@Temporal(TemporalType.TIMESTAMP)
private Date dateModified;