/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.jobs.backupscheduler;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.coordinator.client.model.ProductName;
import com.emc.storageos.management.backup.BackupConstants;
/**
* Class to manage backup file names (tags) using by Backup Scheduler
*/
public class ScheduledBackupTag {
private static final Logger log = LoggerFactory.getLogger(ScheduledBackupTag.class);
private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(BackupConstants.SCHEDULED_BACKUP_DATE_PATTERN);
}
};
private static final Date MIN_DATE = new Date(0);
public static Date parseTimestamp(String timestampStr) throws ParseException {
return dateFormat.get().parse(timestampStr);
}
public static String toTimestamp(Date dt) {
return dateFormat.get().format(dt);
}
public static String toBackupTag(Date dt, String ver, int nodeCount) {
String timestamp = toTimestamp(dt);
return String.format(BackupConstants.SCHEDULED_BACKUP_TAG_TEMPLATE, ver, nodeCount, timestamp);
}
public static Date parseBackupTag(String tag) throws ParseException {
if (tag == null) {
throw new ParseException("Can't parse backup date because tag is null", -1);
}
int beginIndex = tag.length() - BackupConstants.SCHEDULED_BACKUP_DATE_PATTERN.length();
if (beginIndex < 0) {
throw new ParseException("Can't parse backup date from wrong begin index for tag: " + tag, beginIndex);
}
return parseTimestamp(tag.substring(beginIndex));
}
public static List<String> pickScheduledBackupTags(Collection<String> tags) {
ArrayList<String> scheduledTags = new ArrayList<>();
// Typically, this pattern String could match all tags produced by toBackupTag method
// also in consideration of extension, version part could be longer and node count could bigger
String regex = String.format(BackupConstants.SCHEDULED_BACKUP_TAG_REGEX_PATTERN, ProductName.getName(),
BackupConstants.SCHEDULED_BACKUP_DATE_PATTERN.length());
Pattern backupNamePattern = Pattern.compile(regex);
for (String tag : tags) {
if (backupNamePattern.matcher(tag).find()) {
scheduledTags.add(tag);
}
}
log.info("Scheduled backup tags: {}", scheduledTags);
return scheduledTags;
}
public static class TagComparator implements Comparator<String> {
private Date parseTagFallback(String tag) {
// If we cannot extract timestamp from tag, it must be non-scheduled backup. We
// just treat all manual backups as MIN_DATE, anyway they will be further ordered
// by raw string value if the timestamps are equal.
try {
return ScheduledBackupTag.parseBackupTag(tag);
} catch (ParseException e) {
log.info("Can't parse timestamp from the tag of non-scheduled backup({}, errorOffset is at {})",
e.getMessage(), e.getErrorOffset());
return MIN_DATE;
}
}
@Override
public int compare(String o1, String o2) {
Date d1 = parseTagFallback(o1);
Date d2 = parseTagFallback(o2);
int ret = d1.compareTo(d2);
return ret != 0 ? ret : o1.compareTo(o2);
}
}
}