Transforming iCal Calendars with Java
Pages: 1, 2, 3
Saving Back to Disk
Most of the work is done. We need to save the calendar back to disk, which amounts to reversing the process you followed when reading from disk. There is one more subtle point. Look back at the iCal picture from the first section. Notice this line.
X-WR-CALNAME;VALUE=TEXT:example
The calendar's name is stored as part of the text. Since we will be
saving the calendar under a new name, we also need to change this value in
the text. Once again we use reg ex to locate the string to be changed and
supply the new value in the changeCalendarName()
method. Here's the code for saving the calendar back to disk.
package ical;
import java.io.File;
import java.io.IOException;
import java.io.FileWriter;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class ICalendarFromString {
private static final String CALENDAR_HOME = "Calendar/";
private static FileWriter fileWriter;
public static void saveStringAsCalendarFile(String contents,
String destinationCalendar)
throws CalendarNotSavedException {
createCalendarFileWriter(destinationCalendar);
contents = changeCalendarName(contents, destinationCalendar);
writeCalendarToFile(contents);
}
private static void createCalendarFileWriter(String calendarName)
throws CalendarNotSavedException {
File outputFile = new File(CALENDAR_HOME + calendarName + ".ics");
try {
fileWriter = new FileWriter(outputFile);
} catch (IOException e) {
throw new CalendarNotSavedException(e.getMessage(), e.getCause());
}
}
private static String changeCalendarName(String contents, String destinationName) {
Pattern calendarNamePattern = Pattern.compile("(.*?CALNAME.*?:)(.*?)\n");
Matcher calendarNameMatcher = calendarNamePattern.matcher(contents);
return calendarNameMatcher.replaceAll("$1" + destinationName + "\n");
}
private static void writeCalendarToFile(String contents) throws CalendarNotSavedException {
try {
fileWriter.write(contents);
fileWriter.close();
} catch (IOException e) {
throw new CalendarNotSavedException(e.getMessage(), e.getCause());
}
}
}
Here we have used a CalendarNotSavedException that is
exactly the same as a CalendarNotFoundException with the
obvious name changes.
Putting It All Back
All you need is a entry point to the program. This Main
just contains a main() that reads the example.ics calendar
from disk, changes it, and stores it as ipod.ics.
package ical;
public class Main {
public static void main(String[] args) {
try {
String contents = ICalendarToString.getCalendarAsString("example");
contents = ICalendarTodoConverter.convert(contents);
ICalendarFromString.saveStringAsCalendarFile(contents, "ipod");
} catch (CalendarNotFoundException e) {
System.out.println("Could not find Calendar example.ics: " + e.getMessage());
} catch (CalendarNotSavedException e) {
System.out.println("Could not save transformed calendar: " + e.getMessage());
}
}
}
The resulting file ipod.ics looks like this:
It loads beautifully into iCal and synchs perfectly with my iPod. Now I
can view my todos. There are many ways to extend this application. The
main point is that with ICalendarToString and
ICalendarFromString, you have the framework to convert a
calendar into a form in which you can transform it any way you want. I
should know better than to make promises about future articles, but
another technique is to build a calendar object model and be able to
manipulate events and todos without thinking at all about their
persistence.
Daniel H. Steinberg is the editor for the new series of Mac Developer titles for the Pragmatic Programmers. He writes feature articles for Apple's ADC web site and is a regular contributor to Mac Devcenter. He has presented at Apple's Worldwide Developer Conference, MacWorld, MacHack and other Mac developer conferences.
Read more Java Programming on the Mac columns.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 12 of 12.
-
ical recurrence rule implementation in java
2006-10-19 12:28:54 mikesamuel [Reply | View]
If anyone is interested in a library for processing ical recurrence rules: http://code.google.com/p/google-rfc-2445/
-
use templates for output generation
2004-05-23 18:49:42 ragsvasan [Reply | View]
This is indeed a very good article, what i comment here is just a suggestion. Anytime you want to generate a data format (or for that matter any output) try to use the "templates" instead of hard coding the format within the code. Fot this particular case you can use
Velocity . Or if this is heavy weight for your use, (for example if the application is real simple like this ical coversion) you
can try this a rudimentary templating engine .
-
iCal is scriptable!
2003-05-26 01:39:30 JürgenSchweizer [Reply | View]
Hi Daniel,
you can also use Applescript to read and modify single events in iCal files. I haven't aleady checked how flexible this method is. But for simple tasks there should be no need to worry about the iCalendar file format.
What I have learned from working with iCal files is to trust Apple more
1) on using open standards and
2) on supporting its own technologies (i.e. Applescript)
Cheers, Jürgen
-
only the name of the calendar changes
2003-05-22 08:16:35 anonymous2 [Reply | View]
The regex seems not to be changing anything. TODOs remain TODOs. Only the name of the calendar is getting changed. Am I missing something? -
only the name of the calendar changes
2003-05-22 08:24:56 Daniel H. Steinberg |
[Reply | View]
I can't tell whether your question refers to the example in the article or something happening when you try this at home (in which case, I'll need more information).
If you are talking about the example in the article, note that the two items that begin with "BEGIN:VTODO" are transformed to items that begin with "BEGIN:VEVENT". What may be confusing is that the word "TODO" has been inserted into the summary so that on your iPod these stand out as todos. If this isn't what you are asking about, please ask again.
-
buglet. Java 1.3.x? Awk.
2003-05-22 02:32:41 leeharveyosmond [Reply | View]
[1] "This code is presented as an example. Do not use it on data for which you don't have a copy. It hasn't been widely tested."
Yes. In my experience you shouldn't rely on the order of any of the items in a BEGIN:... END:... container. So the regexen could so easily fail.
[2] Some of us using Java for useful work on MacOSX are doing it with WebObjects -- which isn't certified for 1.4.x . And java.util.Pattern etc were introduced in 1.4 . There are alternative regex Java classes available though.
[3] The cautions against perl are in my opinion well-advised. Of course, one could instead write a 'sh' script to invoke 'awk' instead of 'perl'. Remember 'awk'? A regex-enabled scripting language, learnable from the single man page, and very comprehensible to someone familiar with C or Java, with scripts potentially way more readable than those for perl. If there's a down side, it's the lack of modern extended regular expressions. But I'm routinely turning all sorts of random textual data culled from webpages into iCal files, using 'awk'.
But for all that -- cool article. It's very difficult to produce short example programs that both illustrate something useful and do real work.
-
iCal uses IETF iCalendar 2.0 format
2003-05-21 13:54:38 anonymous2 [Reply | View]
Apple iCal uses IETF iCalendar 2.0 format for encoding its events. This is a standard for cross platform scheduling [RFC 2445, RFC 2446, RFC 2447. We can all thank Apple for choosing a standard's based approach to its newest applications. Rather than having a proprietary file format with limited import/export options, Apple chooses the interchange format itself as the iCal storage format.
[Sorry about the previous empty post, I hit ^M instead of ^I, by accident.]
Brett Johnson -
iCal uses IETF iCalendar 2.0 format
2003-05-21 13:57:48 Daniel H. Steinberg |
[Reply | View]
Thanks Brett,
What I find really interesting is that on all three of the RFCs you posted, Microsoft was involved in crafting the standard.
I agree that Apple has made a great choice in selecting iCal
D
-
Not necessary on new iPods?
2003-05-21 13:42:51 anonymous2 [Reply | View]
My new 30GB iPod seems to be able to sync to-do items with iCal perfectly. Though since I use Palm Desktop (which exports vCal items for date book entries but not to-dos), it's not much use; I'm in the process of writing an AppleScript to do that. -
Not necessary on new iPods?
2003-05-21 13:53:59 Daniel H. Steinberg |
[Reply | View]
Cool.
On the other hand you can use the techniques in this article to read from and write to iCal calendars and perform other tasks in between. For example, after I subscribe to a conference calendar I want to edit the schedule to remove those sessions I'm not interested in. You can make those calendars editable easily. Some conferences are in a different time zone so the sessions seem to be at very unusual hours. You could easily change the time zone to local, adjust your schedule and then (if you want) change the time zone back when you're on the road.
Any fun hacks? Post them in the talkback.
Thanks,
Daniel





