/*
* 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 java.io.File;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
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.IOFileFilter;
import org.geoserver.GeoServerConfigurationLock.LockType;
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerDataDirectory;
import org.geoserver.platform.GeoServerExtensions;
import org.geotools.util.logging.Logging;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* Restore task
*
* @author Luca Morandini lmorandini@ieee.org
*/
@XStreamAlias("restore")
public class RestoreTask extends BrTask {
/** serialVersionUID */
private static final long serialVersionUID = -8249264471670677843L;
private final static Logger LOGGER = Logging.getLogger(RestoreTask.class.toString());
public RestoreTask(UUID id, String path, ConfigurableDispatcherCallback locker,
final GeoServerDataDirectory dataRoot) {
super(id, path, locker, dataRoot);
}
@Override
public void lock() {
this.locker.setLockType(LockType.READ);
this.locker.setEnabled(true);
}
/*
* Restore execution
*
* @see org.geoserver.br.BrTask#run()
*/
@Override
public void run() {
// If previous' backup info cannot be read, aborts the restore
// Writes info about backup in a file
BackupTask backupInfo = this.readBackupInfo(this.path);
if (backupInfo == null) {
LOGGER.severe("Backup data info were not written properly, the restore will not start");
this.state = BrTaskState.FAILED;
return;
}
// Sets up the filter to exclude some directories according to the previous backup info
IOFileFilter excludeFilter = this.getExcludeFilter(backupInfo.includeData,
backupInfo.includeGwc, backupInfo.includeLog);
// Sets up source and destination
File srcMount = new File(this.path);
File trgMount = this.dataRoot.root();
// Sets transaction
this.trans = new RestoreTransaction(this, srcMount, trgMount, excludeFilter);
try {
// Start transanction
this.trans.start();
if(checkForHalt()){
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 restore
int workSize = this.act.copy();
LOGGER.info("Restore " + this.id + " has started");
this.startTime = new Date();
this.state = BrTaskState.RUNNING;
// This is to keep track af restore advancement
while (workSize-- > 0) {
Future<File> future = cs.take();
try {
LOGGER.info("copied file: " + future.get());
} catch (ExecutionException e) {
LOGGER.log(Level.INFO,e.getLocalizedMessage(),e);
}
if(checkForHalt()){
ex.shutdown();
if(!ex.awaitTermination(5, TimeUnit.SECONDS)){
throw new RuntimeException("Unable to stop backup task");
}
return;
}
}
// Restore completed
this.trans.commit();
// reload the config from disk
getGeoServer().reload();
} catch (Exception e) {
LOGGER.log(Level.SEVERE,e.getLocalizedMessage(),e);
// In case of errors, rollback
this.trans.rollback();
} finally {
haltSemaphore.release();
}
}
private GeoServer getGeoServer() {
return (GeoServer) GeoServerExtensions.bean("geoServer");
}
}