代码不多,因为我对如何开始有点不知所措。
我正在尝试创建一个备份Derby数据库并存储用户数据的应用程序。我有备份本身的代码,可以手动运行。我想创建一个功能来检查设置文件,并按照适当的时间表(每天,每周,每月)执行备份。我想我可以在启动时检查它,但是如果应用程序正在运行则存在问题,我希望定期检查时间。这个应用程序很可能会连续几天运行。
我也想让用户“睡觉”#34;如果有预定的时间,请备份几个小时。
我可以在启动时调用Thread.Sleep()并每隔X分钟/小时检查一次。同样,如果他们选择睡眠备份。我不确定这是否是最好的方法。我假设任何API调用都可能会这样做,但我想知道我是否在处理这样的线程时遗漏了一些东西。
Netbeans IDE&中是否有任何功能/库?我正在利用的平台,我可以帮助我构建这个功能吗?
由于
答案 0 :(得分:0)
以下是我实施它的方式。我稍微改变了实现方法,所以这个答案并不完全是问题的措辞。我删除了“睡眠”功能,但使用我提供的代码可以轻松实现它。我部分实现了,我将在下面显示代码。它主要涉及创建一些实现Runnable的类。未显示运行备份的实际代码。无论如何,这将是特定于平台的,所以请按照您的意愿处理。我们正在使用Derby,这就是我们的备份处理方式。
我会按课程和课程分解功能:
DatabaseBackupReminder。此类处理向用户发出的提示,告知用户上次备份后多长时间,并允许他们将提醒暂停X个小时。它本身就是一个线程,因此它可以在其他地方调用并且也可以睡眠,所以它不会一直ping数据库以查看上次备份的运行时间。
public class DatabaseBackupReminder extends Thread
/*****************Variables ****************/
String backupFrequency; //How often to backup? Daily, Monthly, Weekly, or Never
String backupTimeOfDay; //I don't use this, but the idea was to autobackup morning,
//day, or night
boolean backupIsSet = false; //Have they set a schedule?
Timestamp lastBackupRunTime; //Pulled from our Derby database to see when the backup was run
Timestamp backupScheduleSetTime; //Pulled from the DB to see when the user set the schedule
//This is so, if they set it to daily, we will check 24hrs from the set date for
//backup validity
Period periodSinceLastBackup; //Using the Joda library, we use this to calculate
boolean backupEverRan; //We check to see if they've ever backed up
//Useful logic for clear dialog purposes.
public enum enumBackupFrequencies {DAILY, WEEKLY, MONTHLY, NEVER} //use a valueOf with the backupFrequency.
//We're using java 1.7, no Switch on strings, this is a workaround
Herd herd;//Herd is a custom datatype we use, it's basically a wrapper around a Derby table.
/*******************methods***************************************/
public DatabaseBackupReminder(String backupFrequency, String backupTimeOfDay, Timestamp lastBackupRunTime, Timestamp backupScheduleSetTime, Herd herd)
//Constructor
//Herd is a custom datatype we use, it's basically a wrapper around a Derby table.
boolean getBackupStillValid() //Checks based on lastBackupRunTime, and backupEverRan to see
//if we have a valid backup
public void promptForBackup(Period duration, boolean backupEverRunx)
//Take's the duration & has it ever run and displays a message.
//Something like "It's been 2 weeks, 1 days since your last backup"
//Not fully implemented, this was scrapped, but I'll explain how I think it should have worked below
public void run()
//Main thread for this reminder
public String timeSinceLastBackupString()
//Calls it based on objects values, not specific values, see method below
public String timeSinceLastBackupString(Period duration, boolean backupEverRunx)
//Constructs the string used in promptForBackup
/********full method code**********/
public DatabaseBackupReminder(String backupFrequency, String backupTimeOfDay, Timestamp lastBackupRunTime, Timestamp backupScheduleSetTime, Herd herd) {
this.herd = herd;
if (backupFrequency == null) {
backupFrequency = "";
}
if (backupTimeOfDay == null) {
backupTimeOfDay = "";
}
if (backupScheduleSetTime == null) {
this.backupScheduleSetTime = new Timestamp(0);
} else {
this.backupScheduleSetTime = backupScheduleSetTime;
}
this.backupFrequency = backupFrequency;
this.backupTimeOfDay = backupTimeOfDay;
if (lastBackupRunTime == null) {
this.lastBackupRunTime = new Timestamp(0);
} else {
this.lastBackupRunTime = lastBackupRunTime;
}
periodSinceLastBackup = new Period(this.lastBackupRunTime.getTime(), Calendar.getInstance().getTimeInMillis());
if (backupFrequency.trim().length() > 1) {
backupIsSet = true;
}
backupEverRan = false;
if (this.lastBackupRunTime.getTime() != 0) {
backupEverRan = true;
}
}
boolean getBackupStillValid() {
if (lastBackupRunTime.getTime() > 0) {
backupEverRan = true;
} else {
return false;
}
if (backupFrequency.trim().length() > 1) {
backupIsSet = true;
}
if (backupIsSet) {
switch (enumBackupFrequencies.valueOf(backupFrequency.trim().toUpperCase())) {
case DAILY:
if (periodSinceLastBackup.getYears() > 1 || periodSinceLastBackup.getMonths() > 1 || periodSinceLastBackup.getWeeks() > 1 || periodSinceLastBackup.getDays() >= 1) {
return false;
}
break;
case WEEKLY:
if (periodSinceLastBackup.getYears() > 1 || periodSinceLastBackup.getMonths() > 1 || periodSinceLastBackup.getWeeks() >= 1) {
return false;
}
break;
case MONTHLY:
if (periodSinceLastBackup.getYears() > 1 || periodSinceLastBackup.getMonths() >= 1) {
return false;
}
break;
case NEVER:
}
}
if (backupEverRan) {
return true;
} else {
return false;
}
}
public void run() {
if (backupIsSet) {
switch (enumBackupFrequencies.valueOf(backupFrequency.trim().toUpperCase())) {
case DAILY:
if (periodSinceLastBackup.getYears() > 1 || periodSinceLastBackup.getMonths() > 1 || periodSinceLastBackup.getWeeks() > 1 || periodSinceLastBackup.getDays() > 1) {
promptForBackup(periodSinceLastBackup, backupEverRan);
}
break;
case WEEKLY:
if (periodSinceLastBackup.getYears() > 1 || periodSinceLastBackup.getMonths() > 1 || periodSinceLastBackup.getWeeks() > 1) {
promptForBackup(periodSinceLastBackup, backupEverRan);
}
break;
case MONTHLY:
if (periodSinceLastBackup.getYears() > 1 || periodSinceLastBackup.getMonths() > 1) {
promptForBackup(periodSinceLastBackup, backupEverRan);
}
break;
case NEVER:
}
}
}
public void promptForBackup(Period duration, boolean backupEverRun) {
int response;
long delay = 0;
response = JOptionPane.showConfirmDialog(null, timeSinceLastBackupString(duration, backupEverRun));
if (response == JOptionPane.NO_OPTION) {
//TODO: open "how long to remind" dialog
BackupSnoozePanel snoozePanel = new BackupSnoozePanel();
JOptionPane.showMessageDialog(null, snoozePanel);
switch (snoozePanel.BackupDelayInterval.getSelectedIndex()) {
case 0:
delay = 5000; //5 seconds, for testing
//delay = 60 * 60 * 1000; // 1 hour
break;
case 1:
delay = 10000; //10 seconds, for testing
//delay = 4 * 60 * 60 * 1000; // 4 hours
break;
case 2:
delay = 15000; //15 seconds, for testing
//delay = 8 * 60 * 60 * 1000; // 8 hours
break;
case 3:
delay = 20000; //20 seconds, for testing
///delay = 12 * 60 * 60 * 1000; // 12 hours
break;
case 4:
delay = 0; //next boot
break;
}
} else {
//TODO: run backup
}
try {
if (delay > 0) {
//TODO: Code to sleep this reminder. Thread.sleep(delay) probably
}
} catch (Exception ex) {
//TODO: something to handle exceptions
}
}//end promptForBackup
public String timeSinceLastBackupString(Period duration, boolean backupEverRunx) {
if (!backupEverRunx) {
return "The backup has never been run. Would you like to run one?";
}
String durationString = "It has been ";
if (duration.getYears() >= 1) {
durationString += duration.getYears() + " years";
}
if (duration.getMonths() >= 1) {
durationString += duration.getMonths() + " months";
}
if (duration.getWeeks() >= 1) {
durationString += duration.getWeeks() + " weeks ";
}
if (duration.getDays() >= 1) {
durationString += duration.getDays() + " days";
}
durationString += " since your last backup. Would you like to run one?";
return durationString;
}
public String timeSinceLastBackupString() {
return timeSinceLastBackupString(periodSinceLastBackup, backupEverRan);
}
DatabaseBackupController。这个类,因为它的名字,控制整个过程。从提醒,到执行实际的备份代码。
public class DatabaseBackupController
/***********variables*************/
String scheduleText; //Daily, Weekly, Monthy, or Never. It's set in our options panel.
String timeText; //Time of day to run the backup, morning, day, or night. As 04:00-12:00 etc…
Timestamp lastBackupRun; //Timestamp from DB (Herd is our abstracted class) from when it was last run.
Timestamp lastBackupRunScheduleSetTime; //Timestamp from DB when the backup was set.
Herd herd; //Herd is a custom datatype we use, it's basically a wrapper around a Derby table.
/***********Method Headers**********/
public DatabaseBackupController(Herd herd) //Constructor
//Sets global variables, based on values in DB
public void setupBackupReminder()
//calls DatabaseBackupReminder, passes global variables.
public boolean checkBackupReminder()
//Checks to make sure the current backup is valid within the duration since last backup
public void runBackupPrompt()
//When we are in fact going to backup, calls BackupRunner instance.
/**********full method code****************/
public DatabaseBackupController(Herd herd) {
this.herd = herd;
scheduleText = herd.getBackupSchedule();
timeText = herd.getBackupTime();
lastBackupRun = herd.getBackupScheduledLastRun();
lastBackupRunScheduleSetTime = herd.getBackupScheduledDatetime();
}
public void setupBackupReminder() {
DatabaseBackupReminder dbReminder = new DatabaseBackupReminder(scheduleText, timeText, lastBackupRun, lastBackupRunScheduleSetTime, herd);
Thread dbBackupThread = new Thread(dbReminder);
dbBackupThread.start();
}//end setupBackupReminder
public boolean checkBackupReminder() {
DatabaseBackupReminder dbReminder = new DatabaseBackupReminder(scheduleText, timeText, lastBackupRun, lastBackupRunScheduleSetTime, herd);
return dbReminder.getBackupStillValid();
}
public void runBackupPrompt() {
DatabaseBackupReminder dbReminder = new DatabaseBackupReminder(scheduleText, timeText, lastBackupRun, lastBackupRunScheduleSetTime, herd);
int response = JOptionPane.showConfirmDialog(null, dbReminder.timeSinceLastBackupString());
if (response == JOptionPane.YES_OPTION) {
//NbPreferences.forModule(BackupSettingsPanel.class).putLong("databaseschedullastrun", Calendar.getInstance().getTimeInMillis());
LoadStatusDialog lsd;
lsd = null;
lsd = new LoadStatusDialog(WindowManager.getDefault().getMainWindow(), false, true);
lsd.setVisible(true);
Thread br = new Thread(new BackupRunner(herd,lsd));
br.start();
}
}
}//end class
Class DbBackupAction处理本地备份方面。我们在本地备份,然后在另一个类的异地发送该文件。 这实现了runnable,因此它将异步处理备份而不会导致整个程序挂起。
class DbBackupAction implements Runnable {
private boolean backupSuccess;
public DbBackupAction() {
this.backupSuccess = false;
}
public void runBackup() {
}
@Override
public void run() {
Connection connection = JDBCUtils.getConnection();
String dbName = NbPreferences.forModule(DatabasePanel.class).get("dbName", "");
try {
DerbyUtils.backUpDatabase(connection, dbName);
} catch (SQLException ex) {
Exceptions.printStackTrace(ex);
}
setBackupSuccess(true);
}
/**
* @return the backupSuccess
*/
public boolean isBackupSuccess() {
return backupSuccess;
}
/**
* @param backupSuccess the backupSuccess to set
*/
public void setBackupSuccess(boolean backupSuccess) {
this.backupSuccess = backupSuccess;
}
}
BackupRunner处理现场/非现场备份。使用DbBackupAction&& RemoteBackupAction
class BackupRunner implements Runnable {
Herd herd;
LoadStatusDialog lsd;
BackupRunner(Herd herd, LoadStatusDialog lsd) {
this.herd = herd;
this.lsd = lsd;
}
@Override
public void run() {
DbBackupAction dba = new DbBackupAction();
Thread dbaThread = new Thread(dba);
dbaThread.start();
while (dbaThread.isAlive()) {
try {
dbaThread.join();
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
}
}
if (dba.isBackupSuccess()) {
RemoteBackupAction rba = new RemoteBackupAction();
lsd.setProgressBarIndeterminate(true);
Thread rbaThread = new Thread(rba);
rbaThread.start();
while (rbaThread.isAlive()) {
try {
rbaThread.join();
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
}
}
if (rba.isBackupSuccess()) {
herd.setBackupScheduledLastRun(new Timestamp(Calendar.getInstance().getTimeInMillis()));
HerdService hs = new HerdDaoService();
hs.update(herd);
EventBus.publish(new RefreshStartScreenEvent());
}
}
}
}
RemoteBackupAction处理非现场备份。
class RemoteBackupAction implements Runnable {
Thread thread;
LoadStatusDialog lsd;
File backupFile;
Pref pref;
private boolean backupSuccess;
public RemoteBackupAction() {
backupSuccess = false;
}
public void runThread() {
backupSuccess = true;
try {
DerbyUtils.remoteBackupDatabase(backupFile);
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null,
"This option is not available when working offline.");
System.out.println("SQLExcption: " + ex);
backupSuccess = false;
} catch (Exception ex) {
JOptionPane.showMessageDialog(null,
"Unable to connection to ftp site for remote backup.");
System.out.println("IOExcption: " + ex);
backupSuccess = false;
}
}
public void startOffsiteBackup() {
pref = CentralLookup.getDefault().lookup(Pref.class);
System.out.println("pref.isOnline(): " + pref.isOnline());
if (!pref.isOnline()) {
JOptionPane.showMessageDialog(null,
"This option is not available when working offline.");
return;
}
File[] files = DerbyUtils.getListOfBackups();
if ((files == null) || (files.length < 1)) {
JOptionPane.showMessageDialog(null,
"There are no backup files available for upload. "
+ "Please create a local backup.");
return;
}
Backup[] backups = new Backup[files.length];
if (files.length > 0) {
Date[] dates = new Date[files.length];
String[] herdCodes = new String[files.length];
SimpleDateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
for (int i = 0; i < files.length; i++) {
try {
String[] splitFileName = files[i].getName().split("_");
herdCodes[i] = splitFileName[0];
dates[i] = inFormat.parse(splitFileName[1].split("//.")[0]);
backups[i] = new Backup(herdCodes[i], files[i], files[i].getName(), dates[i]);
} catch (ParseException ex) {
Exceptions.printStackTrace(ex);
}
}
} else {
System.out.println("no backup files yet");
}
Arrays.sort(backups, Collections.reverseOrder());
if (backups[0] != null) {
this.backupFile = backups[0].getFile();
} else {
// Cancel button selected
return;
}
runThread();
}
/**
* @return the backupSuccess
*/
public boolean isBackupSuccess() {
return backupSuccess;
}
@Override
public void run() {
startOffsiteBackup();
}