Monday, March 24, 2008

Download sources for javax libraries

If you are lucky like me, you often find yourself wanting to see the source code for various javax libraries (JavaMail, JSTL, EL, etc). My success in tracking down the complete zips of these sources varied from project to project. Today, I stumbled across this:
http://download.java.net/maven/1/

This looks like a good starting place if you are after javax sources or jars.

Tuesday, March 11, 2008

ical4j, JavaMail, Exchange and Outlook secret sauce

Last summer, I was tasked with sending out Outlook "meeting invites" for events in our product. This meant integrating with iCal4j. iCal4j itself has a truly bizarre API, but it wasn't bad to create a new invite, as there are so many examples out there. What really stumped me for a while was getting the headers right so that Outlook would pop up an "Accept/Decline" dialog for automatically adding the event to their calendar. I should have blogged about this last summer, as I've now forgotten what I finally did to make it work - I believe the real coup was getting the headers right. I remember finding lots of people with similar problems, so I wanted to get this code out there.

This code requires iCal4j and JavaMail 1.4. I believe the JavaMail 1.4-only ByteArrayDataSource is crucial for getting this to work. This code might not even work for you, I just wanted to get it out there as a starting point.

public MimeMessage createMimeMessage(Session _javaMailsession) throws Exception {
MimeMessage mimeMessage = new MimeMessage(_javaMailsession);
mimeMessage.setSubject(getSubject());
mimeMessage.addFrom(getFromInternetAddresses());
mimeMessage.addRecipients(Message.RecipientType.TO, getFromInternetAddresses());
Multipart multipart = new MimeMultipart();
MimeBodyPart iCalAttachment = new MimeBodyPart();
byte[] invite = createICalInvitation(getMeetingID(), getSubject(), getContent(), getMeetingStart(), getMeetingEnd(), getMeetingTimeZone());
iCalAttachment.setDataHandler(new DataHandler(new ByteArrayDataSource(new ByteArrayInputStream(invite), "text/calendar;method=REQUEST;charset=\"UTF-8\"")));
multipart.addBodyPart(iCalAttachment);
mimeMessage.setContent(multipart);
return mimeMessage;
}

private byte[] createICalInvitation(String _meetingID, String _subject, String _content, Date _start, Date _end, TimeZone _tz) throws Exception {
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_OUTLOOK_COMPATIBILITY, true);

VEvent vEvent = new VEvent();
vEvent.getProperties().add(new Uid(_meetingID));
vEvent.getProperties().add(new Summary(_subject));
vEvent.getProperties().add(new Description(_content));
vEvent.getProperties().add(new DtStart(new DateTime(_start)));
vEvent.getProperties().add(new DtEnd(new DateTime(_end)));

net.fortuna.ical4j.model.Calendar cal = new net.fortuna.ical4j.model.Calendar();
cal.getProperties().add(new ProdId("-//iloveoutlook//iCal4j 1.0//EN"));
cal.getProperties().add(net.fortuna.ical4j.model.property.Version.VERSION_2_0);
cal.getProperties().add(CalScale.GREGORIAN);
cal.getProperties().add(net.fortuna.ical4j.model.property.Method.REQUEST);
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
VTimeZone tz = registry.getTimeZone(_tz.getID()).getVTimeZone();
cal.getComponents().add(tz);
cal.getComponents().add(vEvent);

ByteArrayOutputStream bout = new ByteArrayOutputStream();
CalendarOutputter outputter = new CalendarOutputter();
outputter.output(cal, bout);
return bout.toByteArray();
}