/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.jcr.ext.backup.impl;
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.ext.backup.BackupChain;
import org.exoplatform.services.jcr.ext.backup.BackupConfig;
import org.exoplatform.services.jcr.ext.backup.BackupConfigurationException;
import org.exoplatform.services.jcr.ext.backup.BackupJobListener;
import org.exoplatform.services.jcr.ext.backup.BackupOperationException;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import javax.jcr.RepositoryException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.events.StartElement;
/**
* Created by The eXo Platform SAS.
*
* @author <a href="mailto:peter.nedonosko@exoplatform.com.ua">Peter Nedonosko</a>
* @version $Id: BackupScheduler.java 760 2008-02-07 15:08:07Z pnedonosko $
*/
public class BackupScheduler
{
public enum TaskStatus {
VIRGIN, EXECUTED, FINISHED
};
protected Log log = ExoLogger.getLogger("exo.jcr.component.ext.BackupScheduler");
private final BackupManagerImpl backup;
private final BackupMessagesLog messages;
private final Timer timer;
private final List<WeakReference<SchedulerTask>> tasks = new ArrayList<WeakReference<SchedulerTask>>();
private class TaskConfig
{
private final DateFormat datef = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
BackupConfig backupConfig;
Date startTime;
Date stopTime;
long chainPeriod;
long incrPeriod;
TaskConfig(BackupConfig backupConfig, Date startTime, Date stopTime, long chainPeriod, long incrPeriod)
{
this.backupConfig = backupConfig;
this.startTime = startTime;
this.stopTime = stopTime;
this.chainPeriod = chainPeriod;
this.incrPeriod = incrPeriod;
}
TaskConfig(File taskFile) throws IOException, XMLStreamException, FactoryConfigurationError, ParseException
{
read(taskFile);
}
Date parseDate(String dateString) throws ParseException
{
if ("null".equals(dateString))
return null;
else
return datef.parse(dateString);
}
String formatDate(Date date)
{
return date == null ? "null" : datef.format(date);
}
void save(File taskFile) throws IOException, XMLStreamException, FactoryConfigurationError
{
TaskConfigWriter w = new TaskConfigWriter(taskFile);
w.writeBackupConfig(backupConfig);
w.writeSchedulerConfig(startTime, stopTime, chainPeriod, incrPeriod);
w.writeEndLog();
}
void read(File taskFile) throws IOException, XMLStreamException, FactoryConfigurationError, ParseException
{
TaskConfigReader r = new TaskConfigReader(taskFile);
r.readLogFile();
// done
this.backupConfig = r.backupConfig;
this.startTime = r.startTime;
this.stopTime = r.stopTime;
this.chainPeriod = r.chainPeriod;
this.incrPeriod = r.incrPeriod;
}
@Deprecated
void read_old(File taskFile) throws IOException, ParseException, BackupSchedulerException
{
char[] cbuf = new char[1024];
StringBuilder content = new StringBuilder();
// read file
FileReader fr = new FileReader(taskFile);
int r = 0;
while ((r = fr.read(cbuf)) >= 0)
{
content.append(cbuf, 0, r);
};
fr.close();
// parse file
String[] fc = content.toString().trim().split("\n");
if (fc.length > 1)
{
File _backupLog = null;
Date _startTime = null, _stopTime = null;
long _chainPeriod = -1, _incrPeriod = -1;
String[] terms = fc[fc.length - 1].split(",");
for (int i = 0; i < terms.length; i++)
{
if (i == 0)
{
_backupLog = new File(terms[i]);
}
else if (i == 1)
{
_startTime = datef.parse(terms[i]);
}
else if (i == 2)
{
String t = terms[i];
if (!"null".equals(t))
_stopTime = datef.parse(t);
}
else if (i == 3)
{
_chainPeriod = Long.parseLong(terms[i]);
}
else if (i == 4)
{
_incrPeriod = Long.parseLong(terms[i]);
}
}
if (_backupLog.exists())
{
// this.backupLog = _backupLog;
this.startTime = _startTime;
this.stopTime = _stopTime;
this.chainPeriod = _chainPeriod;
this.incrPeriod = _incrPeriod;
}
else
throw new BackupSchedulerException(
"Scheduler task skipped due to the error. Backup log file not exists " + _backupLog.getAbsolutePath()
+ ". Task file " + taskFile.getAbsolutePath());
}
else
throw new BackupSchedulerException("Scheduler task skipped due to bad configured task file "
+ taskFile.getAbsolutePath() + ". File doesn't contains configuration line.");
}
@Deprecated
File save_old(File taskFile) throws IOException
{
// File taskFile = new File(backupLog.getAbsolutePath() + ".task");
if (!taskFile.exists())
{
FileWriter fw = new FileWriter(taskFile);
fw.append("LogPath,StartTime,StopTime,ChainPeriod,IncrPeriod\n");
fw.append(taskFile.getAbsolutePath() + "," + datef.format(startTime) + ","
+ (stopTime != null ? datef.format(stopTime) : "null") + "," + chainPeriod + "," + incrPeriod);
fw.close();
return taskFile;
}
return null;
}
class TaskConfigWriter
{
Log logger = ExoLogger.getLogger("exo.jcr.component.ext.TaskConfigWriter");
final FileOutputStream logFile;
final XMLStreamWriter writer;
TaskConfigWriter(File logFile) throws FileNotFoundException, XMLStreamException, FactoryConfigurationError
{
this.logFile = new FileOutputStream(logFile);
writer = XMLOutputFactory.newInstance().createXMLStreamWriter(this.logFile);
writer.writeStartDocument();
writer.writeStartElement("backup-task-config");
writer.flush();
}
void writeBackupConfig(BackupConfig config) throws XMLStreamException
{
writer.writeStartElement("backup-config");
writer.writeStartElement("full-backup-type");
writer.writeCharacters(backup.getFullBackupType());
writer.writeEndElement();
writer.writeStartElement("incremental-backup-type");
writer.writeCharacters(backup.getIncrementalBackupType());
writer.writeEndElement();
if (config.getBackupDir() != null)
{
writer.writeStartElement("backup-dir");
writer.writeCharacters(config.getBackupDir().getAbsolutePath());
writer.writeEndElement();
}
if (config.getRepository() != null)
{
writer.writeStartElement("repository");
writer.writeCharacters(config.getRepository());
writer.writeEndElement();
}
if (config.getWorkspace() != null)
{
writer.writeStartElement("workspace");
writer.writeCharacters(config.getWorkspace());
writer.writeEndElement();
}
writer.writeStartElement("incremental-job-period");
writer.writeCharacters(Long.toString(config.getIncrementalJobPeriod()));
writer.writeEndElement();
writer.writeEndElement();
writer.flush();
}
void writeSchedulerConfig(Date startTime, Date stopTime, long chainPeriod, long incrPeriod)
throws XMLStreamException
{
writer.writeStartElement("scheduler-config");
writer.writeStartElement("start-time");
writer.writeCharacters(formatDate(startTime));
writer.writeEndElement();
writer.writeStartElement("stop-time");
writer.writeCharacters(formatDate(stopTime));
writer.writeEndElement();
writer.writeStartElement("chain-period");
writer.writeCharacters(String.valueOf(chainPeriod));
writer.writeEndElement();
writer.writeStartElement("incr-period");
writer.writeCharacters(String.valueOf(incrPeriod));
writer.writeEndElement();
writer.writeEndElement();
writer.flush();
}
void writeEndLog() throws XMLStreamException, IOException
{
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
logFile.close();
}
}
class TaskConfigReader
{
Log logger = ExoLogger.getLogger("exo.jcr.component.ext.TaskConfigReader");
final FileInputStream logFile;
final XMLStreamReader reader;
BackupConfig backupConfig;
Date startTime;
Date stopTime;
long chainPeriod;
long incrPeriod;
TaskConfigReader(File logFile) throws FileNotFoundException, XMLStreamException, FactoryConfigurationError
{
this.logFile = new FileInputStream(logFile);
this.reader = XMLInputFactory.newInstance().createXMLStreamReader(this.logFile);
}
void readLogFile() throws XMLStreamException, ParseException, IOException
{
try
{
while (true)
{
int eventCode = reader.next();
switch (eventCode)
{
case StartElement.START_ELEMENT :
String name = reader.getLocalName();
if (name.equals("backup-config"))
readBackupConfig();
if (name.equals("scheduler-config"))
readTaskConfig();
break;
case StartElement.END_DOCUMENT :
return;
}
}
}
finally
{
logFile.close();
}
}
private void readTaskConfig() throws XMLStreamException, MalformedURLException, ParseException
{
boolean endJobEntryInfo = false;
while (!endJobEntryInfo)
{
int eventCode = reader.next();
switch (eventCode)
{
case StartElement.START_ELEMENT :
String name = reader.getLocalName();
if (name.equals("start-time"))
startTime = parseDate(readContent());
if (name.equals("stop-time"))
stopTime = parseDate(readContent());
if (name.equals("chain-period"))
chainPeriod = Long.valueOf(readContent()).longValue();
if (name.equals("incr-period"))
incrPeriod = Long.valueOf(readContent()).longValue();
break;
case StartElement.END_ELEMENT :
String tagName = reader.getLocalName();
if (tagName.equals("scheduler-config"))
endJobEntryInfo = true;
break;
}
}
}
private void readBackupConfig() throws XMLStreamException
{
BackupConfig conf = new BackupConfig();
boolean endBackupConfig = false;
while (!endBackupConfig)
{
int eventCode = reader.next();
switch (eventCode)
{
case StartElement.START_ELEMENT :
String name = reader.getLocalName();
if (name.equals("backup-dir"))
conf.setBackupDir(new File(readContent()));
if (name.equals("repository"))
conf.setRepository(readContent());
if (name.equals("workspace"))
conf.setWorkspace(readContent());
if (name.equals("incremental-job-period"))
conf.setIncrementalJobPeriod(Long.valueOf(readContent()));
break;
case StartElement.END_ELEMENT :
String tagName = reader.getLocalName();
if (tagName.equals("backup-config"))
endBackupConfig = true;
break;
}
}
backupConfig = conf;
}
// TODO use cycle to read CHARACTERS
private String readContent() throws XMLStreamException
{
String content = null;
int eventCode = reader.next();
if (eventCode == StartElement.CHARACTERS)
content = reader.getText();
return content;
}
}
}
private class TaskThread extends Thread
{
private final CountDownLatch latch = new CountDownLatch(1);
public TaskThread(String name)
{
super(name);
}
void markReady()
{
latch.countDown();
}
void await() throws InterruptedException
{
latch.await();
}
}
class CleanupTasksListTask extends TimerTask
{
static final int PERIOD = 60000 * 30; // 30 min
@Override
public void run()
{
// pack tasks list if an empty references found
synchronized (tasks)
{
for (Iterator<WeakReference<SchedulerTask>> ti = tasks.iterator(); ti.hasNext();)
{
if (ti.next().get() == null)
// remove reference
ti.remove();
}
}
}
}
private abstract class SchedulerTask extends TimerTask
{
protected final BackupConfig config;
protected BackupChain chain;
protected TaskStatus status = TaskStatus.VIRGIN;
protected final BackupJobListener listener;
SchedulerTask(BackupConfig config, BackupJobListener listener)
{
this.config = config;
this.listener = listener;
}
@Override
public String toString()
{
return super.toString() + "-" + getChainName();
}
public String getChainName()
{
return config.getRepository() + "@" + config.getWorkspace();
}
public BackupChain getChain()
{
return chain;
}
protected TaskThread stop()
{
TaskThread stopper = new TaskThread("BackupScheduler_Task_" + getChainName() + "-stop")
{
@Override
public void run()
{
try
{
synchronized (config)
{
backup.stopBackup(chain);
if (log.isDebugEnabled())
log.debug("Chain stopped " + chain.getLogFilePath());
}
}
finally
{
markReady();
}
}
};
stopper.start();
return stopper;
}
protected TaskThread start()
{
TaskThread starter = new TaskThread("BackupScheduler_Task_" + getChainName() + "-start")
{
@Override
public void run()
{
try
{
synchronized (config)
{
chain = backup.startBackup(config, listener);
if (log.isDebugEnabled())
log.debug("Chain satarted " + chain.getLogFilePath());
}
}
catch (BackupOperationException e)
{
postError(getChainName() + " start", e);
}
catch (BackupConfigurationException e)
{
postError(getChainName() + " start", e);
}
catch (RepositoryException e)
{
postError(getChainName() + " start", e);
}
catch (RepositoryConfigurationException e)
{
postError(getChainName() + " start", e);
}
finally
{
markReady();
}
}
};
starter.start();
return starter;
}
protected void postError(String message, Throwable e)
{
messages.addError(message, e);
log.error(message, e);
if (listener != null)
listener.onError(null, message, e);
}
/**
* Backup task done, i.e. stopped and unscheduled
*/
protected TaskThread done()
{
TaskThread done = new TaskThread("BackupScheduler_Task_" + getChainName() + "-done")
{
@Override
public void run()
{
try
{
synchronized (config)
{
// cancel timer
cancel();
// stop the backup chain
backup.stopBackup(chain);
// remove task file config
removeTaskConfig();
if (log.isDebugEnabled())
log.debug("Task done (stopped and scheduler canceled) "
+ (chain != null ? chain.getLogFilePath() : "[not started]"));
}
}
finally
{
markReady();
}
}
};
done.start();
return done;
}
protected void removeTaskConfig()
{
// remove task file config
File taskFile =
new File(backup.getLogsDirectory().getAbsolutePath() + File.separator + config.getRepository() + "-"
+ config.getWorkspace() + ".task");
if (taskFile.exists())
{
taskFile.delete();
if (log.isDebugEnabled())
log.debug("Remove scheduler task " + taskFile.getAbsolutePath());
}
}
@Override
public boolean cancel()
{
status = TaskStatus.FINISHED;
if (log.isDebugEnabled())
log.debug("Task scheduling canceled " + (chain != null ? chain.getLogFilePath() : "[not started]"));
return super.cancel();
}
}
// impl of p.3,4
private class PeriodTask extends SchedulerTask
{
PeriodTask(BackupConfig config, BackupJobListener listener)
{
super(config, listener);
}
@Override
public void run()
{
if (status == TaskStatus.VIRGIN)
{
// start
start();
status = TaskStatus.EXECUTED;
}
else if (status == TaskStatus.EXECUTED)
{
// stop backup and cancel scheduling
done();
}
else
{
// do nothing or warn (shouldn't occurs)
log.warn("Chain already task finished " + getChainName() + ", " + this);
}
}
}
// impl of p.5,6
// &
// impl of p7,8 (stopTime == null)
private class PeriodicTask extends SchedulerTask
{
private final Date stopTime;
PeriodicTask(BackupConfig config, Date stopTime, BackupJobListener listener)
{
super(config, listener);
this.stopTime = stopTime;
}
@Override
public void run()
{
if (chain != null && chain.isFinished())
{
// cancel scheduling
cancel();
// remove task file config
removeTaskConfig();
}
else if (stopTime != null && new Date().after(stopTime))
{
// stop backup and cancel scheduling
done();
}
else if (status == TaskStatus.VIRGIN)
{
// start
start();
status = TaskStatus.EXECUTED;
}
else if (status == TaskStatus.EXECUTED)
{
// stop current
try
{
stop().await(); // wait if stop finished
}
catch (InterruptedException e)
{
postError("Can't stop task for periodic rotation ", e);
}
// start next
start();
}
else
{
// do nothing or warn (shouldn't occurs)
log.warn("Chain already task finished " + getChainName() + ", " + this);
}
}
}
// impl of p.1,2
private class RunOnceTask extends SchedulerTask
{
RunOnceTask(BackupConfig config, BackupJobListener listener)
{
super(config, listener);
}
@Override
public void run()
{
// start
start();
// remove task file config
removeTaskConfig();
}
}
BackupScheduler(BackupManagerImpl backup, BackupMessagesLog messages)
{
this.backup = backup;
this.timer =
new Timer("BackupScheduler_Timer_" + new SimpleDateFormat("yyyyMMdd.HHmmss.SSS").format(new Date()), true);
// tasks list cleanup task
this.timer.schedule(new CleanupTasksListTask(), CleanupTasksListTask.PERIOD, CleanupTasksListTask.PERIOD);
this.messages = messages;
// don't ask timer to cancel tasks
// registerShutdownHook();
}
private void registerShutdownHook()
{
// register shutdownhook for final cancel all taskes scheduled
try
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
timer.cancel();
}
});
}
catch (IllegalStateException e)
{
// can't register shutdownhook
}
}
public BackupMessage[] getErrors()
{
return messages.getMessages();
}
/**
* Restore scheduler after system shutdown etc. Called from manager at start.
*
* Should restore the scheduler tasks if start and stop time are correct and will be occured in
* future. Or should restore and to continue the tasks if start time reached but stop time in
* future or periodic scheduling enabled for the task (including incremental configuration too).
*
* @param taskFile
* @throws ParseException
* @throws BackupSchedulerException
* @throws BackupOperationException
* @throws RepositoryConfigurationException
* @throws RepositoryException
* @throws BackupConfigurationException
* @throws IOException
*/
void restore(final File taskFile) throws BackupSchedulerException, BackupOperationException,
BackupConfigurationException, RepositoryException, RepositoryConfigurationException
{
try
{
TaskConfig tconf = new TaskConfig(taskFile);
// check if the task is not expired
final Date now = new Date();
// by start time and periodic parameters
if ((tconf.stopTime != null && tconf.stopTime.after(now)) || tconf.chainPeriod > 0 || tconf.incrPeriod > 0)
{
// by stop time
// TODO restore without scheduler now. Add task search capabilities to the scheduler and add
// listener to a task
schedule(tconf.backupConfig, tconf.startTime, tconf.stopTime, tconf.chainPeriod, tconf.incrPeriod, null);
} // else - the start time in past and no periodic configuration found
}
catch (IOException e)
{
throw new BackupSchedulerException("Can't restore scheduler from task file " + taskFile.getAbsolutePath(), e);
}
catch (ParseException e)
{
throw new BackupSchedulerException("Can't restore scheduler from task file " + taskFile.getAbsolutePath(), e);
}
catch (XMLStreamException e)
{
throw new BackupSchedulerException("Can't restore scheduler from task file " + taskFile.getAbsolutePath(), e);
}
catch (FactoryConfigurationError e)
{
throw new BackupSchedulerException("Can't restore scheduler from task file " + taskFile.getAbsolutePath(), e);
}
}
/**
* Schedule backup task with given configuration and scheduler parameters. The behaviour of a task
* vary depending on scheduler parameters. If specified
* <ul>
* <li>1. startTime only - run once forever</li>
* <li>2. startTime + incrementalPeriod - run once forever (with incremental backup)</li>
* <li>3. startTime, endTime - run during given period</li>
* <li>4. startTime, endTime + incrementalPeriod - run during given period (with incremental
* backup)</li>
* <li>5. startTime, endTime, chainPeriod - run periodic during given period</li>
* <li>6. startTime, endTime, chainPeriod + incrementalPeriod - run periodic during given period
* (with incremental backup)</li>
* <li>7. startTime, chainPeriod - run periodic forever</li>
* <li>8. startTime, chainPeriod + incrementalPeriod - run periodic forever (with incremental
* backup)</li>
* </ul>
*
* @param config
* @param startTime
* - task start time
* @param stopTime
* - task stop time, may be null i.e. the task will be executed forever
* @param chainPeriod
* - task chain period, means periodic execution of the configured backup chain
* @param incrementalPeriod
* - incr period
* @param listener
* - listener for each job produced by an each backup chain
* @return
* @throws BackupSchedulerException
*/
public void schedule(BackupConfig config, Date startTime, Date stopTime, long chainPeriod, long incrementalPeriod)
throws BackupSchedulerException
{
schedule(config, startTime, stopTime, chainPeriod, incrementalPeriod, null);
}
/**
* Schedule backup task with given configuration and scheduler parameters. The behaviour of a task
* vary depending on scheduler parameters. If specified
* <ul>
* <li>1. startTime only - run once forever</li>
* <li>2. startTime + incrementalPeriod - run once forever (with incremental backup)</li>
* <li>3. startTime, endTime - run during given period</li>
* <li>4. startTime, endTime + incrementalPeriod - run during given period (with incremental
* backup)</li>
* <li>5. startTime, endTime, chainPeriod - run periodic during given period</li>
* <li>6. startTime, endTime, chainPeriod + incrementalPeriod - run periodic during given period
* (with incremental backup)</li>
* <li>7. startTime, chainPeriod - run periodic forever</li>
* <li>8. startTime, chainPeriod + incrementalPeriod - run periodic forever (with incremental
* backup)</li>
* </ul>
*
* The method will return immediate, a task will be scheduled and started as independent thread.
*
* @param config
* @param startTime
* - task start time
* @param stopTime
* - task stop time, may be null i.e. the task will be executed forever
* @param chainPeriod
* - task chain period, means periodic execution of the configured backup chain
* @param incrementalPeriod
* - incr period
* @param listener
* - listener for each job produced by an each backup chain
* @return
* @throws BackupSchedulerException
*/
public void schedule(BackupConfig config, Date startTime, Date stopTime, long chainPeriod, long incrementalPeriod,
BackupJobListener listener) throws BackupSchedulerException
{
long chainPeriodMilliseconds = chainPeriod * 1000;
if (incrementalPeriod > 0)
config.setIncrementalJobPeriod(incrementalPeriod); // override ones from config
SchedulerTask ctask;
if (stopTime != null)
{
if (stopTime.after(startTime))
{
if (chainPeriodMilliseconds > 0)
{
ctask = new PeriodicTask(config, stopTime, listener);
// the task will be executed each time chainPeriod exceeded and stopped at stopTime
timer.schedule(ctask, startTime, chainPeriodMilliseconds);
}
else
{
long stopPeriod = stopTime.getTime() - startTime.getTime();
ctask = new PeriodTask(config, listener);
// the task will be executed twice, second execution will means stop
timer.schedule(ctask, startTime, stopPeriod);
}
}
else
throw new BackupSchedulerException("Stop time (" + stopTime + ") should be after the start time ("
+ startTime + ")");
}
else
{
if (chainPeriodMilliseconds > 0)
{
ctask = new PeriodicTask(config, null, listener);
// the task will be executed each time chainPeriod exceeded and never stopped there
timer.schedule(ctask, startTime, chainPeriodMilliseconds);
}
else
{
ctask = new RunOnceTask(config, listener);
// the task will executed once at given startTime
timer.schedule(ctask, startTime);
}
}
synchronized (tasks)
{
tasks.add(new WeakReference<SchedulerTask>(ctask));
}
TaskConfig tc = new TaskConfig(config, startTime, stopTime, chainPeriod, incrementalPeriod);
try
{
// backup.getLogsDirectory().getAbsolutePath()
File taskFile =
new File(backup.getLogsDirectory().getAbsolutePath() + File.separator + config.getRepository() + "-"
+ config.getWorkspace() + ".task");
if (taskFile.exists())
throw new BackupSchedulerException("Task for repository '" + config.getRepository() + "' workspace '"
+ config.getWorkspace() + "' already exists. File " + taskFile.getAbsolutePath());
tc.save(taskFile); // save task config
}
catch (IOException e)
{
throw new BackupSchedulerException("Can't save scheduler task file " + e, e);
}
catch (XMLStreamException e)
{
throw new BackupSchedulerException("Can't save scheduler task file " + e, e);
}
catch (FactoryConfigurationError e)
{
throw new BackupSchedulerException("Can't save scheduler task file " + e, e);
}
}
/**
* Search task by repository and workspace names
*
* @param repository
* - name string
* @param workspace
* - name string
*
* @return SchedulerTask
*/
public SchedulerTask findTask(String repository, String workspace)
{
synchronized (tasks)
{
for (Iterator<WeakReference<SchedulerTask>> ti = tasks.iterator(); ti.hasNext();)
{
WeakReference<SchedulerTask> tr = ti.next();
SchedulerTask task = tr.get();
if (task != null && task.config.getRepository().equals(repository)
&& task.config.getWorkspace().equals(workspace))
{
return task;
}
}
}
return null;
}
/**
* Unshedule the task scheduled before with the given configuration. The method will waits till
* the task will be stopped.
*
* @param config
* - configuration used for a task search
* @return - true if task was searched and stopped ok
* @throws BackupSchedulerException
*/
public boolean unschedule(BackupConfig config) throws BackupSchedulerException
{
synchronized (tasks)
{
for (Iterator<WeakReference<SchedulerTask>> ti = tasks.iterator(); ti.hasNext();)
{
WeakReference<SchedulerTask> tr = ti.next();
SchedulerTask task = tr.get();
if (task != null && task.config.getRepository().equals(config.getRepository())
&& task.config.getWorkspace().equals(config.getWorkspace()))
{
// remove task
try
{
task.done().await();
}
catch (InterruptedException e)
{
throw new BackupSchedulerException("Task stop operation fails " + e, e);
}
ti.remove();
return true;
}
}
}
return false;
}
}