/*
* 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.io.file.CopyTree;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.OrFileFilter;
import org.geoserver.GeoServerConfigurationLock.LockType;
import org.geoserver.config.GeoServerDataDirectory;
import org.geotools.util.logging.Logging;
/**
* Generic backup/restore task
*
* @author Luca Morandini lmorandini@ieee.org
*/
public abstract class BrTask implements Runnable, Serializable {
/** serialVersionUID */
private static final long serialVersionUID = -6428867493005214884L;
protected UUID id;
protected BrTaskState state;
protected Date startTime;
protected Date endTime;
protected String path;
protected float progress;
protected ConfigurableDispatcherCallback locker;
private final static Logger LOGGER = Logging.getLogger(BrManager.class.toString());
protected GeoServerDataDirectory dataRoot;
protected CopyTree act;
protected IOFileFilter dataFilter = FileFilterUtils.nameFileFilter("data", IOCase.INSENSITIVE);
protected IOFileFilter gwcFilter = FileFilterUtils.nameFileFilter("gwc", IOCase.INSENSITIVE);
protected IOFileFilter logFilter = FileFilterUtils.nameFileFilter("logs", IOCase.INSENSITIVE);
protected BrManager br;
protected static String INFOFILE= "backup.xml";
protected static String BACKUPEXT= ".backup";
private volatile boolean haltRequested=false;
protected final Semaphore haltSemaphore= new Semaphore(1);
protected BrTransaction trans;
public BrTask(UUID id, String path, ConfigurableDispatcherCallback locker) {
this.id = id;
this.state = BrTaskState.QUEUED;
this.progress = 0;
this.path = path;
this.locker = locker;
}
public BrTask(UUID id, String path, ConfigurableDispatcherCallback locker,
final GeoServerDataDirectory dataRoot) {
this(id, path, locker);
this.dataRoot = dataRoot;
}
public void setBrManager(BrManager br) {
this.br= br;
}
public void setDataRoot(final GeoServerDataDirectory dataRoot) {
this.dataRoot = dataRoot;
}
public UUID getId() {
return this.id;
}
public BrTaskState getState() {
return this.state;
}
public void setState(BrTaskState state) {
this.state = state;
}
public Date getStartTime() {
return this.startTime;
}
public Date getEndTime() {
return this.endTime;
}
public void setStartTime(Date time) {
this.startTime= time;
}
public void setEndTime(Date time) {
this.endTime= time;
}
/*
* Task execution (to be overriden by subclasses)
*
* @see java.lang.Runnable#run()
*/
public abstract void run();
public void lock() {
this.locker.setLockType(LockType.WRITE);
this.locker.setEnabled(true);
}
public void unlock() {
this.locker.setEnabled(false);
// XXX BRLockDispatcherCallback.THREAD_LOCK.remove();
}
/*
* Returns true if current task is a backup one, false if restore
*/
public boolean isBackup() {
if (this.getClass().getName().contains("BackupTask")) {
return true;
} else {
return false;
}
}
/**
* Returns an exclusion filter based on directories to avoid during backup based on parameters
*
* @param includeData
* Should data directory be included ?
* @param includeGwc
* Should GeoWebCache directory be included ?
* @param includeLog
* Should logs directory be included ?
*/
protected IOFileFilter getExcludeFilter(boolean includeData, boolean includeGwc,
boolean includeLog) {
List<IOFileFilter> filesToExclude = new ArrayList<IOFileFilter>();
if (!includeData) {
filesToExclude.add(this.dataFilter);
}
if (!includeGwc) {
filesToExclude.add(this.gwcFilter);
}
if (!includeLog) {
filesToExclude.add(this.logFilter);
}
OrFileFilter filesToExcludeFilter = new OrFileFilter();
filesToExcludeFilter.setFileFilters(filesToExclude);
return FileFilterUtils.notFileFilter(filesToExcludeFilter);
}
/**
* Writes an XML file containing data about current backup
*
* @path Directory to write the info in
*
* @return true on success, false otherwise
*/
protected boolean writeBackupInfo(String path) {
File xmlFile= new File(path + File.separatorChar + BrTask.INFOFILE);
try {
FileUtils.writeStringToFile(xmlFile, this.br.toXML(this));
} catch (IOException e) {
LOGGER.log(Level.FINER, e.getMessage(), e);
return false;
}
return true;
}
/**
* Reads an XML file containing data about last backup
*
* @path Directory get dasta from
*
* @return a BackupTask object containing info about previous backup
*/
protected BackupTask readBackupInfo(String path) {
File xmlFile= new File(path + File.separatorChar + BrTask.INFOFILE);
BackupTask backupInfo= new BackupTask(null, "", null, null);
try {
String xml= FileUtils.readFileToString(xmlFile);
this.br.fromXML(xml, backupInfo);
} catch (IOException e) {
LOGGER.log(Level.FINER, e.getMessage(), e);
return null;
}
return backupInfo;
}
/**
* @return the haltRequested
*/
protected boolean isHaltRequested() {
return haltRequested;
}
/**
* @param haltRequested the haltRequested to set
*/
protected void setHaltRequested() {
this.haltRequested = true;
}
/**
* Checks if an Halt was requested
*
* @return
*/
protected boolean checkForHalt() {
if(isHaltRequested()){
// cancel
if (this.act != null) {
this.act.setCancelled();
}
return true;
}
return false;
}
/*
* Stops current backup
*/
public void stop() {
LOGGER.info("Backup " + this.id + " stopped");
LOGGER.fine("stop:Halt requested " + this.id );
// request halt
setHaltRequested();
try {
// wait for stop
haltSemaphore.acquire();
} catch (InterruptedException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
throw new RuntimeException(e);
}
LOGGER.fine("stop:Semaphore taken " + this.id);
// closing all file handles...
Runtime.getRuntime().runFinalization();
Runtime.getRuntime().runFinalization();
System.gc();
System.gc();
System.gc();
LOGGER.fine("stop:About to rollback " + this.id);
if(trans!=null){
this.trans.rollback();
}
this.state = BrTaskState.STOPPED;
LOGGER.info("stop:STOPPED " + this.id);
}
}