我想在我的Java桌面应用程序上生成警报:
我正在使用Java,Eclipse,SWT进行开发,我的应用程序是使用Java Web Start从我的服务器部署的。我正在使用Mac OS X.6进行开发。
我想我有几个选择:
我真的不喜欢这个解决方案,我希望有更优雅的东西 参考:I would like to run my Java program on System Startup on Mac OS/Windows. How can I do this?
如果我将其作为系统服务运行,我可以从中受益,因为操作系统将确保我的软件:
我研究了一些我可以使用的资源:
我在系统服务选项中的问题是:
我的计划实施是否正确:
因此,在第一次运行时,应用程序将安装该服务并启动它。当应用程序关闭时,服务仍在运行,并且不再需要应用程序,除非它未注册 但是,我想我仍然会错过“在启动时运行”功能。
我是对的吗?我错过了什么吗?
在Unix上,我可以轻松使用cron表,而无需将应用程序升级为root用户。我不需要处理重启,系统日期更改等。看起来不错。
在Windows上,即使在使用Task Scheduler或At的命令行中,我也可以使用SchTasks。这看起来不错,但是我需要从XP到7兼容,我不能轻易测试它。
那你会怎么做?我错过了什么?您有什么建议可以帮助我选择最好和最优雅的解决方案吗?
答案 0 :(得分:3)
Bicou:很高兴您分享了解决方案!
请注意,“schtasks.exe”有一些本地化问题,如果你想用它创建一个每日触发器,在英语Windows上你必须使用“每日”,在德语(例如)你我必须改用“täglich”。
要解决此问题,我已使用schtasks.exe
选项实现了对/xml
的调用,提供了我通过模板创建的临时xml文件。
创建此类模板的最简单方法是“手动”创建任务,并在任务管理GUI工具中使用“export”功能。
答案 1 :(得分:2)
在您列出的可用选项中,恕我直言选项3更好。 由于您只需要外部触发器来执行应用程序,因此CRON或计划任务是比您列出的其他选项更好的解决方案。通过这种方式,您可以从应用程序中删除复杂性,并且您的应用程序也无需始终运行。它可以在外部触发,当执行结束时,您的应用程序将停止。因此,避免了不必要的资源消耗。
答案 2 :(得分:1)
您也可以尝试使用Quartz http://quartz-scheduler.org/。它有类似CRON的语法来安排工作。
答案 3 :(得分:1)
以下是我最终实施的内容:
public class AlarmManager {
public static final String ALARM_CLI_FORMAT = "startalarm:";
public static SupportedOS currentOS = SupportedOS.UNSUPPORTED_OS;
public enum SupportedOS {
UNSUPPORTED_OS,
MAC_OS,
WINDOWS,
}
public AlarmManager() {
final String osName = System.getProperty("os.name");
if (osName == null) {
L.e("Unable to retrieve OS!");
} else if ("Mac OS X".equals(osName)) {
currentOS = SupportedOS.MAC_OS;
} else if (osName.contains("Windows")) {
currentOS = SupportedOS.WINDOWS;
} else {
L.e("Unsupported OS: "+osName);
}
}
/**
* Windows only: name of the scheduled task
*/
private String getAlarmName(final long alarmId) {
return new StringBuilder("My_Alarm_").append(alarmId).toString();
}
/**
* Gets the command line to trigger an alarm
* @param alarmId
* @return
*/
private String getAlarmCommandLine(final long alarmId) {
return new StringBuilder("javaws -open ").append(ALARM_CLI_FORMAT).append(alarmId).append(" ").append(G.JNLP_URL).toString();
}
/**
* Adds an alarm to the system list of scheduled tasks
* @param when
*/
public void createAlarm(final Calendar when) {
// Create alarm
// ... stuff here
final long alarmId = 42;
// Schedule alarm
String[] commandLine;
Process child;
final String alarmCL = getAlarmCommandLine(alarmId);
try {
switch (currentOS) {
case MAC_OS:
final String cron = new SimpleDateFormat("mm HH d M '*' ").format(when.getTime()) + alarmCL;
commandLine = new String[] {
"/bin/sh", "-c",
"crontab -l | (cat; echo \"" + cron + "\") | crontab"
};
child = Runtime.getRuntime().exec(commandLine);
break;
case WINDOWS:
commandLine = new String[] {
"schtasks",
"/Create",
"/ST "+when.get(Calendar.HOUR_OF_DAY) + ":" + when.get(Calendar.MINUTE),
"/SC ONCE",
"/SD "+new SimpleDateFormat("dd/MM/yyyy").format(when.getTime()), // careful with locale here! dd/MM/yyyy or MM/dd/yyyy? I'm French! :)
"/TR \""+alarmCL+"\"",
"/TN \""+getAlarmName(alarmId)+"\"",
"/F",
};
L.d("create command: "+Util.join(commandLine, " "));
child = Runtime.getRuntime().exec(commandLine);
break;
}
} catch (final IOException e) {
L.e("Unable to schedule alarm #"+alarmId, e);
return;
}
L.i("Created alarm #"+alarmId);
}
/**
* Removes an alarm from the system list of scheduled tasks
* @param alarmId
*/
public void removeAlarm(final long alarmId) {
L.i("Removing alarm #"+alarmId);
String[] commandLine;
Process child;
try {
switch (currentOS) {
case MAC_OS:
commandLine = new String[] {
"/bin/sh", "-c",
"crontab -l | (grep -v \""+ALARM_CLI_FORMAT+"\") | crontab"
};
child = Runtime.getRuntime().exec(commandLine);
break;
case WINDOWS:
commandLine = new String[] {
"schtasks",
"/Delete",
"/TN \""+getAlarmName(alarmId)+"\"",
"/F",
};
child = Runtime.getRuntime().exec(commandLine);
break;
}
} catch (final IOException e) {
L.e("Unable to remove alarm #"+alarmId, e);
}
}
public void triggerAlarm(final long alarmId) {
// Do stuff
//...
L.i("Hi! I'm alarm #"+alarmId);
// Remove alarm
removeAlarm(alarmId);
}
}
用法很简单。使用以下方式安排新警报:
final AlarmManager m = new AlarmManager();
final Calendar cal = new GregorianCalendar();
cal.add(Calendar.MINUTE, 1);
m.createAlarm(cal);
触发这样的警报:
public static void main(final String[] args) {
if (args.length >= 2 && args[1] != null && args[1].contains(AlarmManager.ALARM_CLI_FORMAT)) {
try {
final long alarmId = Long.parseLong(args[1].replace(AlarmManager.ALARM_CLI_FORMAT, ""));
final AlarmManager m = new AlarmManager();
m.triggerAlarm(alarmId);
} catch (final NumberFormatException e) {
L.e("Unable to parse alarm !", e);
}
}
}
在Mac OS X.6和Windows Vista上测试过。类L
是System.out.println
的帮助者,G
保存我的全局常量(这里,我的服务器上的JNLP文件用于启动我的应用程序)。
答案 4 :(得分:0)
我相信你的情况是正确的。由于服务是系统特定的东西,恕我直言,你不应该使用通用包来覆盖它们,但是每个系统都有一个特定的机制。