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.

