/* (c) 2016 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.backuprestore;
import java.util.Arrays;
import java.util.logging.Logger;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogException;
import org.geoserver.catalog.ValidationResult;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.config.util.XStreamPersister;
import org.geoserver.config.util.XStreamPersisterFactory;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.util.logging.Logging;
import org.opengis.filter.Filter;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.util.Assert;
import com.thoughtworks.xstream.XStream;
/**
* @author Alessio Fabiani, GeoSolutions S.A.S.
*
*/
public abstract class BackupRestoreItem<T> {
/**
* logger
*/
private static final Logger LOGGER = Logging.getLogger(BackupRestoreItem.class);
protected Backup backupFacade;
private Catalog catalog;
protected XStreamPersister xstream;
private XStream xp;
private boolean isNew;
private AbstractExecutionAdapter currentJobExecution;
private boolean dryRun;
private boolean bestEffort;
private XStreamPersisterFactory xStreamPersisterFactory;
private Filter filter;
public BackupRestoreItem(Backup backupFacade, XStreamPersisterFactory xStreamPersisterFactory) {
this.backupFacade = backupFacade;
this.xStreamPersisterFactory = xStreamPersisterFactory;
}
/**
* @return the xStreamPersisterFactory
*/
public XStreamPersisterFactory getxStreamPersisterFactory() {
return xStreamPersisterFactory;
}
/**
* @return the xp
*/
public XStream getXp() {
return xp;
}
/**
* @param xp the xp to set
*/
public void setXp(XStream xp) {
this.xp = xp;
}
/**
* @return the catalog
*/
public Catalog getCatalog() {
return catalog;
}
/**
* @return the isNew
*/
public boolean isNew() {
return isNew;
}
/**
* @return the currentJobExecution
*/
public AbstractExecutionAdapter getCurrentJobExecution() {
return currentJobExecution;
}
/**
* @return the dryRun
*/
public boolean isDryRun() {
return dryRun;
}
/**
* @return the bestEffort
*/
public boolean isBestEffort() {
return bestEffort;
}
/**
* @return the filter
*/
public Filter getFilter() {
return filter;
}
/**
* @param filter the filter to set
*/
public void setFilter(Filter filter) {
this.filter = filter;
}
@BeforeStep
public void retrieveInterstepData(StepExecution stepExecution) {
// Accordingly to the running execution type (Backup or Restore) we
// need to validate resources against the official GeoServer Catalog (Backup)
// or the temporary one (Restore).
//
// For restore operations the order matters.
JobExecution jobExecution = stepExecution.getJobExecution();
this.xstream = xStreamPersisterFactory.createXMLPersister();
if (backupFacade.getRestoreExecutions() != null
&& !backupFacade.getRestoreExecutions().isEmpty()
&& backupFacade.getRestoreExecutions().containsKey(jobExecution.getId())) {
this.currentJobExecution = backupFacade.getRestoreExecutions()
.get(jobExecution.getId());
this.catalog = ((RestoreExecutionAdapter) currentJobExecution).getRestoreCatalog();
this.isNew = true;
} else {
this.currentJobExecution = backupFacade.getBackupExecutions().get(jobExecution.getId());
this.catalog = backupFacade.getCatalog();
this.xstream.setExcludeIds();
this.isNew = false;
}
Assert.notNull(this.catalog, "catalog must be set");
this.xstream.setCatalog(this.catalog);
this.xstream.setReferenceByName(true);
this.xp = this.xstream.getXStream();
Assert.notNull(this.xp, "xStream persister should not be NULL");
JobParameters jobParameters = this.currentJobExecution.getJobParameters();
this.dryRun = Boolean
.parseBoolean(jobParameters.getString(Backup.PARAM_DRY_RUN_MODE, "false"));
this.bestEffort = Boolean
.parseBoolean(jobParameters.getString(Backup.PARAM_BEST_EFFORT_MODE, "false"));
final String cql = jobParameters.getString("filter", null);
if (cql != null && cql.contains("name")) {
try {
this.filter = ECQL.toFilter(cql);
} catch (CQLException e) {
throw new IllegalArgumentException("Filter is not valid!", e);
}
} else {
this.filter = null;
}
initialize(stepExecution);
}
/**
*
*/
protected abstract void initialize(StepExecution stepExecution);
/**
* @param result
* @param e
* @return
* @throws Exception
*/
protected boolean logValidationExceptions(ValidationResult result, Exception e) throws Exception {
CatalogException validationException = new CatalogException(e);
if(!isBestEffort()) {
if (result != null) {
result.throwIfInvalid();
} else {
throw e;
}
}
if(!isBestEffort()) {
getCurrentJobExecution().addFailureExceptions(Arrays.asList(validationException));
}
return false;
}
/**
* @param resource
*/
protected boolean logValidationExceptions(T resource, Throwable e) {
CatalogException validationException = e != null ? new CatalogException(e) :
new CatalogException("Invalid resource: " + resource);
if (!isBestEffort()) {
getCurrentJobExecution().addFailureExceptions(Arrays.asList(validationException));
throw validationException;
} else {
getCurrentJobExecution().addWarningExceptions(Arrays.asList(validationException));
}
return false;
}
/**
* @param resource
* @param ws
* @return
*/
protected boolean filteredResource(T resource, WorkspaceInfo ws, boolean strict) {
// Filtering Resources
if (getFilter() != null) {
if ((strict && ws == null) || (ws != null && !getFilter().evaluate(ws))) {
LOGGER.info("Skipped filtered resource: " + resource);
return true;
}
}
return false;
}
}