Support for partial backups
Additional query parameters "from", "to" and "period" are introduced
that allow specifying the time frame for a backup.
"period" gives a time interval in the form <numeral><unit>, e.g.
"5d" or "7h". Supported units are "d" for days, "h" for hours and
"m" for minutes (all case insensitive).
"from" and "to" can be timestamps in ISO format, for instance
"from=2013-10-15T00:00:00Z", or time intervals like "-7d", which
is interpreted as "7 days before now".
"period" can be combined with either "from" or "to" to define, for
example, a certain time interval beginning at a given point in time
in the past. If both "from" and "to" are given, "period" is ignored.
If no time interval for the backup is specified, 1 day is assumed.
For a full backup, now the query parameter "all" must be added.
Change-Id: I70591c11536a7049752430bc8f8f6ff196e86a35
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 4d680d3..479b29d 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
@@ -38,7 +38,6 @@
import org.eclipse.skalli.services.persistence.PersistenceService;
import org.eclipse.skalli.services.persistence.StorageConsumer;
import org.eclipse.skalli.services.persistence.StorageService;
-import org.eclipse.skalli.services.search.SearchQuery;
import org.restlet.data.Disposition;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
@@ -55,9 +54,6 @@
private static final String FILE_NAME = "backup.zip"; //$NON-NLS-1$
- private static final String EXCLUDE_PARAM = "exclude"; //$NON-NLS-1$
- private static final String INCLUDE_PARAM = "include"; //$NON-NLS-1$
-
private static final String ACTION_PARAM = "action"; //$NON-NLS-1$
private static final String ACTION_OVERWRITE = "overwrite"; //$NON-NLS-1$
@@ -83,8 +79,11 @@
if (storageService == null) {
return createServiceUnavailableRepresentation(ERROR_ID_NO_STORAGE_SERVICE, "Storage Service");
}
- Set<String> categories = getCategories();
- ZipOutputRepresentation zipRepresentation = new ZipOutputRepresentation(storageService, categories);
+
+ BackupQuery query = new BackupQuery(getQueryAttributes());
+ Set<String> categories = getCategories(query);
+ ZipOutputRepresentation zipRepresentation = new ZipOutputRepresentation(storageService, categories,
+ query.getFrom(), query.getTo());
Disposition disposition = new Disposition(Disposition.TYPE_ATTACHMENT);
disposition.setFilename(FILE_NAME);
zipRepresentation.setDisposition(disposition);
@@ -103,8 +102,9 @@
return createServiceUnavailableRepresentation(ERROR_ID_NO_STORAGE_SERVICE, "Storage Service");
}
+ BackupQuery query = new BackupQuery(getQueryAttributes());
String action = getQueryAttribute(ACTION_PARAM);
- Set<String> categories = getCategories();
+ Set<String> categories = getCategories(query);
Set<String> accepted = new HashSet<String>();
Set<String> rejected = new HashSet<String>();
@@ -235,12 +235,10 @@
* result set. Then first add all categories contained in the include list
* and remove afterwards all entries contained in the exclude list.
*/
- private Set<String> getCategories() {
+ private Set<String> getCategories(BackupQuery query) {
Set<String> categories = new HashSet<String>(CATEGORIES);
- Set<String> include = CollectionUtils.asSet(StringUtils.split(getQueryAttribute(INCLUDE_PARAM),
- SearchQuery.PARAM_LIST_SEPARATOR));
- Set<String> exclude = CollectionUtils.asSet(StringUtils.split(getQueryAttribute(EXCLUDE_PARAM),
- SearchQuery.PARAM_LIST_SEPARATOR));
+ Set<String> include = query.getIncluded();
+ Set<String> exclude = query.getExcluded();
if (!include.isEmpty()) {
categories.removeAll(CATEGORIES);
}
@@ -265,14 +263,18 @@
private static final int BUFFER = 2048;
- private StorageService storageService;
- private Set<String> categories;
- private boolean withHistory;
+ private final StorageService storageService;
+ private final Set<String> categories;
+ private final long startDate;
+ private final long endDate;
+ private final boolean withHistory;
- public ZipOutputRepresentation(StorageService storageService, Set<String> categories) {
+ public ZipOutputRepresentation(StorageService storageService, Set<String> categories, long startDate, long endDate) {
super(MediaType.APPLICATION_ZIP);
this.storageService = storageService;
this.categories = categories;
+ this.startDate = startDate;
+ this.endDate = endDate;
this.withHistory = categories.contains("History"); //$NON-NLS-1$
}
@@ -303,8 +305,16 @@
}
private void write(String category, String key, final ZipOutputStream target) throws IOException {
- String entryName = MessageFormat.format("{0}/{1}.xml", category, key); //$NON-NLS-1$
- write(entryName, storageService.read(category, key), target);
+ storageService.read(category, key, new StorageConsumer() {
+ @Override
+ public void consume(String category, String key, long lastModified, InputStream blob)
+ throws IOException {
+ if (inRange(lastModified)) {
+ String entryName = MessageFormat.format("{0}/{1}.xml", category, key); //$NON-NLS-1$
+ write(entryName, blob, target);
+ }
+ }
+ });
}
private void writeHistory(String category, String key, final ZipOutputStream target) throws IOException {
@@ -312,9 +322,11 @@
@Override
public void consume(String category, String key, long lastModified, InputStream blob)
throws IOException {
- String entryName = MessageFormat.format("{0}/{1}_{2}.xml", //$NON-NLS-1$
- category, key, Long.toString(lastModified));
- write(entryName, blob, target);
+ if (inRange(lastModified)) {
+ String entryName = MessageFormat.format("{0}/{1}_{2}.xml", //$NON-NLS-1$
+ category, key, Long.toString(lastModified));
+ write(entryName, blob, target);
+ }
}
});
}
@@ -334,6 +346,9 @@
IOUtils.closeQuietly(source);
}
}
- }
+ private boolean inRange(long lastModified) {
+ return (startDate <= 0 || startDate <= lastModified) && (endDate <= 0 || lastModified <= endDate);
+ }
+ }
}