MS Exchange Calendar Integration
We have a channel in development that pulls down calendar information from Exchange via WebDav. To do this, we created a user Id that has administrator permissions to all mailboxes (we have not found a way to restrict this to calendar information only). Using this ID, we connect to the Exchange servers via the Slide WebDav client and execute a select against the calendar for the current user. The only problem I have run into is timeouts on the Exchange server. From what I can tell, the query is sent without any problem, the connection blocks until the query completes (which can take several seconds), which causes the channel to timeout. We're hoping that we'll have better reliability from WebDav when we move to Exchange 2003, until then, getting the calendar information successfully is hit or miss (I'd say about 60-75% of the time it succeeds).
Microsoft has some articles that explain how to make the query via
WebDav:
- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_exch2k_searching_calendar_folders_webdav.asp
- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_exch2k_searching_folders_http.asp
Hope this gives you some ideas. Once I get a chance to clean the code up a bit, I'd be happy to share it.
Neil C Fritz
Technology Support Analyst
Arizona State University
ncf@asu.edu
(480)965-9077
email-q myasu-q
web-q webapp-q
One way to work with OWA is using Simulated Single Signon to login using Form Based Authentication. Note that Form Based Authentication is greyed out on a cluster server because FBA isn't available on a cluster.
Exchange 2003 Integration with uPortal
At Liverpool we have just gone through the process of migrating to Exchange, in the process we have added functionality into our portal so as to allow the extraction of Calendar data over webdav.
One feature to note about Exchange2003 implementations is that if you Sign a user into OWA using a formfilling method, you may find that when the user hits the Log Off button they are then unable to continue working with your portal. This happens in IE6.2 and above because the log off process calls a function called ClearAuthenticationCache which removes ALL of the session cookies in the browser. This does not effect non IE browsers. To fix this you need to comment out the line
document.execCommand("ClearAuthenticationCache", "false");
in the logon.asp, logoff.asp and frm_LogOff.js files. To be safe we also changed the default logoff html page on our ISA servers to be that for non IE browsers.
The main class that extracts data from our exchange server is called ConnectToServer, the file attached is for a cluster of exchange servers using FBA and an ISA front end, if you are not using an ISA front end just comment out the following two lines in the authenticate method.
 fbaAuth.addParameter( "destination", "Z2F" ); fbaAuth.addParameter( "flags" , "0" );
You will also need to change the value of _strFBAPath from
 _strFBAPath = "CookieAuth.dll?Logon"
 to
 _strFBAPath = "/exchweb/bin/auth/owaauth.dll
You can easily check if this is correct by looking at the url when you access your sites implementation of OWA.
Here is an example of using the code
 /* * GetDiary.java * Version : 1.0 * File created on 15 Aug 2006 at 08:44:46 * * Copyright (c) The University of Liverpool. * All rights reserved. * * The code contained in this file has NOT been thoroughly tested under * all conditions. The University of Liverpool cannot guarantee or imply * reliability, serviceability, or function of this software. * * This code is provided "AS IS" without any warranties of any kind. * The implied warranties of non-infringement, merchantability and * fitness for a particular purpose are expressly disclaimed. * */ package uk.ac.liv.csd.groupware.portal.exchange; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import org.apache.commons.httpclient.HttpMethod; import uk.ac.liv.csd.groupware.calendar.Appointment; import uk.ac.liv.csd.groupware.exchange.sql.GetCalendarEntries; import uk.ac.liv.csd.groupware.portal.exchange.webdav.ConnectToServer; import uk.ac.liv.csd.groupware.portal.exchange.webdav.SearchMethod; /** * * @author Duncan Appelbe, Computing Services Department, * The University of Liverpool. * * This class will grab all of the Calendar data that we need from our exchange * server. * */ public class GetDiary { private static SimpleDateFormat sdf1 = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'" ); private static SimpleDateFormat sdf2 = new SimpleDateFormat( "yyyy-MM-dd'T00:00:00Z'" ); private ArrayList<Appointment> appList = new ArrayList<Appointment>(); public GetDiary( String user, int numdays ) { ConnectToServer cts = new ConnectToServer( username, password, domain, host (e.g. owa.myinst.ac.uk), "exchange"); if ( cts.isError() ) { System.out.println( cts.getErrorMsg() ); } else { cts.connect( user ); if ( cts.isError() ) { System.out.println( cts.getErrorMsg() ); } else { SearchMethod sm = new SearchMethod( cts.getCalendarUrl() ); GetCalendarEntries gce = new GetCalendarEntries(); Date startDate = new Date(); Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, numdays); Date endDate = cal.getTime(); gce.setDateRange(sdf1.format( startDate ), sdf2.format( endDate )); sm.setRequestBody( gce.toString() ); HttpMethod mymeth = cts.executeGetMethod( sm ); // System.out.println( mymeth.getResponseBodyAsString() ); try { String s1 = readFully(new InputStreamReader( mymeth.getResponseBodyAsStream() ) ); if ( s1 != null && s1.length() > 1 ) { int nLen = s1.length(); String resStr = "<a:response>"; String resStr2 = "</a:response>"; String propStr = "<a:prop>"; String startStr = "<dtstart b:dt=\"dateTime.tz\">"; String endStr = "<dtend b:dt=\"dateTime.tz\">"; String summStr = "<summary>"; String descStr = "<textdescription>"; String locStr = "<location>"; String allStr = "<alldayevent b:dt=\"boolean\">"; String meeting_start = ""; String meeting_end = ""; String meeting_summ = ""; String meeting_loc = ""; String meeting_desc = ""; String meeting_allDay = ""; int p1 = s1.indexOf( resStr ); int p2 = 0; int p3 = 0; int p4 = 0; int responseMax = 0;  //-- Probably should have used an xml parser here, but had problems due to //-- incompatabilities elsewhere while ( p1 > 0 && p1 < nLen ) { //-- Loop over all of the xml starting at <a:response> //-- Find the first </a:response> responseMax = s1.indexOf( resStr2, p1 + resStr2.length() ); if ( responseMax > 0 && responseMax < nLen ) { meeting_start = ""; meeting_end = ""; meeting_summ = ""; meeting_loc = ""; meeting_desc = ""; meeting_allDay = ""; //-- We want to make sure that we get all of the //-- data for this response //-- Look for <dtstart> p2 = s1.indexOf( startStr, p1 ); if ( p2 > 0 && p2 < responseMax ) { p3 = s1.indexOf( "<", p2 + startStr.length() ); if ( p3 > 0 && p3 < responseMax ) { meeting_start = s1.substring(p2 + startStr.length(), p3); } } p2 = s1.indexOf( endStr, p1 ); if ( p2 > 0 && p2 < responseMax ) { p3 = s1.indexOf( "<", p2 + endStr.length() ); if ( p3 > 0 && p3 < responseMax ) { meeting_end = s1.substring(p2 + endStr.length(), p3); } } p2 = s1.indexOf( summStr, p1 ); if ( p2 > 0 && p2 < responseMax ) { p3 = s1.indexOf( "<", p2 + summStr.length() ); if ( p3 > 0 && p3 < responseMax ) { meeting_summ = s1.substring(p2 + summStr.length(), p3); } } p2 = s1.indexOf( descStr, p1 ); if ( p2 > 0 && p2 < responseMax ) { p3 = s1.indexOf( "<", p2 + descStr.length() ); if ( p3 > 0 && p3 < responseMax ) { meeting_desc = s1.substring(p2 + descStr.length(), p3); } } p2 = s1.indexOf( locStr, p1 ); if ( p2 > 0 && p2 < responseMax ) { p3 = s1.indexOf( "<", p2 + locStr.length() ); if ( p3 > 0 && p3 < responseMax ) { meeting_loc = s1.substring(p2 + locStr.length(), p3); } } p2 = s1.indexOf( allStr, p1 ); if ( p2 > 0 && p2 < responseMax ) { p3 = s1.indexOf( "<", p2 + allStr.length() ); if ( p3 > 0 && p3 < responseMax ) { meeting_allDay = s1.substring(p2 + allStr.length(), p3); } } Appointment ap = new Appointment(); ap.setLocation( new StringBuffer( meeting_loc ) ); ap.setBody ( new StringBuffer( meeting_desc ) ); ap.setSummary ( new StringBuffer( meeting_summ ) ); if ( meeting_allDay.equalsIgnoreCase( "1" ) ) { ap.setIsAllDay( true ); } else { ap.setIsAllDay( false ); } ap.setStart( meeting_start ); ap.setEnd ( meeting_end ); appList.add( ap ); p1 = responseMax; } else { p1 = nLen * 2; } } } } catch (IOException e) { e.printStackTrace(); } finally { mymeth.releaseConnection(); cts.disconnect(); } } } } public ArrayList<Appointment> getAppList() { return this.appList; } //-- Grabbed from http://mail-archives.apache.org/mod_mbox/jakarta-httpclient-user/200411.mbox/%3C41A8C0B4.8060301@earthlink.net%3E //-- use with: readFully( new InputStreamReader(get.getResponseBodyAsStream(), get.getResponseCharSet())); private String readFully( Reader input ) { try { BufferedReader bufferedReader = input instanceof BufferedReader ? (BufferedReader) input : new BufferedReader(input); StringBuffer result = new StringBuffer(); char[] buffer = new char[4 * 1024]; int charsRead; while ((charsRead = bufferedReader.read(buffer)) != -1) { result.append(buffer, 0, charsRead); } return result.toString(); } catch ( IOException ioe ) { } return ""; } }
 I have attached the class files that we use as they should give people a good idea of what can be done, and maybe provide some ideas.