The requirement my customer has: create a nice web application that will allow our company to manage our contacts and stores them in a database. While you’re at it, sync those contacts with Exchange in such a way that only the web app can create, modify and delete contacts in Exchange but all Outlook users can use the contacts to send mail to.
The solution: create an Oracle ADF web application with JDeveloper and JHeadstart and use Jakarta Slide to sync the database with Exchange via Webdav.
I guess there are enough JDeveloper/JHeadstart tutorials roaming around the internet. But I found it quite hard to find a good Slide tutorial. Well, this isn’t exactly a tutorial, but it should get you on your way anyway. In testing my code I used both NetBeans (5.0 beta 2) and JDeveloper (10.1.2.1.0 build 1913). This brief article will tell you how to create a Contacts folder in Exchange and populate it with a Contact. It will also give you enough info to figure out the rest yourself.
Please note I did my tests with Slide 2.1 on Exchange 2003 SP2. Other versions of Slide or Exchange may or may not work with this code.
The Jakarta Slide project comes with two subprojects. There is a server version and there is a client version. The server version is needed when you want to setup your own Webdav server. It can be used to store all files and folders being uploaded to the server via Webdav to a database. In order to connect to either that Webdav server or to Exchange, the Slide client is needed. So, download the client binary version (or the source version if you’d like to compile it yourself) and unpack the zip or tgz file. Next, start your favourite IDE and make the Slide jars available to it through a custom library definition.
The central Slide class to connect to an Exchange store is called “WebdavResource”. This class contains methods for all Webdav commands. All these WebdavResource commands generate the correct XML messages that are sent to the Exchange store to do the tasks you’d like to do. The Webdav commands you’ll need to know about in order to connect to and work with Exchange can be found in the MicroSoft WebDav Protocol Reference. All you need to do is create an HttpURL with the correct username and password to login to the Webdav store at the URL that you also need to provide and then create a WebdavResource from that HttpURL:
HttpURL url = null;
WebdavResource resource = null;
try {
url = new HttpURL(USERNAME, PASSWORD, DAV_URL);
resource = new WebdavResource(url);
resource.close();
} catch (URIException ex) {
//ex.printStackTrace();
} catch (IOException ex) {
//ex.printStackTrace();
}
DAV_URL represents the URL to the Webdav store and could, for instance, be http://myexchangeserver/Public
Webdav basically works with two kinds of objects. These are called collections (folders) and messages (files). Both collections and messages exist in different types. A collection can be of type MailItems (IPF.Note), ContactItems (IPF.Contact), AppointmentItems (IPF.Appointment), NoteItems (IPF.StickyNote), TaskItems (IPF.Task) or JournalItems (IPF.Journal). The Webdav internal type that they are known by are mentioned in the brackets behind every type.
Webdav recognises the type you’d like to set by the “outlookfolderclass” tag in the “http://schemas.microsoft.com/exchange/” XML namespace. See for a C# example on how to create an AppointmentItems collection this Microsoft KnowledgeBase article. Since I have been dealing with creating ContactItems collections, I’ll be dealing with that here too. In order to create a collection, forst the MKCOL command needs to be executed on the Webdav store. To set the correct type of collection, the PROPPATCH command needs to be executed. Using Slide this goes as follows:
HttpURL url = null;
WebdavResource resource = null;
try {
url = new HttpURL(USERNAME, PASSWORD,DAV_URL);
resource = new WebdavResource(url);
resource.mkcolMethod(DAV_URL + CONTACTS_DIRECTORY);
Hashtable contactProps = new Hashtable();
contactProps.put(new PropertyName(EXCHANGE_XML_NAMESPACE,”outlookfolderclass”), “IPF.Contact”);
if (resource.proppatchMethod(DAV_URL + CONTACTS_DIRECTORY, contactProps, true))
{
System.out.println(“Status code returned: ” + resource.getStatusMessage());
} else
{
System.out.println(“Request failed:”);
System.out.println(“Status code returned: ” + resource.getStatusMessage());
}
resource.close();
} catch (URIException ex) {
//ex.printStackTrace();
} catch (IOException ex) {
//ex.printStackTrace();
}
Here, CONTACTS_DIRECTORY is a String containing the name of the collection to create and EXCHANGE_XML_NAMESPACE is a String containing the correct XML namespace. As stated before, this is “http://schemas.microsoft.com/exchange/”.
Please note: the PROPPATCH method will create an item on which the properties are set if it doesn’t exist. But the PROPPATCH command will always create a message and never a collection, even if the property to set is the “outlookfolderclass” property. Therefore, creating a collection always involves first creating it and then setting its type.
So, now that our ContactItems collection exists we can put a contact in it. Since Webdav only knows of collections and messages, a Contact actually is a message. But the “outlookmessageclass” now is “IPM.Contact” (in contrast to IPF.Contact for a ContactItems collection). I guess the M in IPM indicates we’re dealing with a message as opposed to the F in IPF when dealing with a collection which actually is a folder.
Anyway, as can be read in this MicroSoft KnowledgeBase article only one other property is required in order to create a Contact, which is the “contentclass” property in the “DAV:” namespace (mind the trailing “:”!!!) which needs to be set to “urn:content-classes:person”. The same KB article shows which properties are available for a Webdav Contact and this code sets a few of them and then calls the PROPPATCH command to store the contact in Webdav:
HttpURL url = null;
WebdavResource resource = null;
try {
url = new HttpURL(USERNAME, PASSWORD,DAV_URL);
resource = new WebdavResource(url);
Hashtable contactProps = new Hashtable();
contactProps.put(new PropertyName(DAV_XML_NAMESPACE,”contentclass”), “urn:content-classes:person”);
contactProps.put(new PropertyName(EXCHANGE_XML_NAMESPAC
E,”outlookmessageclass&
quot;), “IPM.Contact”);
contactProps.put(new PropertyName(URN_SCHEMAS_CONTACTS_XML_NAMESPACE,”givenName”), firstname);
contactProps.put(new PropertyName(URN_SCHEMAS_CONTACTS_XML_NAMESPACE,”middlename”), middlename);
contactProps.put(new PropertyName(URN_SCHEMAS_CONTACTS_XML_NAMESPACE,”sn”), lastname);
contactProps.put(new PropertyName(URN_SCHEMAS_CONTACTS_XML_NAMESPACE,”cn”), firstname + ” ” + middlename + ” ” + lastname);
contactProps.put(new PropertyName(URN_SCHEMAS_CONTACTS_XML_NAMESPACE,”fileas”), firstname + ” ” + middlename + ” ” + lastname);
if (resource.proppatchMethod(DAV_URL + path + CONTACTS_DIRECTORY + lastname + CONTACTS_EXTENSION, contactProps, true))
{
System.out.println(“Status code returned: ” + resource.getStatusMessage());
} else
{
System.out.println(“Request failed:”);
System.out.println(“Status code returned: ” + resource.getStatusMessage());
}
resource.close();
} catch (URIException ex) {
//ex.printStackTrace();
} catch (IOException ex) {
//ex.printStackTrace();
}
Fill the variables “firstname”, “middlename” and “lastname” with the properties you’d like to store and make sure de Strings DAV_XML_NAMESPACE, EXCHANGE_XML_NAMESPACE and URN_SCHEMAS_CONTACTS_XML_NAMESPACE contain the values “DAV:”, “http://schemas.microsoft.com/exchange/” and “urn:schemas:contacts:” and give it a go.
The contact created this way is of little use to ay real life Outlook users. It doesn’t contain an email addres, nor a phone number or anything of the kind. But it proves Slide works like a charm.
Troy,
Do you mean you first create a new message and then try to change it to a contact? I’m not sure if this is the correct way of doing it. I would suggest you add statements to transform the message into a contact immediately when you create the message and then give it another try.
Another issue may be that the XML namespaces and tags have different values than the ones in my blog. The ones in my blog refer to Exchange 2003 SP2 so if you are using another version, please refer to the documentation of that version to get the correct XML namespaces and tags.
HTH, Wouter
I am using PHP to execute the WebDAV commands.
I am able to create a new item in a contacts folder, but so far I’m unable
to change the item from a message to an actual contact (IPF.Contact). I am including:
urn:content-classes:person
IPM.Contact
Any ideas?
Well about security, because the store is allready secured by the rights that are set on the folders containing the objects your are creating, the security settings are automaticly duplicated on the new objects because they are childs of the folder that holds them.
In in this case u only need to set the security right on the parrent, and make sure the user that is used to create these objects have owner rights on this folder…
so no need to know how microsoft uses SIDS and UIDS to determin the security… let exchange worry about that 😀
…without needing to concern about rights policies and other complex microsoft technologies…AND security.
😉
The problem with the AD store is that it doesnt hold the data for the Exchange Public folders. This data resides in a seperate store managed by the exchange server itsself. When u use LDAP u are actually using work arround to do this. Using webDAV u are directly talking to the Public store of exchange without needing to concern about rights policies and other complex microsoft technologies…
I suppose you can also use LDAP to communicate with the Exchange server.
Koel!