= Exchange Web Services =
Exchange Web Services is a moderately incorrect implementation of a SOAP service. It appears to be possible to interact with Exchange using the SOAP framework in Java but there are some difficulties.
This set of pages will describe the process of implementing a synchronization engine for bedework which I hope will synchronize calendars between the two systems.
== Push Subscriptions ==
This is the mechanism we will use. Briefly, send a message to Exchange subscribing to a push feed for a given resource and Exchange will send back messages describing changes to the resource.
We have to consider a number of cases when (re)subscribing.
1. First time subscription for this user to the resource
1. Our service is restarting
1. The other end died and we are trying to restart the subscriptions.
When subscribing, a status frequency in minutes is supplied. This will allow us to detect that Exchange has stopped talking to us. If we don't get any notification within the status frequency (plus some extra for delays in the system), then it appears the other end is down. A good guide is that a delay of twice the status frequency indicates trouble. Note that notifications of changes are sent (almost) immediately. The status frequency is essentially a minimum poll time.
When restarting a subscription we make use of the watermark last received. Supplying this on the resubscribe should ensure we miss no notifications. Somewhere in the MS documentation I believe it suggests that old watermarks can cause efficiency issues so treating those as a new subscription would make sense. However, really old watermarks means our service wasn't running for some time. There is a suggestion that after 7 days watermarks expire in some way.
Exchange has a complex process for retrying notifications. It will double the status frequency and try again on failure. It does this a small number of times then gives up. It's not clear (yet) what happens if the bedework service goes down then restarts while Exchange is still pinging us. The best approach is probably to persist all subscription states and reread them on restart. We don't need to special case a service restart, it just looks like a long delay since Exchange last contacted us.
== Synch Engine ==
This requires a web server which acts as the target for the notifications from exchange. We are building this whole engine as a single ear file to deploy on jboss. It will include the Exchange Synch service and a web server.
== 1. Build a jar of generated classes from the WSDL ==
Download the Exchange Web Services SDK and extract the folder EWSReference containing
{{{
Services.wsdl
messages.xsd
types.xsd
}}}
(or obtain them from your local exchange)
Place EWSReference at the same level as the metro bin directory.
Edit Services.wsdl and before the final closing tag add this
{{{
}}}
In types.xsd, near the beginning, replace
{{{
}}}
with
{{{
}}}
{{{
cd EWSReference
mkdir gensrc
mkdir classes
../bin/wsimport.sh -d classes -s gensrc Services.wsdl
}}}
You should end up with a lot of java in gensrc and the compiled classes in classes.
Within gensrc are two packages:
{{{
com.microsoft.schemas.exchange.services._2006.messages
and
com.microsoft.schemas.exchange.services._2006.types
}}}
Build a jar file from the results
{{{
$JAVA_HOME/bin/jar cf "exchangews-2010.jar" -C classes com
}}}
Create an exchange directory in jboss ROOT.war directory and copy in
{{{
types.xsd
messages.xsd
Services.wsdl
}}}
These are needed for the service later on
Tried the following change - then removed it
{{{
}}}
== 2. Subscriptions ==
From types.xsd we have these schema segments:
{{{
}}}
Folder ids appears to be a list of names - in our case a single calendar.
!EventTypes is a list with entries described by
{{{
}}}
We want all except !NewMailEvent.
== 3. Prepare jboss ==
This should be done anyway - even if not running this service - unless you're trying to run under java 5.
Remove all the jbossws-native*.jar files from the common/lib and lib/endorsed. They should not be there for java 6.
To handle an issue with EWS not handling content type correctly add a number of files to lib/endorsed to upgrade JAXB etc to 2.2.1. lib/endorsed should now contain:
{{{
activation.jar
gmbal-api-only-2.2.1.jar
jaxb-api-20100511-2.2.1.jar
jaxb-impl-2.2.1.jar
jaxws-api-2.2.1.jar
jaxws-rt-2.2.1.jar
jaxws-tools-2.2.1.jar
policy-2.2.1.jar
resolver.jar
serializer.jar
stax-api.jar
stax-ex-2.2.1.jar
streambuffer-2.2.1.jar
xalan.jar
xercesImpl.jar
}}}
The endorsed directory is available zipped up at http://bedework.org/downloads/lib/jboss5-1-0-lib-endorsed.zip
== 4. Certificates ==
If the exchange server has self-signed certs we need to create a keystore. Get the certificate in a file - e.g. exchange.cert
{{{
$JAVA_HOME/bin/keytool -importcert -file exchange.cert -keystore /jboss-5.1.0.GA/server/default/data/bedework/exsynchcerts
Enter keystore password:
...
Re-enter new password:
...
Trust this certificate? [no]: yes
Certificate was added to keystore
}}}
== 5. Creating a subscription. ==
We're creating a push subscription based service. We start with a list of current subscriptions and subscribe to Exchange with each one. Each subscription will cause Exchange to call back to an http end-point created as part of our service. Each call-back tells us if anything changed.
The stub creation phase generated an !ObjectFactory class and we call its methods to obtain Jaxb classes representing elements of the request
{{{
ObjectFactory of = new ObjectFactory();
...
}}}
== 6. Deal with Exchange not handling content-type correctly ==
Exchange complains with
{{{
'text/xml;charset="utf-8"' was not the expected type 'text/xml; charset=utf-8'
}}}
clearly not handling the (valid) lack of space and/or quotes.
To get around this installed jaxb-2.2.1 and jaxws-2.2.1 in jboss endorsed. (2.1 is the current version in the runtime.)
== References ==
Gained some information from
* http://www.reidmiller.name/exchange_web_services_with_java_and_metro_exchangeserviceporttype_with_authentication