/*
* Copyright (c) 2001 - 2012 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.bkprst;
import it.geosolutions.tools.commons.listener.DefaultProgress;
import it.geosolutions.tools.io.file.CopyTree;
import it.geosolutions.tools.io.file.Remove;
import java.io.File;
import java.util.UUID;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.geoserver.config.GeoServerDataDirectory;
import org.geotools.util.logging.Logging;
/**
* @author Luca Morandini lmorandini@ieee.org
*
*/
public class BackupTask extends BrTask {
/** serialVersionUID */
private static final long serialVersionUID = 671444680723521282L;
// Flag to asvoid backup data directory
protected boolean includeData = false;
// Flag to asvoid backup GeoWebCache directory
protected boolean includeGwc = false;
// Flag to asvoid backup logs directory
protected boolean includeLog = false;
private final static Logger LOGGER = Logging.getLogger(BackupTask.class.toString());
public BackupTask(UUID id, String path, ConfigurableDispatcherCallback locker,
final GeoServerDataDirectory dataRoot) {
super(id, path, locker, dataRoot);
}
public void setIncludeData(boolean includeData) {
this.includeData = includeData;
}
public void setIncludeGwc(boolean includeGwc) {
this.includeGwc = includeGwc;
}
public void setIncludeLog(boolean includeLog) {
this.includeLog = includeLog;
}
/*
* Backup execution
*
* @see org.geoserver.br.BrTask#run()
*/
@Override
public void run() {
// Sets up the filter to exclude some directories according to the previous backup info
IOFileFilter excludeFilter = this.getExcludeFilter(this.includeData, this.includeGwc,
this.includeLog);
// Sets up source and destination
File srcMount = this.dataRoot.root();
File trgMount = new File(this.path);
// Sets transaction
this.trans = new BackupTransaction(this, srcMount, trgMount, excludeFilter);
try {
// Deletes dest directory if existing
if (trgMount.exists()) {
Remove.deleteDirectory(
trgMount,
FileFilterUtils.or(FileFilterUtils.directoryFileFilter(),
FileFilterUtils.fileFileFilter()), true, true);
}
// Starts transanction
this.trans.start();
if(checkForHalt()){
LOGGER.fine("run:Halt requested " + this.id);
return;
}
// Sets up the copy task
ExecutorService ex = Executors.newFixedThreadPool(2);
if (ex == null || ex.isTerminated()) {
throw new IllegalArgumentException(
"Unable to run asynchronously using a terminated or null ThreadPoolExecutor");
}
ExecutorCompletionService<File> cs = new ExecutorCompletionService<File>(ex);
this.act = new CopyTree(excludeFilter, cs, srcMount, trgMount);
this.act.addCopyListener(new DefaultProgress(this.id.toString()) {
public void onUpdateProgress(float percent) {
super.onUpdateProgress(percent);
progress = percent;
}
});
// Starts backup
int workSize = this.act.copy();
// This is to keep track af restore advancement
while (workSize-- > 0) {
Future<File> future;
try {
future = cs.take();
LOGGER.info("copied file: " + future.get());
} catch (Exception e) {
LOGGER.log(Level.INFO,e.getLocalizedMessage(),e);
}
if(checkForHalt()){
LOGGER.fine("run:Halt requested, shutting down threads " + this.id);
ex.shutdown();
if(!ex.awaitTermination(5, TimeUnit.SECONDS)){
throw new RuntimeException("Unable to stop backup task");
}
return;
}
}
// Writes info about backup
if (!this.writeBackupInfo(this.path)) {
LOGGER.severe("Backup data info were not written properly, a restore operation will fail on this data");
this.state = BrTaskState.FAILED;
}
if(checkForHalt()){
LOGGER.fine("run:Halt requested " + this.id);
return;
}
// Restore completed
this.trans.commit();
} catch (Exception e) {
LOGGER.log(Level.SEVERE,e.getLocalizedMessage(),e);
// In case of errors, rollbacks
this.trans.rollback();
} finally{
haltSemaphore.release();
}
}
}