<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Software Gorilla &#187; Development</title>
	<atom:link href="http://www.thesoftwaregorilla.com/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.thesoftwaregorilla.com</link>
	<description>The Software Gorilla</description>
	<lastBuildDate>Wed, 20 Oct 2010 19:56:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Exchange Web Services Example &#8211; Part 4 &#8211; Subscriptions and Notifications</title>
		<link>http://www.thesoftwaregorilla.com/2010/07/exchange-web-services-example-part-4-subscriptions-and-notifications/</link>
		<comments>http://www.thesoftwaregorilla.com/2010/07/exchange-web-services-example-part-4-subscriptions-and-notifications/#comments</comments>
		<pubDate>Thu, 08 Jul 2010 06:52:11 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Exchange Web Services]]></category>
		<category><![CDATA[Exchange Web Services Example]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[n-tier Development]]></category>
		<category><![CDATA[OpenClient]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[OpenEdge AppServer]]></category>
		<category><![CDATA[Dynamic OpenClient]]></category>
		<category><![CDATA[EWS]]></category>
		<category><![CDATA[Exchange 2007]]></category>
		<category><![CDATA[Exchange 2010]]></category>
		<category><![CDATA[Exchange EWS]]></category>
		<category><![CDATA[Exchange Impersonation]]></category>
		<category><![CDATA[Exchange Server 2007]]></category>
		<category><![CDATA[Exchange Server 2010]]></category>
		<category><![CDATA[Java 6]]></category>
		<category><![CDATA[Java EE 6]]></category>
		<category><![CDATA[Java OpenClient]]></category>
		<category><![CDATA[Microsoft Exchange 2007]]></category>
		<category><![CDATA[Microsoft Exchange 2010]]></category>
		<category><![CDATA[OpenEdge OpenClient]]></category>
		<category><![CDATA[Progress]]></category>
		<category><![CDATA[Progress AppServer]]></category>
		<category><![CDATA[Progress OpenClient]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=892</guid>
		<description><![CDATA[Now that we have succeeded in creating, updating and deleting calendar items and mastered Exchange Impersonation, it's time to turn our attention to having Exchange notify us about what it is doing. Part 4 of this series is going to provide a detailed code walk-through of some code that leverages the Subscription API. 

The example includes two code examples - one for Java programmers and one for OpenEdge programmers. The OpenEdge version writes updates through the OpenClient via the OpenEdge AppServer to an OpenEdge database.]]></description>
			<content:encoded><![CDATA[<p>Now that we have succeeded in creating, updating and deleting calendar items and mastered Exchange Impersonation, it&#39;s time to turn our attention to having Exchange notify us about what it is doing. Part 4 of this series is going to provide a detailed code walk-through of some code that leverages the Subscription API.&nbsp;</p>
<p>I covered a lot of material about the push subscription mechanism in <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/">an earlier post</a>, and if you haven&#39;t read it, I highly recommend you go back and revisit it as this article builds on that one. It also builds on <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/">part 1</a>, <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/">part 2</a>, and <a href="http://www.thesoftwaregorilla.com/2010/06/exchange-web-services-example-part-3-exchange-impersonation/">part 3</a> of this series, so you should probably have worked through those, too.&nbsp;</p>
<h3>Goals and Background</h3>
<p>By now, you know that the reason that I have embarked on this project is to integrate Microsoft Exchange with a CRM application that is in Progress OpenEdge. The first part of the exercise was to figure out how to create calendar items based on data entered into the CRM system, and how to automate that for a large number of sales people without having to log in to each mailbox.</p>
<p>Now that we know how to do that, the next step is handling the situation where the sales person makes a change to a calendar item from Outlook or a mobile device. The item change needs to make it back to the CRM application, and for that, the Exchange WebServices Push Subscription API is going to be essential.</p>
<p>When a change is made to an Exchange Server calendar item, the Push Subscription API can send a message to an HTTP target of your choice. As long as the HTTP target knows how to parse the SOAP message that is sent by Exchange, it can react to the events that it are sent.</p>
<p>In this example, we are going to concentrate on 3 events that occur against objects in the default calendar folder for a mailbox; the Created-, Modified-, and DeletedEvents.</p>
<h3>The Subscription Process</h3>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" target="_blank"><img align="left" alt="The Subscription process" height="206" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" width="300" /></a>By now, the diagram to the left is all too familiar, but it clarifies the process really well, so I am going to walk through it again.</p>
<p>The first step (1.1) is to initiate a call to the Java EWS WebService to register a subscription. The EWS WebService then makes a call to Exchange (1.2) to tell it to call back to the Java HTTP Servlet.&nbsp;</p>
<p>When something happens to an item for which we have registered a subscription, Exchange will call the HTTP Servlet (2.1) with a notification message.</p>
<p>Now the order of what happens next is something that you will want to change for production code, because it should happen in the order illustrated in the diagram, but I have decided to take the simple road with the attached code and process everything in a synchronous way. What follows is the order in which I am doing the processing in the sample code.</p>
<p>After parsing the message notification message that was received (2.1), the code determines if there are any items that need to be processed. A notification message only contains the ItemID of the object that has changed. It does not contain the item itself. This means that we need to call the Exchange Server back to get the item&#39;s information (2.3).</p>
<p>Once we have the item&#39;s information, we can react to it, and in the example code, this includes calling OpenEdge (2.4) with information about the appointment that has changed.&nbsp;It is really important to note that only notifications that actually affect an item are passed on to OpenEdge. This significantly reduces the processing that OpenEdge has to perform.</p>
<p>Finally, when we are done with the processing, we respond to Exchange with an acknowledgement message (2.2) so that it will continue to send us messages.</p>
<p>If you want more information about the details of this process, refer to my detailed description in the blog posting entitled <em><a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/#settingupsub" target="_blank">Exchange Web Services &ndash; Subscriptions and Notifications</a>.</em></p>
<p>It is important to remember that Exchange will poll the Java HTTP Servlet at regular intervals to check that it still wants to receive notifications. The frequency is user-defined as <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/#statusfrequency" target="_blank">explained in the aforementioned article</a>. These StatusEvents do not require any processing, other than an acknowledgement of receipt back to the Exchange Server (2.2). So the Java HTTP Servlet also performs the function of keeping the subscription alive.</p>
<p>I have also provided a mechanism for unsubscribing from the notifications. This mechanism works by keeping track of all the subscriptions that are currently active, and then returning an <em>Unsubscribe</em> response (2.2) to the Exchange Server after a request to unsubscribe has been received in 1.1.</p>
<h3>The Code</h3>
<p>Now that you understand how the process works, let&#39;s take a look at <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/tsgewsexample_4.zip">the code</a>.</p>
<p>First, I need to point out that the <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/tsgewsexample_4.zip">download</a> contains 2 zip files. If you are a Java developer with no interest in OpenEdge, you should use the file called <em>EWSAPI_JavaOnly.zip</em>. The difference between this code and the <em>EWSAPI_OpenEdge.zip</em> file is that the latter actually makes AppServer calls to an OpenEdge AppServer, whereas the former simply displays the results of processing the messages in the log file.</p>
<p>The <em>EWSAPI_OpenEdge.zip</em> files can also be installed per the regular instructions, but there are a few additional steps that you have to perform. These are documented in a file called <em>OpenEdge_Setup.pdf </em>that is contained in the downloaded zip file. Essentially, you will need to&nbsp;create a database using a definition that is provided,&nbsp;set up an OpenEdge AppServer that has access to the database, and deploy some OpenEdge ABL code to the AppServer so that it can receive the calls. You will also need to copy your OpenClient runtime libraries to the Glassfish installation so that it can make the OpenClient calls. As I said, all of this is covered in <em>OpenEdge_Setup.pdf</em>.</p>
<p>Like the previous articles, you can download the code and <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/#codesetup" target="_blank">set up your workspace as described in part 2</a>.</p>
<h4>What&#39;s New?</h4>
<p>The <em>EWSAPI</em> project that is included in both the <em>EWSAPI_JavaOnly.zip</em> and the <em>EWSAPI_OpenEdge.zip</em> files contains the following code changes in the <em>com.tsg.ews</em> root package (filenames in italics are new files):</p>
<ul>
<li><em><strong>EWSListener.java</strong></em> &#8211; This code, which is new, contains the Java code for the Java HTTP Servlet that listens for notifications from Exchange.</li>
<li><strong>EWSImpersonationCalendar.java</strong> &#8211; This code, which is the code for the Impersonation-based calendar WebService, has been modified to support two new operations &#8211; Subscribe and Unsubscribe.</li>
</ul>
<p>In addition, the&nbsp;<em>com.tsg.ews.calendar</em> package contains the following code changes:</p>
<ul>
<li><strong>Appointment.java</strong> &#8211; A minor modification has been made to the <em>retrieve</em> method to support retrieval with a <em>ChangeKey</em>. I also changed the code to use namespaces.</li>
</ul>
<p>Finally, the <em>com.tsg.ews.service</em> package contains a lot of code changes (again, filenames in italics are new files):</p>
<ul>
<li><strong>EWSResponse.java</strong> &#8211; This code, which deserializes responses from the Exchange Web Service, has been altered to support namespaces in the deserialization of the XML. It also now supports a <em>SubscriptionID</em> and a <em>Watermark </em>property.</li>
<li><strong>ExchangeService.java</strong> &#8211; There are a couple of minor changes to expose some methods outside of the class.</li>
</ul>
<p>An enumeration and a new class have been added to enhance some of the XML parsing that I have been doing:&nbsp;</p>
<ul>
<li><strong><em>EWSNamespaces.java</em></strong> &#8211; This is an enumeration of the namespaces used in Exchange WebServices messages.</li>
<li><strong><em>NamespaceContextImpl.java</em></strong> &#8211; This class extends NamespaceContext and is used in namespace resolution of the XPath queries. It makes use of EWSNamespaces to perform this resolution.&nbsp;</li>
</ul>
<p>The following three classes have been added to support the registration and long-term monitoring of subscriptions:</p>
<ul>
<li><em><strong>SubscriptionManager.java</strong></em> &#8211; This class manages all subscriptions.&nbsp;</li>
<li><em><strong>SubcriptionList.java</strong></em> &#8211; This class is a collection of subscriptions and is used for serialization and deserialization of all subscriptions.</li>
<li><em><strong>Subscription.java</strong></em> &#8211; This class is used to register a subscription and serialize it and it keeps track of the watermarks for the subscription.</li>
</ul>
<p>The remaining new classes and enumerations have been added to parse notifications from Exchange Server:</p>
<ul>
<li><em><strong>Notification.java</strong></em> &#8211; This class is the parent class for each notification. It can be instantiated from an Exchange Web Service SOAP Notification message and it will deserialize the message into its internal objects. The notification, itself, has properties for the <em>SubscriptionId</em>, <em>PreviousWatermark</em>, and a collection of <em>SubscriptionEvents</em>. It also has a flag that indicates whether it is just a status event.</li>
<li><em><strong>SubscriptionEvent.java</strong></em> &#8211; A <em>Notification</em> may include one or more <em>SubscriptionEvent</em> objects. These events will be one of the <em>EventType</em>s (see the next bullet point) for which the subscription has been registered (<em>CreatedEvent</em>, <em>ModifiedEvent</em>, <em>DeletedEvent</em>, or <em>StatusEvent</em>). After the event has been parsed, it contains properties for <em>EventType</em>, <em>SubscriptionID</em>, <em>Watermark</em> (each event will have a different watermark), <em>TimeStamp</em>, <em>AffectedItem</em> (the item that actually changed), and <em>ParentFolder</em> (the folder that contains the item that changed). If the <em>AffectedItem</em> is a calendar item, the calendar item will be retrieved (if possible) and stored in the <em>Appointment</em> property.</li>
<li><em><strong>EventType.java</strong></em> &#8211; This is an enumeration of the supported event types.</li>
<li><em><strong>IDHolder.java</strong></em> &#8211; When we receive an event, it comes with two elements; the first is either a <em>FolderId</em> or an <em>ItemId</em>, and the second is a <em>ParentFolderId</em>. These nodes contain two attributes; an <em>ID</em> and a <em>ChangeKey</em>. The <em>IDHolder</em> has three properties, two of which map to the <em>ID</em> and the <em>ChangeKey</em>. The third is an <em>IDType</em>, described in the next bullet.</li>
<li><em><strong>IDType.java</strong></em> &#8211; This enumeration contains items for each possible type of <em>ID</em> that can be contained in the <em>IDHolder</em>.</li>
</ul>
<h4>The OpenEdge pieces</h4>
<p>If you are using the OpenEdge version of the code (<em>EWSAPI_OpenEdge.zip</em>), the EWSAPI project contains the following additional packages:</p>
<ul>
<li><em>com.tsg.common.collections</em></li>
<li><em>com.tsg.common.interfaces</em></li>
<li><em>com.tsg.dynamicopenclient</em></li>
<li><em>com.tsg.dynamicopenclient.data</em></li>
<li><em>com.tsg.dynamicopenclient.valueholders</em></li>
<li><em>com.tsg.exceptions</em></li>
<li><em>com.tsg.ews.openedge</em></li>
</ul>
<p>All but the last package are modified copies of <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/11/DynamicOpenClient.zip">the code that accompanies</a> the <a href="http://www.thesoftwaregorilla.com/2009/11/openedge-dynamic-openclient-java-example/" target="_blank"><em>OpenEdge Dynamic OpenClient Java Example</em></a> article that I wrote back in November 2009.</p>
<p>The last package contains one class, <em>OpenEdgeCallFactory</em>, that is responsible for making the OpenClient call to the AppServer.</p>
<p>The EWSAPI project for OpenEdge also contains an additional folder, <em>oepieces</em>, that contains the ABL procedure (<em>ewscall.p</em>) that it expects to call and a DF file (<em>test.df</em>) that contains the database definitions for the database table that <em>ewscall.p</em> expects to write to.</p>
<p>I&#39;m not planning to cover the OpenEdge part of this in any detail later in the article. All <em>ewscall.p</em> does is accept a set of parameters and write their values directly to a table in an OpenEdge database. The <em>ewscall.p</em> procedure needs to be deployed to an OpenEdge AppServer. The AppServer needs to be running in STATE-FREE mode against a database that contains the <em>ews_update</em> table that is defined in the <em>test.df</em> file.</p>
<h4>Additional Setup</h4>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_UpdateDefinitions1.jpg" target="_blank"><img align="left" alt="Updating the soapUI WebService Definition" height="188" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_UpdateDefinitions1.jpg" width="301" /></a>Once you have set up the code and have it running, you need to update the WebService definition for the CalendarService in soapUI. The screenshot at left should help you do this. Right-click on the EWSImpersonationCalendarPortBinding tree node, and select <em>Update Definition </em>from the context menu.</p>
<p>Two additional nodes will be added &#8211; Subscribe and Unsubscribe. As you will note from the screenshot, I have created two copies of the RegisterServer request and 8 copies of the Subscribe request.</p>
<p>I have two Exchange servers &#8211; One running Exchange 2010 and one running Exchange 2007 SP3. Each Exchange Server has 4 mailboxes that I am using for testing, hence 2 RegisterServer requests and 8 Subscribe requests.</p>
<p>One other thing I would recommend is if you have an MSDN subscription and you can install Outlook 2010, do so. It will make your life a whole lot easier for testing. In Outlook 2010, you can add more than one Exchange mailbox to your list of mailboxes which means that you can work on any of the test mailboxes from just one Windows login. This makes testing much, much easier.</p>
<h3>Establishing a Subscription</h3>
<p>As I have described, there are two parts to the Subscription API &#8211; the Subscription and the Notification. This code walk-through is therefore going to be divided into two main sections covering each of those parts of the API. This section covers setting up the subscription, and the subscription starts at the <em>CalendarService</em> WebService which is in the <em>EWSImpersonationCalendar</em> class in <em>com.tsg.ews</em>.</p>
<h4>EWSImpersonationCalendar</h4>
<p>This code was included in part 3 of this series, but we have added two additional operations in Lines 76 through 98; Subscribe and Unsubscribe:</p>
<pre>@WebMethod(operationName = &quot;Subscribe&quot;)
@WebResult(name = &quot;Response&quot;)
public EWSResponse subscribe(@WebParam(name = &quot;ServerID&quot;) String serverID,
				 @WebParam(name = &quot;UserAccount&quot;) String account,
				 @WebParam(name = &quot;CallbackURL&quot;) String url,
				 @WebParam(name = &quot;OpenEdgeURL&quot;) String oeUrl) {
	Subscription sub = new Subscription(serverID);
	sub.setAccount(account);
	sub.setListenerURL(url);
	sub.setOpenedgeURL(oeUrl);
	EWSResponse resp = sub.subscribe();
	if (!resp.hasError()) {
		SubscriptionManager.getInstance().register(sub);
	}
	return resp;
}

@WebMethod(operationName = &quot;Unsubscribe&quot;)
@WebResult(name = &quot;Response&quot;)
public EWSResponse unsubscribe(@WebParam(name = &quot;SubscriptionID&quot;) String subscriptionID) {
	SubscriptionManager.getInstance().unsubscribe(subscriptionID);
	return new EWSResponse(&quot;NoError&quot;, 0, &quot;Success&quot;);
}
</pre>
<p>These two operations rely heavily on the concept of the <em>SubscriptionManager</em> which keeps track of all active subscriptions and ensures that they are persisted to a local XML file. This means that when a notification is received later, we have the ability to relate that notification back to the subscription that initiated it, even if we shutdown and restart the Glassfish server. We will definitely talk more about this later once you have a chance to understand the concepts that affect it.</p>
<p>Looking at the <em>Subscribe</em> operation/method in lines 76 through 91, the operation expects to receive a <em>ServerID</em> as an input parameter. This <em>ServerID</em> is the <em>ServerID</em> we retrieved from a previous <a href="http://www.thesoftwaregorilla.com/2010/06/exchange-web-services-example-part-3-exchange-impersonation/#registerserver" target="_blank"><em>RegisterServer</em> call</a>.&nbsp;The <em>UserAccount</em> is used for Exchange Impersonation and to specify the mailbox for which the subscription is to be registered. The <em>CallbackURL</em> is the URL of the Java HTTP Servlet that will handle the notifications, and the <em>OpenEdgeURL</em> is the URL that should be used to call the OpenEdge AppServer.&nbsp;</p>
<p>Lines 82 through 85 establish a Subscription object and in line 86, the <em>subscribe</em> method is called. We&#39;ll look at the <em>subscribe</em> method in a little more detail in a moment, but for now just accept that it is responsible for actually making the call to the Exchange WebService and obtaining a <em>SubscriptionID</em>. In production code, the <em>Subscription</em> object would be instantiated by the <em>SubscriptionManager</em>, but it makes for more readable example code to do it the way I have done it here.</p>
<p>Lines 87 and 88 check the error status on the <em>EWSResponse </em>object&nbsp;and register the subscription with the <em>SubscriptionManager </em>if the subscription was successful. Whether the subscription was successful or not, the EWSResponse object is returned from the WebService, and if it was successful, it contains the <em>SubscriptionID</em> and <em>Watermark</em> for the subscription.</p>
<p>The <em>Unsubscribe</em> operation in lines 93 through 98 pass the <em>SubscriptionID</em> to the <em>unsubscribe</em> method on the <em>SubscriptionManager</em>.</p>
<p>There is a special case that the <em>Unsubscribe</em> method will support: If an &quot;*&quot; is passed as the <em>SubscriptionID, </em>all existing subscriptions will be canceled.</p>
<h4>The Subscription Object</h4>
<p>I said we would take a closer look at the <em>subscribe</em> method, and we&#39;ll do that in just a moment. First, though, open the <em>Subscription.java</em> class that is in the <em>com.tsg.ews.service</em> package. For the most part, this object is a set of properties, including the <em>ServiceID</em>, <em>ListenerURL</em>, <em>OpenEdgeURL</em>, <em>Account</em>, <em>SubscriptionID</em> and <em>Watermark</em>. The class has JAXB serialization annotations associated with it so that it can be serialized to and from XML.</p>
<p>There is also a <em>canceled</em> flag. The <em>canceled </em>flag is set to false until the <em>cancel</em> method in line 130 is called.</p>
<p>The <em>subscribe</em> method is in lines 97 through 128. The SOAP message that needs to be sent is built between lines 98 through 118:</p>
<pre>public EWSResponse subscribe() {
	StringBuffer request = new StringBuffer();
        request.append(&quot;&lt;Subscribe \n&quot;);
        request.append(&quot;               xmlns=\&quot;http://schemas.microsoft.com/exchange/services/2006/messages\&quot;\n&quot;);
        request.append(&quot;               xmlns:t=\&quot;http://schemas.microsoft.com/exchange/services/2006/types\&quot;&gt;\n&quot;);
        request.append(&quot;    &lt;PushSubscriptionRequest&gt;\n&quot;);
        request.append(&quot;\n&quot;);
        request.append(&quot;        &lt;t:FolderIds&gt;\n&quot;);
        request.append(&quot;            &lt;t:DistinguishedFolderId Id=\&quot;calendar\&quot;/&gt;&quot;);
        request.append(&quot;        &lt;/t:FolderIds&gt;\n&quot;);
        request.append(&quot;        &lt;t:EventTypes&gt;\n&quot;);
        request.append(&quot;            &lt;t:EventType&gt;CreatedEvent&lt;/t:EventType&gt;\n&quot;);
        request.append(&quot;            &lt;t:EventType&gt;ModifiedEvent&lt;/t:EventType&gt;\n&quot;);
        request.append(&quot;            &lt;t:EventType&gt;DeletedEvent&lt;/t:EventType&gt;\n&quot;);
        request.append(&quot;        &lt;/t:EventTypes&gt;\n&quot;);
        request.append(&quot;        &lt;t:StatusFrequency&gt;3&lt;/t:StatusFrequency&gt;\n&quot;);
        request.append(&quot;        &lt;t:URL&gt;&quot;);
        request.append(this.getListenerURL());
        request.append(&quot;&lt;/t:URL&gt;\n&quot;);
        request.append(&quot;    &lt;/PushSubscriptionRequest&gt;\n&quot;);
        request.append(&quot;&lt;/Subscribe&gt;\n&quot;);
        SOAPRequest message = new SOAPRequest(request.toString(), this.getAccount());
</pre>
<p>The Subscription message has been discussed in some detail in <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/#subscriptionrequest" target="_blank">my previous post on Subscriptions and Notifications</a>, and this message is largely the same message as that one, with the exception that the user can specify the URL, and the instantiation of the SOAPRequest object in line 118 (the last line) results in the use of Exchange Impersonation to make the request.</p>
<p>The <em>DistinguishedFolderId</em> node that is added in line 105 will result in notifications being generated based on any changes to the folder(s) that is(are) listed &#8211; in this case, just the <em>calendar</em> folder. The following folders are supported by name:</p>
<ul>
<li>calendar</li>
<li>contacts</li>
<li>deleteditems</li>
<li>drafts</li>
<li>inbox</li>
<li>journal</li>
<li>notes</li>
<li>outbox</li>
<li>sentitems</li>
<li>tasks</li>
<li>msgfolderroot</li>
<li>root</li>
<li>junkemail</li>
<li>searchfolders</li>
<li>voicemail</li>
</ul>
<p>Any folder can be monitored, but if it is not one of these folders, you need to supply the <em>FolderID</em> for the folder.</p>
<p>The <em>EventTypes</em> node in lines 107 through 111 defines the list of events for which notifications should be received. This list could include any of the following values:</p>
<ul>
<li>CopiedEvent</li>
<li>CreatedEvent</li>
<li>DeletedEvent</li>
<li>ModifiedEvent</li>
<li>MovedEvent</li>
<li>NewMailEvent</li>
<li>FreeBusyChangedEvent (Exchange 2010 only)</li>
</ul>
<p>The <em>StatusFrequency</em> node is described in a lot more detail <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/#statusfrequency" target="_blank">in my previous post</a>. In this case, I am asking for Exchange to send a status event to the Java HTTP Servlet every 3 minutes. This gives me the opportunity to cancel the subscription every 3 minutes. I have mixed feelings about status frequencies in terms of how long they should be, and I&#39;ll talk more about this later in this article.</p>
<p>Once the message is built, we call <em>makeRequest</em> on the <em>ExchangeService</em> object with the message in lines 119 through 128:</p>
<pre>        EWSResponse response;
        try {
		response = getService().makeRequest(message);
		subscriptionID = response.getSubscriptionId();
		watermark = response.getWatermark();
	} catch (Exception e) {
		response = new EWSResponse(e);
	}
	return response;
}
</pre>
<p>If the call is successful, the EWSResponse object will contain a unique <em>SubscriptionID</em> and a <em>Watermark</em>. It is important to understand that the <em>SubscriptionID</em> is unique, even if you have already registered a subscription for this mailbox. In other words, it is possible to have more than one subscription active for a mailbox.</p>
<h4>The SubscriptionManager Object</h4>
<p>The SubscriptionManager object is responsible for tracking all active subscriptions. In essence, it is a persistence mechanism for maintaining the state of a subscription over a long period of time. The SubscriptionManager takes care of persisting the subscription details to an XML file and providing a central point through which all changes to a subscription can take place. Any time any object needs information about a subscription, it makes a call to the SubscriptionManager to obtain information about the subscription.</p>
<p>Any changes made to a subscription are persisted to the XML file, so that if the Glassfish server is restarted, and the subscription is not lost, the SubscriptionManager will be able to maintain the context of any subscriptions that are currently active.</p>
<p>Why do we care about this context anyway? For a number of reasons:</p>
<ol>
<li>We associate the OpenEdge URL with a subscription and there is no way to include this information with the information that we submit to Exchange Server so there is no way to know what we need to do when we receive a notification if we don&#39;t persist the context of the subscription;&nbsp;</li>
<li>To be able to specifically cancel a subscription, the SubscriptionManager needs to know about it. Remember that the only ways to cancel a subscription are by responding to a notification with an unsubscribe response, or by not responding and waiting for it to time out. Ideally, we need the ability to do this gracefully, and that means responding to a notification with the unsubscribe response. It may be several minutes between the time that an unsubscribe request is received by the Java EWS WebService and the time a notification is received by the Java HTTP Servlet, so all the SubscriptionManager can do is note that the subscription is canceled. When the next notification comes in, the Java HTTP Servlet can then act on the cancellation;</li>
<li>In a production environment where there may be numerous mailboxes that are all being monitored concurrently, it would be far more efficient to receive all notifications for one mailbox as a set. The problem is that when a subscription is registered, there may be no way of knowing what other subscriptions will be registered for the same mailbox. Although the implementation that I have included does not do this, the SubscriptionManager is the ideal place to maintain a link between subscriptions for the same mailbox so that the load on the Exchange Server can be minimized and delegated to a separate middleware service; and</li>
<li>If the Glassfish server goes down for any reason, context needs to be maintained so that when it is restarted, it can re-establish the subscriptions as they were running before it was terminated. Of course, in a production environment with load balancing in place, it would be unlikely that the Glassfish server farm would not be available, but the notion of more than one Glassfish server immediately means that the subscription context needs to be persisted centrally.</li>
</ol>
<p>So although the SubscriptionManager that is provided with this example is somewhat primitive, it performs a key role in maintaining continuity and performance for subscriptions.&nbsp;</p>
<p>The SubscriptionManager code is not particularly interesting so I am not going to spend any time walking through it. It definitely has holes in it, but it works for the examples that we are using here.</p>
<h4>Establishing a Subscription</h4>
<p>Now that you know how the code works for establishing a subscription, let&#39;s go ahead and register a subscription for one of the mailboxes. Assuming you already have the code installed and running in Eclipse and the Glassfish server running, open soapUI and open a request under the <em>Subscribe</em> operation for the <em>CalendarService</em>:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_SettingUpSubscription1.jpg" target="_blank"><img alt="Creating the subscription request" height="297" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_SettingUpSubscription1.jpg" width="600" /></a></p>
<p>The <em>ServerID</em> element should contain a UUID for a server that was registered using the <em>RegisterServer</em> operation. The <em>UserAccount</em> should contain the e-mail address of the mailbox that you want to monitor.</p>
<p>The <em>CallbackURL</em> is the first new element you need to complete. This is the URL that the Exchange Server should use for all notifications. This URL will be in the form <em>http://&lt;server-name&gt;:8080/EWSAPI/EWSListener</em>&nbsp;where <em>&lt;server-name&gt;</em> is the machine that is running your Glassfish server (your local machine). Note that you cannot use localhost as the server name. Calls to this URL are going to come from your Exchange Server so it needs a DNS-registered name.</p>
<p>The <em>OpenEdgeURL</em> is only of interest to you if you are an OpenEdge developer. If this element contains anything but a string that begins with <em>AppServer:// </em>it will be ignored. If you are using the default asbroker1 AppService, the URL that I have in the screenshot (<em>AppServer://localhost:5162/asbroker1</em>) should work for you, assuming your AppServer is running on the same machine as your Glassfish server.</p>
<p>Once you have filled out the request parameters, submitting the request will get you a response similar to the one in the following screenshot:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_SettingUpSubscription2.jpg" target="_blank"><img alt="Subscription request response" height="204" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_SettingUpSubscription2.jpg" width="600" /></a></p>
<p>The <em>Response</em> node contains 3 attributes. The <em>ErrorState</em> attribute should have a value of &quot;NoError&quot; and should be followed by a <em>SubscriptionID</em> attribute and a <em>Watermark</em> attribute, both with strings of characters that don&#39;t mean anything. The <em>SubscriptionID</em> uniquely identifies the subscription and can be used to unsubscribe through the <em>Unsubscribe</em> operation.</p>
<p>If you switch your focus to the Console view in Eclipse for the Glassfish Server Log, you will see messages start popping up occasionally in the view like the one below:</p>
<pre>INFO: Notification:
=============
	Account: froggf@intangere.internal.intangere.com
	Subscription Id: LQBpbnRhbmdlcmVleHMuaW50YW5nZXJlLmludGVybmFsLmludGFuZ2VyZS5jb20QAAAAdyIIAinbTUGf+zpPjEyTaw==
	Prev Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHGLgAAAAAAAAE=
	More Events: false
	Status: true
	Event: StatusEvent	Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHGLgAAAAAAAAE=

INFO: &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;soap:Envelope ... &lt;/soap:Envelope&gt;
INFO: Total execution time: 205
</pre>
<p>These messages will pop up every 3 minutes and indicate that the Glassfish server is receiving messages from the Exchange Server.</p>
<p>If you switch to Outlook and create a calendar item in Outlook, you will see a message something like the one below about 20 seconds after you create it:</p>
<pre>INFO: Notification:
=============
	Account: froggf@intangere.internal.intangere.com
	Subscription Id: LQBpbnRhbmdlcmVleHMuaW50YW5nZXJlLmludGVybmFsLmludGFuZ2VyZS5jb20QAAAAdyIIAinbTUGf+zpPjEyTaw==
	Prev Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHGLgAAAAAAAAE=
	More Events: false
	Status: false
	Event: ModifiedEvent	Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHJLgAAAAAAAAE=
			TimeStamp: Wednesday, July 7, 2010 6:39:42 PM PDT
		Affected Item-- Type: FolderId	ID: ...	ChangeKey: AgAAAA==
	Event: ModifiedEvent	Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHKLgAAAAAAAAE=
			TimeStamp: Wednesday, July 7, 2010 6:39:42 PM PDT
		Affected Item-- Type: FolderId	ID: ...	ChangeKey: AgAAAA==
	Event: ModifiedEvent	Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHLLgAAAAAAAAE=
			TimeStamp: Wednesday, July 7, 2010 6:39:42 PM PDT
		Affected Item-- Type: FolderId	ID: ...	ChangeKey: AgAAAA==
	Event: CreatedEvent	Watermark: AQAAANnz8X+xbA5HtnQ8PXPRJfHRLgAAAAAAAAE=
			TimeStamp: Wednesday, July 7, 2010 6:39:42 PM PDT
		Affected Item-- Type: ItemId	ID: ...	ChangeKey: DwAAAA==
		Appointment-- Subject: New Appointment for Software Gorilla test
			Location: Who cares where! Just make sure it works!!
			Start: Wednesday, July 7, 2010 7:00:00 PM PDT	End: Wednesday, July 7, 2010 8:00:00 PM PDT

INFO: &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;soap:Envelope ... &lt;/soap:Envelope&gt;
INFO: Total execution time: 75</pre>
<p>I have edited this slightly so it fits on the screen. This notification informs you that the Exchange Server has called the Java HTTP Servlet which has processed the notification.</p>
<p>If you supplied an OpenEdge URL for the AppServer, and you connect to the database that contains the <em>ews_update</em> table from OpenEdge and execute the following code, you will find entries in the database for each appointment that you created:</p>
<pre>for each ews_update:
    display skip(1)
        ews_update.cEmailAddress skip
        ews_update.cSubject skip
        ews_update.cLocation skip
        ews_update.dTimeStamp skip
        ews_update.dStartTime ews_update.dEndTime skip(2)
      with 1 down side-labels width 100.
end.</pre>
<p><img align="left" alt="Data from the Exchange Notification reaching OpenEdge" height="245" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/07/Part4_DataInOpenEdge.jpg" width="415" />There are a couple of important things to note about the data in the OpenEdge database. If you are not living in the UTC timezone, you will see a difference between the time that OpenEdge reports and the time that notification reported. That&#39;s to be expected. Time in the database is reported as UTC. In my case, I am in the PDT (Pacific Daylight Time) timezone.</p>
<p>Second, it looks like the subject and location have been truncated. Again, no surprise. I set the formats in the database fields to X(50) for the subject and location, although the database will store more than that for them.</p>
<p>Looking back to the notification that we received from Exchange, you&#39;ll note that there is a Watermark for each event, and that each Watermark is different (sometimes by only one character). The Watermark provides a way of going back and verifying that you have received all events from Exchange, but it is important to realize that subscribing with an old Watermark can have significant performance impacts on Exchange.</p>
<p>You&#39;ll also notice that there is a Total Execution Time for each notification. This is the time taken (in milliseconds) from the time the notification was received, until the time the response was flushed out to the HTTP stream. In other words, it is the total time taken to process the request. What is interesting about this is that it takes as much as 4 times longer to process a StatusEvent than it does to process a real notification. I have determined that this has to do with the time it takes to read the original notification message off the input stream, and I have not yet figured out how to shorten that time.</p>
<p>Now that you have seen the notification mechanism working, let&#39;s look at what is going on under the covers.&nbsp;</p>
<h3>Receiving Notifications &#8211; EWSListener</h3>
<p>As noted, notifications are received on the&nbsp;<em>http://&lt;server-name&gt;:8080/EWSAPI/EWSListener </em>URL. To achieve this, the EWSListener.java class in com.tsg.ews listens on the URL for incoming requests, so go ahead an open EWSListener.java in Eclipse.</p>
<p>All of the work associated with processing a request occurs in the doPost method that runs between lines 52 and line 170. I have included a lot of comments in the code that is in the zip file, so I am going to extract sections of it here and exclude the comments that are in the source. Line numbers, though, correspond with the source in the zip file.</p>
<h4>Receiving the Notification (2.1 in the diagram above)</h4>
<p>Lines 52 through 63 deal with receiving the notification:</p>
<pre>protected void doPost(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {
	boolean safeDoc = false;
	boolean canceled = false;

	long startTime = GregorianCalendar.getInstance().getTimeInMillis();
	long endTime;

	try {

		String result = ExchangeService.getResult(request.getInputStream());
		Document doc = loadXML(result);
		safeDoc = true;

		Notification nfcn = null;
		try {
			nfcn = new Notification(doc);
</pre>
<p>The notification XML document is received from Exchange in the <em>request</em> object. The <em>response</em> object will contain our response back to Exchange later.</p>
<p>The <em>safeDoc</em> flag is used to indicate that we have successfully parsed the XML document and that it is indeed a document that we expect. The <em>canceled</em> flag indicates that the response to Exchange should be an <em>unsubscribe</em> message.&nbsp;The <em>startTime</em> and <em>endTime</em> fields are used to calculate the total elapsed time of the call.</p>
<p>In line 63, we make a call to <em>getResult</em> (now a static method) on the <em>ExchangeService</em> class. This method simply reads all the data off an input stream.&nbsp;</p>
<p>Now that we have a character string, it&#39;s time to do something with it, and in line 66, we make a call to the internal loadXML method which parses the XML string into a DOM document.</p>
<p>In line 74, we instantiate a Notification object with the XML document and the Notification object takes care of parsing the the DOM into appropriate objects.&nbsp;</p>
<h4>Parsing the XML</h4>
<p>I&#39;m not going to spend any time walking through the code that parses the XML document, but the following XML is from an actual notification for the creation of a new appointment (I&#39;ve truncated IDs for brevity):</p>
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;soap11:Header /&gt;
    &lt;soap11:Body&gt;
        &lt;m:SendNotification xmlns:t=&quot;http://schemas.microsoft.com/exchange/services/2006/types&quot;
                               xmlns:m=&quot;http://schemas.microsoft.com/exchange/services/2006/messages&quot;&gt;
            &lt;m:ResponseMessages&gt;
                &lt;m:SendNotificationResponseMessage ResponseClass=&quot;Success&quot;&gt;
                    &lt;m:ResponseCode&gt;NoError&lt;/m:ResponseCode&gt;
                        &lt;m:Notification&gt;
                            &lt;t:SubscriptionId&gt;LwBncnzAg=&lt;/t:SubscriptionId&gt;
                            &lt;t:PreviousWatermark&gt;AQAAAAE=&lt;/t:PreviousWatermark&gt;
                            &lt;t:MoreEvents&gt;false&lt;/t:MoreEvents&gt;
                            &lt;t:ModifiedEvent&gt;
                                &lt;t:Watermark&gt;AQAAAAAE=&lt;/t:Watermark&gt;
                                &lt;t:TimeStamp&gt;2010-07-05T18:06:29Z&lt;/t:TimeStamp&gt;
                                &lt;t:FolderId Id=&quot;AQAoAnnJwAAAx4AAAA=&quot; ChangeKey=&quot;AgAAAA==&quot; /&gt;
                                &lt;t:ParentFolderId Id=&quot;AQAoAAAxIAAAA=&quot; ChangeKey=&quot;AQAAAA==&quot; /&gt;
                            &lt;/t:ModifiedEvent&gt;
                            &lt;t:CreatedEvent&gt;
                                &lt;t:Watermark&gt;AQAAAAE=&lt;/t:Watermark&gt;
                                &lt;t:TimeStamp&gt;2010-07-05T18:06:29Z&lt;/t:TimeStamp&gt;
                                &lt;t:ItemId Id=&quot;AAAoAGF/4YLFkwAAAAQJAgAA&quot; ChangeKey=&quot;DwAAAA==&quot; /&gt;
                                &lt;t:ParentFolderId Id=&quot;AQAoAAAx4AAAA=&quot; ChangeKey=&quot;AQAAAA==&quot; /&gt;
                            &lt;/t:CreatedEvent&gt;
                        &lt;/m:Notification&gt;
                    &lt;/m:SendNotificationResponseMessage&gt;
            &lt;/m:ResponseMessages&gt;
        &lt;/m:SendNotification&gt;
    &lt;/soap11:Body&gt;
&lt;/soap11:Envelope&gt;</pre>
<p>The <em>Notification</em> element contains a <em>SubscriptionId</em>, <em>PreviousWatermark</em> and <em>MoreEvents</em> element.&nbsp;When the code parses this XML document, it creates a <em>Notification</em> object to contain this information.</p>
<p>The <em>Notification</em> element also contains an&nbsp;<em>Event</em> element for each event for which you are receiving a notification. In this case, the first <em>Event</em> element is a <em>ModifiedEvent </em>and it applies to a Folder (in this case, the calendar folder that has been modified by the addition of a new item). The second event, the <em>CreatedEvent</em> element, contains an <em>ItemId</em> element that identifies the calendar item that was created.</p>
<p>The <em>Notification</em> is an iterable collection of <em>SubscriptionEvent</em> objects, so when the code parses these elements, it creates and stores a <em>SubscriptionEvent </em>object to hold each of these <em>Event</em> elements.&nbsp;Each <em>Event</em> node contains a <em>Watermark</em> that is applicable for the event that took place and a&nbsp;<em>TimeStamp</em> &#8211; the time that the event took place. These values are recorded against the <em>SubscriptionEvent</em> object.</p>
<p>An&nbsp;<em>Event</em>&nbsp;element will contain either a&nbsp;<em>FolderId</em>&nbsp;element or an&nbsp;<em>ItemId</em>&nbsp;element which is the object that was affected by the event. This element is parsed and an <em>IDHolder</em> object is created to contain it and it is stored as the <em>AffectedItem</em> property of a <em>SubscriptionEvent</em> object.</p>
<p>There is also a <em>ParentFolderId</em> which is the ID of the folder that contains the object that is affected by the event. When this element is parsed, its data is also stored in an <em>IDHolder</em> object in the <em>ParentFolder</em> property of the <em>SubscriptionEvent</em> object.</p>
<p>In the case of the above notification, one <em>Notification</em> object was created and it contained two <em>SubscriptionEvent</em> objects &#8211; one for the <em>ModifiedEvent</em> and one for the <em>CreatedEvent</em>.&nbsp;</p>
<h4>Marrying the Notification and the Subscription</h4>
<p>Now that we have parsed the notification, we&#39;ll go back to the code in line 77 through 86 and deal with marrying the Notification with a Subscription object:</p>
<pre>	Subscription sub = SubscriptionManager.getInstance().getSubscription(nfcn.getSubscriptionId());
	if (sub != null) {
		nfcn.setAccount(sub.getAccount());

		canceled = sub.isCanceled();
		if (canceled)
			SubscriptionManager.getInstance().clearSubscription(sub);

		if (!nfcn.isStatus()) {
			getAppointments(sub.getService(),nfcn);
		}</pre>
<p>In line 77 we ask the <em>SubscriptionManager</em> for the <em>Subscription</em> object associated with the <em>SubscriptionId</em> in the <em>Notification</em> object. The next set of code only executes if we found a <em>Subscription</em> object.</p>
<p>In line 80, we set the account (e-mail address) for the notification to the account of the subscription and in line 84, we check to see if the subscription has been canceled by a call to the <em>Unsubscribe</em> operation. If it has, we set the <em>canceled</em> flag and remove the subscription from the <em>SubscriptionManager</em> because this is the last notification we will receive for this subscription.</p>
<p>As I mentioned earlier, Exchange will send notifications on a regular basis (as defined by <em>StatusFrequency</em>). These notifications do not contain any data; they are simply status messages (think of them as pings). When we parse the SOAP message into the <em>Notification</em> object, if the notification is a <em>StatusEvent</em>, we set a flag to indicate that this is only a status message. In line 91 we check to see if this is a status message, and if not, we make a call to <em>getAppointments</em> which is responsible for retrieving appointments from the Exchange Server.</p>
<h4>getAppointments (2.3 in the diagram above)</h4>
<p>The getAppointments method is in lines 176 through 209:</p>
<pre>private void getAppointments(ExchangeService service, Notification nfcn) {

	for (SubscriptionEvent se: nfcn) {

		if (se.getEventType() != EventType.STATUS
				&amp;&amp; se.getEventType() != EventType.DELETED
				&amp;&amp; se.getAffectedItem() != null
				&amp;&amp; se.getAffectedItem().getIdType() == IDType.ITEM) {

			Appointment appt = new Appointment(service);
			appt.setEmailAddress(nfcn.getAccount());

			EWSResponse resp = appt.retrieve(se.getAffectedItem().getId(),
                                                  se.getAffectedItem().getChangeKey());
			if (!resp.hasError()) {
				se.setAppointment(appt);
			}
			else {
				if (resp.getResponseCode().equals(&quot;ErrorItemNotFound&quot;)) {
					se.setEventType(EventType.DELETED);
				}
				else {
					System.out.println(...);
				}
			}
		}
	}
}</pre>
<p>As you will recall, the notification that we receive from Exchange only contains the ID of the item that has changed. It does not provide any information about the item itself. In <em>getAppointments </em>we take care of retrieving those items.</p>
<p><em>Notification</em> objects are iterable collections of <em>SubscriptionEvents</em> so we loop through all the <em>SubscriptionEvents</em>&nbsp;(line 179) in the <em>Notification</em> collection, ignoring anything that is not a <em>Created-</em> or <em>ModifiedEvent</em> for an <em>ItemId </em>(lines 183 to 186).</p>
<p>We then instantiate an Appointment object (line 189), set the account for it (line 190), and attempt to retrieve it from the Exchange Server (line 193).</p>
<p>If we&#39;re successful retrieving the appointment, we set the Appointment property of the SubscriptionEvent from the appointment we retrieved (line196).</p>
<p>If we failed with an <em>ErrorItemNotFound</em> message from Exchange, it means that the item has been deleted so we cannot find any information about it. The event type therefore needs to be changed to a <em>DeletedEvent </em>(lines 200 through 202). This may seem strange, but remember that Exchange will move a deleted item to the Deleted Items folder which means we will receive a <em>ModifiedEvent</em>, rather than a <em>DeletedEvent</em>.</p>
<h4>Calling OpenEdge (2.4 in the diagram above)</h4>
<p>Returning to the code in doPost, lines 96 through 103 deal with the call to OpenEdge:</p>
<pre>	System.out.println(nfcn.print());

	// **OESPECIFIC
	// The following code is inactive in the Java zip file version of the code.
	// If the subscription has an OpenEdge AppServer URL in it, let&#39;s call OpenEdge.
	if (sub.getOpenedgeURL().startsWith(&quot;AppServer://&quot;)) {
		OpenEdgeCallFactory.callOpenEdge(sub, nfcn);
	}
</pre>
<p>Line 96 just displays the notification information in human readable form &#8211; it is responsible for the Notification messages in the server log.</p>
<p>Line 101 through 103 checks if the OpenEdge URL for the subscription starts with the string &quot;AppServer://&quot; and, if so, calls the <em>callOpenEdge</em> method which is in lines 68 through 99 of the <em>OpenEdgeCallFactory</em> class:</p>
<pre>public static void callOpenEdge(Subscription sub, Notification nfcn) {
	checkInitialized();
	for (SubscriptionEvent se: nfcn) {
		if (se.getAffectedItem() != null &amp;&amp; se.getAffectedItem().getIdType() == IDType.ITEM) {
			Call call = new Call(OECALL);
			call.setParameterValue(PAR_EMAIL, sub.getAccount());
			call.setParameterValue(PAR_SUBSCRIPTION_ID, nfcn.getSubscriptionId());
			call.setParameterValue(PAR_EVENT_TYPE, se.getEventType().toString());
			call.setParameterValue(PAR_TIME_STAMP, se.getTimeStamp());
			call.setParameterValue(PAR_WATERMARK, se.getWatermark());
			call.setParameterValue(PAR_ITEM_ID, se.getAffectedItem().getId());
			call.setParameterValue(PAR_CHANGE_KEY, se.getAffectedItem().getChangeKey());
			Appointment appt = se.getAppointment();
			if (appt != null) {
				call.setParameterValue(PAR_SUBJECT, appt.getDescription());
				call.setParameterValue(PAR_LOCATION, appt.getLocation());
				call.setParameterValue(PAR_NOTES, appt.getNotes());
				call.setParameterValue(PAR_START_TIME, appt.getStartDate());
				call.setParameterValue(PAR_END_TIME, appt.getEndDate());
				call.setParameterValue(PAR_REMINDER_MINUTES, appt.getReminderMinutes());
				call.setParameterValue(PAR_REMINDER_SET, appt.isReminderSet());
			}
			call.executeCall(sub.getOpenedgeURL());
			if (call.isReturnError()) {
				System.out.println(...);
			}
			else if (call.getFailure() != null) {
				System.out.println(...);
			}
		}
	}
}
</pre>
<p>This method simply instantiates a Call object (line 72), sets the parameters for the call to ewscall.p (lines 73 through 89), and executes the call using the OpenEdge URL (line 90). A successful call to ewscall.p will result in the data being written to the OpenEdge database.&nbsp;If you read my article on the <a href="http://www.thesoftwaregorilla.com/2009/11/openedge-dynamic-openclient-java-example/" target="_blank"><em>OpenEdge Dynamic OpenClient Java Example</em></a>, this code will be reasonably familiar.</p>
<p>At this point, all that is left to do is update the subscription and respond to the Exchange Server.</p>
<h4>Updating the Subscription</h4>
<p>From the information in David Sterling, et al&#39;s book, <em>Inside Microsoft Exchange Server 2007 Web Services</em>, I had understood that the Watermark was associated with a subscription, but in working with this a little more, I have come to the conclusion that the Watermark is associated with the Exchange Server as a whole. I had been hoping to use the Watermark to guarantee that I knew that I had received all events from the Exchange Server, but it does not seem to work the way I had understood. I&#39;m still piecing this together at the time of writing, so the code that is included with the example is predicated on my understanding from Sterling, et al.</p>
<p>Lines 107 through 127 deal with updating the subscription:</p>
<pre>			if (!sub.getWatermark().equals(nfcn.getPreviousWatermark())) {
				System.out.println(...);
			}

			String lastWm = null;
			for (SubscriptionEvent se : nfcn) {
				lastWm = se.getWatermark();
			}

			if (lastWm != null) {
				sub.setWatermark(lastWm);
			}
		}
		else {
			canceled = true;
			System.out.println(...);
		}
	}</pre>
<p>In line 107 through 109, we check to see if the subscription&#39;s current watermark matches the previous watermark of the notification we received. If it doesn&#39;t (and if my understanding of Sterling, et al is correct, it should), we print a warning message to the log.</p>
<p>In lines 112 through 116, we loop through all the <em>SubscriptionEvent</em> objects and store the last watermark and line 117 through 119, we set the Watermark on the <em>Subscription</em> to the Watermark of the last <em>SubscriptionEvent</em>.&nbsp;</p>
<p>In lines 121 through 125 we deal with the situation where we were unable to match the notification with a subscription &#8211; we set the canceled flag to true so that the subscription will terminate.</p>
<h4>Responding to Exchange (2.2 in the diagram above)</h4>
<p>In lines 138 through 170 we deal with responding to Exchange:</p>
<pre>	if (!safeDoc) {
		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
	}
	else {
		String str;

		if (canceled) {
			str = getResponseXML(UNSUBSCRIBE);
		}
		else {
			str = getResponseXML(OK);
		}

		response.setCharacterEncoding(&quot;UTF-8&quot;);
		response.setStatus(HttpServletResponse.SC_OK);
		response.setContentType(&quot;text/xml; charset=UTF-8&quot;);
		response.setContentLength(str.length());

		PrintWriter w = response.getWriter();
		w.print(str);
		w.flush();
	}
	response.flushBuffer();
	endTime = GregorianCalendar.getInstance().getTimeInMillis();
	System.out.println(String.format(&quot;Total execution time: %1$s&quot;, (Long) (endTime - startTime)));
}</pre>
<p>In lines 139 through 141, we handle the situation where we received a bad message from Exchange &#8211; we return an HTTP 400 error.</p>
<p>In lines 143 through 151 we check to see if the canceled flag is set. If it is, we build an Unsubscribe response, otherwise we just build an OK acknowledgement response. Lines 154 through 157 set some properties of the response object and lines 160 through 167 write the response to the output stream and flush the buffers.&nbsp;</p>
<p>Finally, in lines 168 and 169 we determine the amount of time that has elapsed since the notification was received and we display this.</p>
<h3>Summary</h3>
<p>That&#39;s it. Now you have seen how to handle the&nbsp;Exchange Web Services&nbsp;Push Subscription API in Java. Although this may seem like a convoluted piece of code, I have found it to be extraordinarily stable. I have experimented with taking down the Glassfish server and bringing it back up and the notifications keep on coming.</p>
<p>I have left the server running for days with no updates happening on the Exchange Server with no problem at all. I have also exposed it to some pretty serious stress and it has performed with no problems at all on fairly small hardware and software configurations.</p>
<p>Most of the time, notifications, including the call back to Exchange Server and OpenEdge, are being processed in around 100ms. StatusEvents take just over 200ms.</p>
<p>The one thing I am still having trouble with is trying to decide on an appropriate StatusFrequency. I would like to set the StatusFrequency to 10 minutes. That way, it will take 30 minutes for a subscription to expire. The problem is that clean cancellations rely on regular status events, so anything longer than 3 minutes can seem like an eternity. One thing I have definitely concluded is that the StatusFrequency needs to be configurable.</p>
<p>I hope this article has been useful. The next article in this series is going to deal with determining availability, but I am going to be engaged in some pretty serious development work for the next few weeks so it is likely that the next article in this series will only see the light of day toward the end of the Summer.&nbsp;</p>
<p>Let me have your feedback&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2010/07/exchange-web-services-example-part-4-subscriptions-and-notifications/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Exchange Web Services Example &#8211; Part 3 &#8211; Exchange Impersonation</title>
		<link>http://www.thesoftwaregorilla.com/2010/06/exchange-web-services-example-part-3-exchange-impersonation/</link>
		<comments>http://www.thesoftwaregorilla.com/2010/06/exchange-web-services-example-part-3-exchange-impersonation/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 02:40:51 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Exchange Web Services]]></category>
		<category><![CDATA[Exchange Web Services Example]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[EWS]]></category>
		<category><![CDATA[Exchange EWS]]></category>
		<category><![CDATA[Exchange Impersonation]]></category>
		<category><![CDATA[Exchange Server 2007]]></category>
		<category><![CDATA[Exchange Server 2010]]></category>
		<category><![CDATA[Java 5]]></category>
		<category><![CDATA[Java 6]]></category>
		<category><![CDATA[Java EE 6]]></category>
		<category><![CDATA[Microsoft Exchange 2007]]></category>
		<category><![CDATA[Microsoft Exchange 2010]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=890</guid>
		<description><![CDATA[In part 3 of this series on integrating Exchange Web Services with Java and OpenEdge, we're going to talk about a technique for accessing mailboxes called Exchange Impersonation. The first part of this article is going to talk about what it is, how it works, and the very serious risks it can potentially introduce to your enterprise. We'll talk a little about how you can mitigate those risks, how to set it up from an administrative point of view, and then we'll actually use it.

As with the other articles in this series, there is also a set of sample code that you can download and install to follow along later in the article.]]></description>
			<content:encoded><![CDATA[<p>In part 3 of this series on integrating Exchange Web Services with Java and OpenEdge, we&#39;re going to talk about a technique for accessing mailboxes called&nbsp;<em>Exchange Impersonation.</em></p>
<p>I had planned to get this article posted a few weeks back, but a number of things have cropped up in between. I have already been using Exchange Impersonation for a while, but it has been against Exchange 2007. As I was doing the initial work on this article, I knew that Microsoft had changed the mechanism for Impersonation in Exchange 2010, so I decided to investigate the impact of it. That took a lot more work than I was planning, as I ended up installing and running a separate 2010 server and learning a lot about Windows Powershell that I really was not planning. So I&#39;m sorry about the delay, but I think you are probably going to agree that the due-diligence was worth it.</p>
<p>The first part of this article is going to talk about what Exchange Impersonation is, how it works, and the very serious risks it can potentially introduce to your enterprise. We&#39;ll talk a little about how you can mitigate those risks, how to set it up from an administrative point of view, and then we&#39;ll actually use it.</p>
<p>As with the other articles in this series, there is also a <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/tsgewsexample_3.zip">set of sample code that you can download</a> and install to follow along later in the article.</p>
<p>So here we go&#8230;</p>
<h3>The Need for Server-to-Server (S2S) Communication</h3>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" target="_blank"><img align="left" alt="Server to Server communication" height="275" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" width="400" /></a>As I described in my initial article, the whole reason I am building this solution is to act as an intermediate service between a Customer Relationship Management (CRM) application and Microsoft Exchange. An OpenEdge application will be making updates to a database that need to trigger the creation of appointments. Furthermore, when any of those appointments change on the Microsoft Exchange Server, the CRM application needs to be updated accordingly. The important thing to realize is that the updates to and from the OpenEdge application will happen in the business logic and therefore there is no client user. The client is really a server process itself.</p>
<p>To complicate matters further, the &quot;client&quot; is also a service-oriented application, so there is no tight coupling between Microsoft Exchange and the CRM application. This means that all communication with Exchange is to happen via message-oriented middleware or MOM (specifically, ApacheMQ and SonicMQ), which, in turn means that the connection to Exchange will be from a service container in the middleware, and that service container can have no knowledge of the client user. Practically speaking, that container would need to know the user names and passwords for all potential users of the system and that really is not practical.</p>
<p>The service container (which is a server process) is communicating with Exchange Server (another server process) on behalf of a user &#8211; thus, server-to-server (S2S) communication.&nbsp;</p>
<p>So you have a server communicating with another server on behalf of a user. From the user&#39;s point of view, it really is as though the user performed the business action that led to the effect on Exchange.</p>
<p>In the diagram of the architecture, the Glassfish Application Server containing the Java EWS WebService and the Java HTTP Servlet are really the one side of the server-to-server configuration and the Microsoft Exchange Server is the other.</p>
<h3>What is Exchange Impersonation?</h3>
<p>Exchange Impersonation is a mechanism that allows a single Windows Active Directory account to act on behalf of other users on a Microsoft Exchange mailbox as if they were performing the action themselves. In other words, assuming I create an Active Directory logon called <em>ewsproxy</em> (which we will do later on), and I give <em>ewsproxy</em> Exchange Impersonation privileges for users <em>froggf</em> and <em>hippoh</em>, ewsproxy can perform any action that froggf or hippoh can perform on their mailboxes.</p>
<p>There is one small caveat. <em>Exchange Impersonation only works via the Exchange Web Services API</em>. This means that although ewsproxy is able to act on behalf of froggf and hippoh, it only works if it is done as an Exchange Web Service call; it does not work through Outlook, Outlook Web Access, or any other Exchange client, and that is good news. I&#39;ll get to why in a moment.</p>
<p>Another thing to bear in mind is that from froggf&#39;s point of view, he cannot tell the difference between an appointment that was created by ewsproxy and an appointment created by himself. To all intents and purposes, ewsproxy is froggf when it operates on froggf&#39;s mailbox.</p>
<p>Exchange Impersonation is the ideal way for a service to act on behalf of an Exchange user, and that is specifically what I want it for. Remember, I am looking at the Exchange Web Services API from the point of view of a Java service that can perform any operation on behalf of any user. It is effectively a super-user.</p>
<h4>Other Alternatives</h4>
<p>Exchange Impersonation is not the only way to do this. There are a number of alternatives that can be used, but none of them work quite as well as Exchange Impersonation:</p>
<ul>
<li>Delegate &#8211; You can delegate rights to other accounts to act on your behalf, but you have to do it from your Exchange client (Outlook). In other words, the end-user controls these rights and can grant and revoke privileges as desired. Delegation is really a mechanism for a user to give another user permissions on their mailbox.</li>
<li>Send As &#8211; An Administrator can set up an account so that it can send mail on behalf of another account. This permission allows most of the same behavior as Exchange Impersonation, with one subtle difference: A user can act on behalf of another user from their Exchange client, whereas with Exchange Impersonation, it is only through the Exchange Web Services API that a user can act on behalf of another user.</li>
</ul>
<p>There are also a number of other alternatives that are not Exchange-specific, but these normally require elevated permissions, such as admin rights, which are not desirable. The beauty of Exchange Impersonation lies in the fact that the Exchange Impersonation account is nothing more than a regular user account, and you can lock down the account so that it can do nothing else. It is therefore the best alternative for this purpose.&nbsp;</p>
<h3>Risks of Exchange Impersonation</h3>
<p>When BP got the permit to drill the well that is now spewing oil into the Gulf of Mexico, they knew that there was a lot of risk associated with what they were doing. By all accounts, they cut a lot of corners for the sake of profit, which is why we have the mess on the beaches in Louisiana that we do today.&nbsp;</p>
<p>I would be lying to you if I did not tell you that there are some significant security risks associated with Exchange Impersonation, and they&#39;re a lot more insidious than you may realize. So instead of behaving like BP and pretending that the risks do not exist, I am going to go the other way and err on the side of caution.</p>
<p>Exchange Impersonation is a very powerful feature that allows you to build a server-side component that can perform any action on any mailbox on behalf of any user. Obviously, the Exchange Administrator can limit which mailboxes have the permission applied to them, but those that do can have actions performed on their behalf.</p>
<h4>The Exchange Web Services API is Secure</h4>
<p>Microsoft has done an admirable job of locking down Exchange Web Services so that it is very tightly controlled:</p>
<ul>
<li>You have to make an SSL connection;</li>
<li>You have to be authenticated against an Active Directory; and</li>
<li>By default you have to use NTLM V2 authentication.</li>
</ul>
<p>Moreover, you can add to this security level by requiring client-side certificates which make it almost impossible for a client that is not authentic to connect to the Exchange Web Service. So locking down Exchange Server is not where the problem lies.</p>
<h4>The Real Risk</h4>
<p>The problem lies in the application code that you build that connects to the Exchange Web Services API. If you don&#39;t build the same security into the connections to your code, you are opening the Exchange Server up to all kinds of risks. If you don&#39;t lock down your client connections to your application, there is nothing stopping anything from making changes to the server.&nbsp;</p>
<p>Think, for a minute, about how easy it has been to get soapUI to connect to the Java EWS WebService. If this was a production application, the security hole would be huge. Now think about the removing all the connection information and having to only provide the e-mail address of the account for which you wish to make the change. Suddenly, what was a very secure connection is open to all kinds of abuse.</p>
<p>This becomes even more serious as the solution becomes more service-oriented. The messages will now flow through a MOM where they are deliberately being exposed to other services for processing.</p>
<p>The reason I am making this point so strongly is that the examples I am going to include do nothing to protect the channel of communication. It is completely insecure, and that&#39;s fine in a development environment for now. The code that you are going to look at, though, has to be made far more secure and robust if it is going to be used in a production environment.&nbsp;</p>
<p>Now that you are well and truly scared of the risks that you could be creating (and if you are not, you should not be writing code), let&#39;s get things set up.</p>
<h3>Creating the Accounts</h3>
<p>Back in part 1 of this series, I told you that I had 4 user accounts that I would be using:</p>
<ul>
<li>Freddie F. Frogg (froggf@example.com)</li>
<li>Harriet H. Hippo (hippoh@example.com)</li>
<li>Edward E. Elifant (elifante@example.com)</li>
<li>Gerald G. Gerarf (gerarfg@example.com)</li>
</ul>
<p>These 4 users are all sales people who sell safari tours, in my fictitious test company, so I have added them to the <em>Sales</em>&nbsp;user group.</p>
<h4>User Accounts, AD Accounts, and Mailbox Accounts</h4>
<p>So that we are using a common set of terms, I am going to call these the user accounts. There&#39;s a subtlety here, though, that I need to make sure you understand: Freddie F Frogg has two accounts that we care about:</p>
<ol>
<li>His Active Directory account that gives him permission to logon to the domain. I&#39;m going to refer to this as his <em>Active Directory Account (or AD Account)</em>; and</li>
<li>His Exchange Server Mailbox that is used to pick up e-mail and change his calendar. I&#39;m going to refer to this as his <em>Mailbox Account</em>.</li>
</ol>
<p>The AD account has to have access rights to a corresponding Mailbox account in order to receive mail, etc, but an AD account can exist without a corresponding Mailbox account. The four accounts that I mentioned above are created in the Active Directory and then a corresponding mailbox is created for them on the Exchange Server. This is standard Exchange Administration.</p>
<p>So these four user accounts consist of an AD account and a Mailbox account.</p>
<h4>The Service Account</h4>
<p>As I described earlier on, we&#39;re going to create an account called <em>ewsproxy </em>that will act on behalf of the four user accounts. I&#39;m going to refer to this as the Service Account because it is used by the service that we have built to act on behalf of the user account.&nbsp;</p>
<p>The service account does not need to have a mailbox account. Instead, it only has an AD account.</p>
<p>So what we are going to do is create the Service account and then set some permissions on both the service and the user accounts that will allow the service account to act on behalf of the user accounts.</p>
<hr />
<p><strong>My Configuration</strong></p>
<p>Just so you have a point of reference, I am running two versions of Exchange &#8211; Exchange 2010 and Exchange 2007 SP3.</p>
<p>The Exchange 2010 server is running on a Windows 2008 R2 machine.</p>
<p>The Exchange 2007 server is running on a Windows 2008 SP2 machine.</p>
<p>In both cases, the Active Directory is running on a Windows 2008 R2 domain controller.</p>
<p>I am going to be using command line utilities to get things set up for Exchange Impersonation, and you may find that if you are doing things on a different combination of operating system and Exchange server, that things look or are slightly different. Consult the documentation for your combination and hopefully the differences are not too big.</p>
<hr />
<h4>Adding the AD Account for the Service Account</h4>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_AddUser.jpg" target="_blank"><img align="left" alt="Creating the User Account" height="252" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_AddUser.jpg" width="300" /></a>There is really nothing special about adding the AD account for the Service Account. It is simply a normal user in the domain.&nbsp;</p>
<p>Log on to the Active Directory server and simply add an account with whatever username you want to add.<a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_AddUser2.jpg" target="_blank"><img align="right" alt="Setting the Service Account password" height="252" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_AddUser2.jpg" width="300" /></a></p>
<p>On the next page of the wizard, you are prompted for the password for this account. It&#39;s important to make this a tough password and it&#39;s also probably worthwhile setting the <em>Password never expires flag</em>, as this is intended to be a service account, and changing the password will affect the service as well.</p>
<p>My knowledge of Active Directory is not good enough to unequivocally say this, but I am fairly confident that you could create a policy that would prevent the user from being able to log in interactively. I know you can restrict a user to only log in from certain machines. I will be researching that a little later in the development process, but for now, creating a regular user account will have to do.</p>
<h3>Applying Permissions</h3>
<p>So far, there is no difference between working with Exchange Server 2007 and Exchange Server 2010, but here is where the two releases of the product diverge, and I have to say that I am very glad they do, because there is a marked improvement in the design of the 2010 release over the 2007 release in this area.&nbsp;</p>
<p>Exchange Server 2007 makes use of Access Control Lists (ACL) to apply the permissions. You apply two rights; one that authorizes the Service Account access to Exchange Impersonation rights on the Client Access Server (CAS), and the other that is applied to either an AD account or an entire Mailbox database. This is somewhat kludgey because you either do it on an account-by-account basis, or you do it on an entire mailbox database.</p>
<p>Exchange Server 2010 allows a much finer-grained control of the application of permissions because it makes use of Role-Based Access Control (RBAC) to apply the permissions. Instead of applying the tokens to an account or a mailbox database, you can define a scope to which the permission applies. This means that you can get all the users in a group, for example, and set the permission for that scope.&nbsp;</p>
<p>So let&#39;s deal with applying these permissions to each of the server versions, one by one.</p>
<h4>Applying Exchange Impersonation Permissions on <em><strong>Exchange Server 2007</strong></em></h4>
<p>As I mentioned, Exchange 2007 requires that you apply two rights to be able to get Exchange Impersonation working:</p>
<ul>
<li><strong>ms-Exch-EPI-Impersonation</strong> &#8211; This right is applied to the Client Access Server and grants the Service Account permission to function as an Exchange Impersonation account on that CAS.</li>
<li><strong>ms-Exch-EPI-May-Impersonate</strong> &#8211; This right is applied on either a user-by-user basis for each of the users that require impersonation to be enabled, or it can be applied on a mailbox database.</li>
</ul>
<p>The first step is to make sure we have the right setting for the Client Access Server. I have reached the point with Exchange where I do most of my administration from the command line rather than the GUI. I find it much easier to do for a number of things, especially setting permissions. So I am going to give you the command line way to do this. You can do it from the GUI if you stand on your head while juggling balls, whistling the national anthem, and playing a guitar, but that is not my idea of fun. The command line is much easier. I guess that&#39;s what comes of being a Unix geek.</p>
<p>With the release of Exchange Server 2007, Microsoft released the Exchange Management Shell (or Powershell) that allows you to perform most administration functions from the command line. To set the Impersonation permission on your Client Access Server, log on to your Exchange Server machine, and launch the Exchange Management Shell from the Microsoft Exchange Server 2007 program group in the Start menu. At the command line, type the following command (replacing <em>intangereexs</em> with your own CAS and <em>EWS Proxy</em> with the name of your own Service Account):</p>
<pre>Add-ADPermission -Identity (Get-ExchangeServer -Identity intangereexs).DistinguishedName
  -User (Get-User -Identity &quot;EWS Proxy&quot;).Identity
  -extendedRight ms-Exch-EPI-Impersonation
</pre>
<p>Note that the identity of the Client Access Server is the name of the machine that hosts it, and the identity of the user is the full name of the user. If you don&#39;t know what the user&#39;s full name is, you can type <em>Get-User</em> at the command line, and you will get a list of all the known user names.</p>
<p>If the command succeeds, you should see a message similar to that at the bottom of the window below:</p>
<p><img alt="Setting Impersonation CAS Permissions" height="332" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_SettingCASPerms_2007.jpg" width="669" /></p>
<p>The next step is to set the permissions on each user for which we want to enable Exchange Impersonation. Again, from the command line, we will use the <em>Add-ADPermission</em> commandlet, except this time we are adding the right to the user, not the CAS server. Below are the 4 commands that I used to set these permissions.</p>
<pre>Add-ADPermission -Identity (Get-User -Identity &quot;Freddie F. Frogg&quot;).DistinguishedName
  -User (Get-User -Identity &quot;EWS Proxy&quot;).Identity
  -extendedRight ms-Exch-EPI-May-Impersonate

Add-ADPermission -Identity (Get-User -Identity &quot;Harriet H. Hippo&quot;).DistinguishedName
  -User (Get-User -Identity &quot;EWS Proxy&quot;).Identity
  -extendedRight ms-Exch-EPI-May-Impersonate

Add-ADPermission -Identity (Get-User -Identity &quot;Gerald G. Gerarf&quot;).DistinguishedName
  -User (Get-User -Identity &quot;EWS Proxy&quot;).Identity
  -extendedRight ms-Exch-EPI-May-Impersonate

Add-ADPermission -Identity (Get-User -Identity &quot;Edward E. Elifant&quot;).DistinguishedName
  -User (Get-User -Identity &quot;EWS Proxy&quot;).Identity
  -extendedRight ms-Exch-EPI-May-Impersonate</pre>
<p>Assuming you have set the permissions properly, your command window should look something like this:</p>
<p><img alt="Setting Impersonation User Account Permissions for Exchange 2007" height="331" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_SettingUserPerms_2007.jpg" width="668" /></p>
<p>That&#39;s all that is required to set up Exchange Impersonation for these four accounts and the Client Access Server for Exchange 2007. As I mentioned, you can set the ms-Exch-EPI-May-Impersonate permission on a mailbox store basis, but I would not advise doing that unless you have segregated your users in a way that makes sense for you to do this. The last thing you want is to give a service account permission to read a CEO&#39;s e-mail. That would be a serious CLM &#8211; Career Limiting Move.</p>
<h4>Applying Exchange Impersonation Permissions on <em><strong>Exchange Server 2010</strong></em></h4>
<p>Setting up Exchange Impersonation for Exchange Server 2010 is a lot easier than it is for Exchange Server 2007. The Roll-Based Access Control mechanism allows you to define groups of users and assign those groups of users the ApplicationImpersonation role. Once that is done, any new users that are added to the group are automatically assigned the ApplicationImpersonation permission.</p>
<h5>Management Scope</h5>
<p>I have used the term &quot;group&quot; here somewhat confusingly, and I&#39;m going to perpetuate that confusion by using a security group as the basis for defining the permission, but that is not the only way to do this. The ApplicationImpersonation role has to be assigned to a <em>ManagementScope. </em></p>
<p>So what is a ManagementScope? A <em>ManagementScope</em>&nbsp;is a logical group of users that are defined by a common set of criteria. It is not necessarily an Active Directory Security Group, although, for the purposes of our example, I will be using a security group to define it. You can define the scope to consist of users who meet a certain criteria, such as having a common manager.</p>
<p>You define a ManagementScope by using the <em>New-ManagementScope</em> commandlet. The <em>RecipientRestrictionFilter</em> parameter allows you to define the criteria that select a list of users. In this case, I am looking for all users that are members of the Sales security group (fully qualified:&nbsp;<em>gruenbaums.internal.intangere.com/Users/Sales</em>). The following command creates a management scope that will only include members of that group.&nbsp;</p>
<pre>New-ManagementScope -Name:&quot;SalesImpersonation&quot;
        -RecipientRestrictionFilter {memberofgroup -eq
        &quot;cn=Sales,cn=Users,DC=gruenbaums,DC=internal,DC=intangere,DC=com&quot;}</pre>
<p>The string at the end of the command line is a Distinguished Name string from the Active Directory that represents the <em>Sales</em> security group. There are a number of different filters that can be applied to create a management scope. The nice thing about this one is that if I add or remove a user to the Sales security group, the scope defined here will ensure that the permissions for the user are affected accordingly.</p>
<h5>Role Assignment</h5>
<p>Once the management scope exists, one or more management roles can be applied to the management scope. In this case, I am going to assign the <em>ApplicationImpersonation</em> role for the <em>ewsproxy</em> user to the management scope that I just created, and I am going to call the role <em>SalesImpersonation</em>.&nbsp;</p>
<pre>New-ManagementRoleAssignment -Name:&quot;SalesImpersonation&quot;
         -Role:ApplicationImpersonation
         -User:&quot;ewsproxy@gruenbaums.internal.intangere.com&quot;
         -CustomRecipientWriteScope:&quot;SalesImpersonation&quot;</pre>
<p>Just to confuse the issue, I called my scope&nbsp;<em>SalesImpersonation,</em>&nbsp;too. So in the command line above, the first occurrence of SalesImpersonation refers to the name of the management role assignment that is being created whereas the second one refers to the name of the management scope that was created in the previous step.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_SettingUserPerms_2010.jpg" target="_blank"><img alt="Setting Impersonation Permissions in Exchange 2010" height="287" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_SettingUserPerms_2010.jpg" width="801" /></a></p>
<p>Now that the impersonation permissions have been set on both machines, we are ready to start testing.</p>
<h3>The Sample Code</h3>
<p>The source code for this article only contains Java code, and all the testing for this is through soapUI.&nbsp;The code contains a completely new version of the EWSAPI example in part 2, so you need to create a new Eclipse workspace in which to set it up.</p>
<p>By now, I am assuming you have worked through <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/">part 1</a> and <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/">part 2</a> of this series and are going to be okay with setting up your environment. If not, you should go <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/#codesetup">back to part 2 and read the section on code setup</a>. You can <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/tsgewsexample_3.zip">download the source code</a>&nbsp;for this article and set it up by following the instructions in part 2.&nbsp;From the standpoint of the client application, this is not difficult to do. Most of the problems are related to the set up of the impersonation permissions.&nbsp;</p>
<h4>What&#39;s New?</h4>
<p>The code that you will be looking at is very similar to the code for part 2. The first difference is that the namespaces for all of these objects have changed because I messed up and only realized it as I was building the code for this article. Instead of the <em>org.tsg.ews</em>&nbsp;workspace, all the code now sits in the <em>com.tsg.ews</em>&nbsp;workspace.</p>
<p>The following code is new:</p>
<ul>
<li><strong>EWSImpersonationCalendar.java</strong> &#8211; This class, in the <em>com.tsg.ews</em> package, contains the definition of the new CalendarService WebService. It performs the same functions as the AppointmentService in part 2, but it does so using Exchange Impersonation.</li>
<li><strong>ExchangeServer.java</strong> &#8211; This class, in the <em>com.tsg.ews.service</em> package, is a descriptor for an Exchange Server and contains the server name and the Server Account authentication credentials.</li>
<li><strong>ServerList.java</strong> &#8211; This class, in the <em>com.tsg.ews.service</em> package,&nbsp;allows for the registration of more than one Exchange Server. I&#39;m really using this class to handle the persistence of the server list to an XML file, but I wrote it while I was experimenting with JAXB so I am not going to spend a lot of time covering the details.</li>
</ul>
<p>The following code has changed:</p>
<ul>
<li><strong>ExchangeService.java</strong> &#8211; This class,&nbsp;in the <em>com.tsg.ews.service</em> package, has been changed to support server registration so that a server can be re-used and only the e-mail address of the User Account has to be supplied to operate on their mailbox.</li>
<li><strong>EWSResponse.java</strong> &#8211; This class, in the <em>com.tsg.ews.service</em> package, has been changed to handle receiving the SOAP fault messages that can be returned in response to call to the Exchange Web Service. It provides more detailed information about failures and can help diagnose why a call to the server failed. This is especially important when you are trying to get the permissions right.</li>
</ul>
<p>So now that you know what is new and what has changed, let&#39;s walk through the code and understand what is going on.</p>
<h4>EWSImpersonationCalendar</h4>
<p>Open EWSImpersonationCalendar.java, and scroll down to line 16. This class is very similar to EWSCalendar.java, but there are a couple of very small changes.</p>
<h5><a name="registerserver"></a>RegisterServer</h5>
<p>Line 16 through 23 define a new operation, <em>RegisterServer</em>, that did not exist in part 2. The operation takes the name of the Exchange Client Access Server, the domain name, a user name and a password. We will use this operation to register the server name and its associated Service Account.</p>
<pre>@WebMethod(operationName = &quot;RegisterServer&quot;)
@WebResult(name = &quot;RegisterServerResponse&quot;)
public EWSResponse setServer(@WebParam(name = &quot;ExchangeServer&quot;) String hostName,
		@WebParam(name = &quot;Domain&quot;) String domain,
		@WebParam(name = &quot;User&quot;) String username,
		@WebParam(name = &quot;Password&quot;) String passwd) {
	return ExchangeService.registerServer(hostName, domain, username, passwd);
}
</pre>
<p>Line 22 makes a call to <em>ExchangeService.registerServer</em>, which &nbsp;simply creates an <em>ExchangeServer</em> object and stores it in the <em>ServerList</em>. When an ExchangeServer object is instantiated, it is assigned a UUID, which is returned as a string from the <em>registerServer</em> method call. This UUID, which is returned as a ServerID, is used in later calls.</p>
<p>I&#39;m not going to spend a lot of time discussing the internal workings of <em>registerServer</em>. When I wrote the code, I was experimenting with JAXB, so there is some stuff that needs to be cleaned up, but it does what I need it to do reasonably well.</p>
<h5>CreateAppointment</h5>
<p>Lines 27 through 49 define the CreateAppointment operation, which is carried over from EWSCalendar. The difference lies in the first two parameters to this operation:</p>
<ul>
<li>The <em>ServerID</em> parameter is the ServerID that was received in response to a previous <em>RegisterServer</em> call.</li>
<li>The <em>UserAccount</em> parameter is the e-mail address of the UserAccount for which the appointment is to be created.</li>
</ul>
<pre>@WebMethod(operationName = &quot;CreateAppointment&quot;)
@WebResult(name = &quot;Response&quot;)
public EWSResponse createAppointment(@WebParam(name = &quot;ServerID&quot;) String serverID,
		@WebParam(name = &quot;UserAccount&quot;) String account,
		@WebParam(name = &quot;Description&quot;) String description,
		@WebParam(name = &quot;Location&quot;) String location,
		@WebParam(name = &quot;StartDateTime&quot;) GregorianCalendar startDate,
		@WebParam(name = &quot;EndDateTime&quot;) GregorianCalendar endDate,
		@WebParam(name = &quot;Notes&quot;) String notes,
		@WebParam(name = &quot;SetReminder&quot;) boolean reminder,
		@WebParam(name = &quot;ReminderMinutes&quot;) int minutes) {
	ExchangeService srvc = new ExchangeService(serverID);
	Appointment appt = new Appointment(srvc);
	appt.setEmailAddress(account);
	appt.setDescription(description);
	appt.setLocation(location);
	appt.setStartDate(startDate);
	appt.setEndDate(endDate);
	appt.setNotes(notes);
	appt.setReminder(reminder);
	appt.setReminderMinutes(minutes);
	EWSResponse resp = appt.create();
	return resp;
}
</pre>
<p>In line 36, we instantiate a new ExchangeService object, just as we did in line 31 of EWSCalendar, except that this time we are passing in the ServiceID. The ExchangeService object will handle communication with the Exchange Server and in a commercial application, this would really be a pool.</p>
<p>The only other line of code that is different in this code is line 38, where we call <em>setEmailAddress</em> on the Appointment object. The way that I have implemented this code, that e-mail address is the User Account of the calendar in which we will create the calendar item.</p>
<hr />
<p>Note that were this not code that was already written as a prototype, I would probably do things slightly differently with the object model. Using the e-mail address as an indicator for whether or not to use impersonation is probably not the best idea, but as I said in my previous posts, this is more about showing how to use the technology than it is about where things fit in object models.</p>
<hr />
<h5>GetAppointment and DeleteAppointment</h5>
<p>Like CreateAppointment, the only changes to the GetAppointment and DeleteAppointment operations are that we are passing in the ServerID and the e-mail account, and using them to identify the Exchange Server and User Account for which the appointment is to be retrieved.</p>
<h4>So where does the work get done?</h4>
<p>Right now, you are probably wondering what it is that causes Exchange to behave differently. Nothing in the code that I have shown you really changes the way we communicate with Exchange Server.&nbsp;</p>
<p>The &quot;work&quot; happens in the construction of the SOAP request that will be sent to the Exchange Server, which actually takes place in the <em>SOAPRequest</em> class which is instantiated in <em>Appointment.create()</em>, <em>Appointment.retrieve()</em>, and <em>Appointment.delete(), </em>just before the call to <em>ExchangeService.makeRequest()</em>. We walked through this area of the code in part 2, so I am not going to rehash the instantiation of SOAPRequest, but the following code is extracted from <em>Appointment.create()</em>, lines 322 and 323:</p>
<pre>SOAPRequest req = new SOAPRequest(request.toString(), emailAddress);
EWSResponse retVal = service.makeRequest(req);
</pre>
<p>Note that when we instantiate the SOAPRequest, we are passing in the emailAddress (which may be null) to the constructor, and then we pass the SOAPRequest object into the makeRequest call on the ExchangeService.</p>
<p>Open <em>SOAPRequest.java</em> in the <em>com.tsg.ews.service </em>package and scroll to the <em>getMessage</em> method in line 23:</p>
<pre>String getMessage() {
    StringBuilder builder = new StringBuilder();
    builder.append(&quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;utf-8\&quot;?&gt;\n&quot;);
    builder.append(String.format(&quot;&lt;soap:Envelope xmlns:xsi=\&quot;%1$s\&quot;\n&quot;,XSI_URI));
    builder.append(String.format(&quot;               xmlns:xsd=\&quot;%1$s\&quot;\n&quot;,XSD_URI));
    builder.append(String.format(&quot;               xmlns:soap=\&quot;%1$s\&quot;\n&quot;,SOAP_URI));
    builder.append(String.format(&quot;               xmlns=\&quot;%1$s\&quot;\n&quot;,MESSAGES_URI));
    builder.append(String.format(&quot;               xmlns:t=\&quot;%1$s\&quot;&gt;\n&quot;,TYPES_URI));
    builder.append(&quot;    &lt;soap:Header&gt;\n&quot;);
    if (emailAddress != null) {
    	builder.append(getImpersonation());
    }
    builder.append(&quot;    &lt;/soap:Header&gt;\n&quot;);
	builder.append(&quot;&lt;soap:Body&gt;\n&quot;);
	builder.append(soapBody);
	builder.append(&quot;&lt;/soap:Body&gt;\n&quot;);
	builder.append(&quot;&lt;/soap:Envelope&gt;\n&quot;);
    return builder.toString();
}
</pre>
<p>This code builds the SOAP message that will be sent to the Exchange WebService and the important piece is in lines 32 through 34 where, if the <em>emailAddress</em> is not null, we append the results of a call to <em>getImpersonation().</em></p>
<p>The <em>getImpersonation()</em> method is in lines 43 through 53:</p>
<pre>private String getImpersonation() {
    StringBuilder builder = new StringBuilder();
    builder.append(&quot;        &lt;t:ExchangeImpersonation&gt;\n&quot;);
    builder.append(&quot;            &lt;t:ConnectingSID&gt;\n&quot;);
    builder.append(&quot;                &lt;t:PrimarySmtpAddress&gt;&quot;);
    builder.append(emailAddress);
    builder.append(&quot;&lt;/t:PrimarySmtpAddress&gt;\n&quot;);
    builder.append(&quot;            &lt;/t:ConnectingSID&gt;\n&quot;);
    builder.append(&quot;        &lt;/t:ExchangeImpersonation&gt;\n&quot;);
    return builder.toString();
}
</pre>
<p>The code in <em>getImpersonation</em> builds an <em>ExchangeImpersonation</em> node that contains a <em>ConnectingSID</em> node. This node specifies the User Account on behalf of which the action is being performed. There are three ways of identifying the account to be used:</p>
<ul>
<li>Principal Name &#8211; The User Principal Name for the account and it is in the format of an e-mail address. I could have used it as the node name in this call, but I have a reason for using the Primary SMTP Address which I will mention later. This, and the SID are the most efficient authentication mechanisms as they only need to communicate with the Active Directory once.</li>
<li>SID &#8211; This is the security identifier for a user. SIDs are a string of numbers that have a meaning to Active Directory and Windows, but really don&#39;t mean a whole lot to anyone else and are pretty difficult to know if you are coming from a Unix-based server system.</li>
<li>Primary SMTP Address &#8211; Each Active Directory account has a primary SMTP address associated with it and this address can be used to authenticate the user. The problem with the primary SMTP address is that it results in two calls to the Active Directory and this is somewhat inefficient. The reason that I chose to use it is that it is often true that the primary SMTP address and the PrincipalName are different, and the primary SMTP address is normally the one used by an employee on his business card, and therefore likely to be in the CRM application.</li>
</ul>
<p>The upshot of this is that the header for the message now contains an <em>ExchangeImpersonation</em> node that will be read by the Exchange Web Service. This node contains a User Account and Exchange will perform the action on that user&#39;s behalf, even though the login used to connect to the Exchange Server was the Service Account (ewsproxy, in this case).</p>
<p>The full SOAP message for a CreateItem operation call to create a CalendarItem using Exchange Impersonation therefore looks something like this:</p>
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;soap:Envelope xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
               xmlns:xsd=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;
               xmlns:soap=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;
               xmlns=&quot;http://schemas.microsoft.com/exchange/services/2006/messages&quot;
               xmlns:t=&quot;http://schemas.microsoft.com/exchange/services/2006/types&quot;&gt;
    &lt;soap:Header&gt;
        &lt;t:ExchangeImpersonation&gt;
            &lt;t:ConnectingSID&gt;
                &lt;t:PrimarySmtpAddress&gt;hippoh@intangere.internal.intangere.com&lt;/t:PrimarySmtpAddress&gt;
            &lt;/t:ConnectingSID&gt;
        &lt;/t:ExchangeImpersonation&gt;
    &lt;/soap:Header&gt;
    &lt;soap:Body&gt;
	&lt;CreateItem
		SendMeetingInvitations=&quot;SendToNone&quot;
		xmlns=&quot;http://schemas.microsoft.com/exchange/services/2006/messages&quot;
		xmlns:t=&quot;http://schemas.microsoft.com/exchange/services/2006/types&quot;&gt;
	    &lt;Items&gt;
	        &lt;t:CalendarItem&gt;
	            &lt;t:Subject&gt;Test Appointment&lt;/t:Subject&gt;
	            &lt;t:Body BodyType=&quot;Text&quot;&gt;Something or anothar&lt;/t:Body&gt;
	            &lt;t:ReminderIsSet&gt;true&lt;/t:ReminderIsSet&gt;
	            &lt;t:ReminderMinutesBeforeStart&gt;10&lt;/t:ReminderMinutesBeforeStart&gt;
	            &lt;t:Start&gt;2010-06-28T17:50:00.000-07:00&lt;/t:Start&gt;
	            &lt;t:End&gt;2010-06-28T18:30:00.000-07:00&lt;/t:End&gt;
	            &lt;t:Location&gt;Whereever&lt;/t:Location&gt;
	        &lt;/t:CalendarItem&gt;
	    &lt;/Items&gt;
	&lt;/CreateItem&gt;
    &lt;/soap:Body&gt;
&lt;/soap:Envelope&gt;
</pre>
<h3>Exchange Impersonation in Action</h3>
<p>Let&#39;s now take a look at how this works in practice. The first thing to do is open Eclipse and make sure you have the code built and running on your Glassfish server. The instructions in Part 2 on getting this code running should work for you.&nbsp;</p>
<p>Now that your server is running, open soapUI and create a new project. In the <em>Initial WSDL/ASDL</em> field, type the following URL:</p>
<pre>http://localhost:8080/EWSAPI/CalendarService?wsdl
</pre>
<h4>The RegisterServer Call</h4>
<p>When you choose the OK button, a new project called <em>CalendarService</em> will be created. Expand the nodes until you can see the <em>RegisterServer</em> node.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_RegisterServer.jpg" target="_blank"><img alt="Register Server call" height="500" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_RegisterServer.jpg" width="800" /></a></p>
<p>With RegisterServer, all you are doing is setting up the parameters for the server machine you want to connect to and you need to provide the username, password and domain for the Service Account you created &#8211; in my case, ewsproxy. When the call completes, the SOAP message that is returned contains an ErrorState attribute that should be &quot;NoError&quot;. It also contains a <em>responseMessage </em>attribute that contains a hex string that is the UUID for the server that you just registered. This string is the value for the <em>StringID </em>element in the CreateAppointment call that we will make next.</p>
<h4>The CreateAppointment Call</h4>
<p>The CreateAppointment call will create a calendar item in the User Account&#39;s mailbox.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_CreateAppointment.jpg" target="_blank"><img alt="Create Appointment Call" height="500" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/Part3_CreateAppointment.jpg" width="800" /></a></p>
<p>This time, you are going to copy the string that was returned in the response to the <em>RegisterServer</em> call above into the <em>ServerID</em> element. In the <em>UserAccount</em> element, you need to supply the e-mail address of the User Account in whose calendar you want to create the appointment. Complete the rest of the fields per the example in Part 2. When you run this call, you will receive a ChangeKey and an ItemID in the response if it succeeded, and the appointment will be created in the user&#39;s calendar.</p>
<p>Now go and change the e-mail address in the <em>UserAccount</em> element to another User Account for which you have enabled impersonation. &nbsp;Again, you should get a ChangeKey and ItemID in the response, in which case all is good.</p>
<p>Note that you did not have to provide any credentials for either the first or second CreateAppointment calls. They just worked. Scary thought. Without any special permission, you have been able to create appointments in someone else&#39;s calendar. That&#39;s why I said that although this is powerful functionality, if you don&#39;t secure it properly, it has the potential for significant security risks.</p>
<h4>Likely Exception</h4>
<p>It is possible that you will hit an Impersonation error along the way. I have seen this error so many times, it is scary:&nbsp;</p>
<pre>&lt;S:Envelope xmlns:S=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&gt;
   &lt;S:Body&gt;
      &lt;ns2:CreateAppointmentResponse xmlns:ns2=&quot;http://ews.tsg.com/&quot;&gt;
         &lt;Response ErrorState=&quot;EWSError&quot;
		responseCode=&quot;ErrorImpersonateUserDenied&quot;
		responseMessage=&quot;The account does not have permission to impersonate the requested user.&quot;/&gt;
      &lt;/ns2:CreateAppointmentResponse&gt;
   &lt;/S:Body&gt;
&lt;/S:Envelope&gt;
</pre>
<p>The problem is that the description that I provided above on how to configure impersonation generally works pretty well. But if you are trying to figure out some special criteria for Exchange 2010 in the&nbsp;<em>-RecipientRestrictionFilter&nbsp;</em>parameter when you allocate permissions for impersonation, you can spend hours getting this message, trying to figure out why. Unfortunately, I can&#39;t offer too much advice other than to consult the documentation for the PowerShell add-ins for Exchange Server which are available in the Exchange Server SDK.&nbsp;</p>
<h3>In Summary</h3>
<p>I have tried to present a fairly extensive example of using Exchange Impersonation. I&#39;ve also tried to make sure you understand that you, as a developer, can transform a secure Microsoft Exchange Server into a pretty big security hole by using Exchange Impersonation without paying attention to security.</p>
<p>There is no doubt that for serious S2S applications that need to interact with an Exchange Server, Exchange Impersonation is incredibly valuable. Just make sure you use it carefully.</p>
<p>Part 4 of this series will discuss the Subscription API and I will provide a working example that shows how to use the Push subscription API.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2010/06/exchange-web-services-example-part-3-exchange-impersonation/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>OpenEdge GUI for .NET &#8211; Testing the Bridge</title>
		<link>http://www.thesoftwaregorilla.com/2010/06/openedge-gui-for-net-testing-the-bridge/</link>
		<comments>http://www.thesoftwaregorilla.com/2010/06/openedge-gui-for-net-testing-the-bridge/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 03:25:12 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Exchange Web Services]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[OpenEdge GUI for .NET]]></category>
		<category><![CDATA[4GL]]></category>
		<category><![CDATA[ABL]]></category>
		<category><![CDATA[EWS]]></category>
		<category><![CDATA[Exchange EWS]]></category>
		<category><![CDATA[Progress]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=922</guid>
		<description><![CDATA[Progress Software Corporation has been running a program to test the OpenEdge GUI for .NET bridge with controls that have no user-interface. My company, Intangere, is very interested in this program because we are looking at releasing a control that would make it possible for OpenEdge developers to communicate directly with a Microsoft Exchange Server and receive mailbox updates for an OpenEdge client. 

Intangere thus signed up for the program and created a control that mimics the behavior of a real Exchange Web Services control. This test has been surprisingly successful, and this article provides some information about the test and the code and a document that describes its use.]]></description>
			<content:encoded><![CDATA[<p>With the Exchange Web Services project, I have found a lot of .NET example code that makes connecting to Exchange&nbsp;from .NET&nbsp;a breeze. It&#39;s orders of magnitude easier than from Java, and that&#39;s to be expected &#8211; Microsoft&#39;s primary focus is on Microsoft. I do, however, want to make it as easy as possible for people to integrate Exchange into their applications, and from a UI point of view, the easiest way to do this is through .NET.</p>
<p>Providing a .NET control that facilitates this as Open Source is definitely on the to-do list for the Exchange Web Services project, but I was not sure how I would do this for OpenEdge as non-UI controls are not supported and most of the work that the control does is communication with the Exchange Web Service in a multi-threaded configuration on background threads.&nbsp;</p>
<p>On <a href="http://communities.progress.com/pcom/thread/26605?tstart=0" target="_blank">May 5th, Progress temporarily raised the restriction</a>&nbsp;to test the OpenEdge GUI for .NET bridge with controls that have no user-interface&nbsp;so that users can experiment with the controls and determine what types of controls should be supported.&nbsp;My company, Intangere, thus signed up for the program and created a control that mimics the behavior of a proposed Exchange Web Services control. This test has been surprisingly successful, and this article provides some information about the test and&nbsp;<a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/NonUIControlTests.zip" target="_blank">the code and a document that describes its use</a>.</p>
<h3>Architecture</h3>
<p>Progress would have had logistical issues incorporating an Exchange Web Server into their nightly build simply to test the background functionality that this control will provide. To test the functionality, therefore, I needed to provide Progress with an example that replicates the functionality that I expect to use in the Exchange Web Services architecture.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/EWSEmulator.jpg" target="_blank"><img align="left" alt="EWSEmulator conceptual architecture" height="255" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/EWSEmulator.jpg" width="450" /></a> The model at left graphically demonstrates how the architecture of <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/NonUIControlTests.zip">the code</a> works. The model closely mimics the <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" target="_blank">model for the Subscription and Notification API</a> that &nbsp;I discussed in the <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/" target="_blank">Exchange Web Services &#8211; Subscriptions and Notifications</a> post that I wrote back on April 26th.</p>
<p>Starting from the right of the diagram, Listener.exe is intended to emulate the functions that are performed by the Microsoft Exchange Web Services API. Specifically, it supports registering subscriptions and notifying the client of &quot;updates&quot; on a background thread. All communication between the client and Listener.exe is by means of .NET objects serialized as XML.&nbsp;</p>
<p>The EWSEmulator Control is a .NET control that has no user interface and performs the function <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" target="_blank">that the Java EWS WebService and the Java HTTP Servlet perform</a>. As such, it is derived from System.ComponentModel.Component and it handles the job of communicating with Listener.exe, both in terms of posting subscription requests, and in terms of receiving notifications. The control receives the notifications on a background thread (the Notification Processor) which deserializes the objects and hands them to the event generator which raises a .NET event <em>on the UI thread.</em></p>
<p>Receiving the event on the UI thread is one of the most critical components of this control. OpenEdge is single-threaded which means that if an event is raised on anything but the UI thread, it is likely to cause problems for OpenEdge. So the Event Generator&#39;s sole function is to marshal all notifications and generate a .NET event on the UI thread.</p>
<p>The User Interface Logic is responsible for registering subscriptions via the embedded EWSEmulator Control, shutting down the Listener service and reacting to events raised by the Event Generator.</p>
<h3>So how did the test go?</h3>
<p><img align="left" alt="EWSEmulator User Interface" height="421" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/EWSEmulatorUI.jpg" width="519" />I&#39;m not going to spend a lot of time telling you about the gory details of the code. You can&nbsp;<a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/06/NonUIControlTests.zip">download the code and a document</a>&nbsp;that describes a lot more about my experience and findings, and you can even run it and look at both the ABL and .NET code. The document is a PDF contained in the zip file.&nbsp;</p>
<p>In a nutshell, though, I was able to duplicate the behavior I was looking for, marshal the events onto the UI thread, and get OpenEdge to react to those events without too much trouble. Section 4.2.2 of the document provides a description of how the marshaling works.</p>
<p>More importantly, I was also able to establish that the volume of data that can be handled by the OpenEdge ABL in this kind of communication was significantly greater than I had thought. I was able to generate upwards of 400 messages per second from Listener.exe and the client handled them without losing any.</p>
<p>Of course, no one in their right mind would expect the client to handle that volume of traffic, especially considering that every event had to be marshaled to the UI thread. But it was encouraging to learn that it was possible.</p>
<h3>My Conclusion</h3>
<p>What this test has proven is that the OpenEdge GUI for .NET is more than capable of supporting background controls, provided they conform to the rule that all threads need to be marshaled to the UI thread before an event is raised.</p>
<p>Also, I made extensive use of the XmlSerializer, HttpListener, HttpWebResponse, and several other streaming classes and had no problem at all with OpenEdge.&nbsp;</p>
<p>I have submitted this code and these findings to Progress Software and hopefully they will be able to lift the restriction on use of non-UI controls with OpenEdge GUI for .NET.</p>
<p>Feel free to download the example code and documentation and mess with it, and please let me have your feedback.</p>
<p>Also note that <a href="http://communities.progress.com/pcom/thread/29062?tstart=0" target="_blank">the program with Progress to test the bridge</a> for non-UI controls is open until July 31st, so if you can <a href="mailto:TestingTheBridge@progress.com?subject=I'd%20like%20to%20test%20the%20bridge!">join the program</a> and contribute, please do.&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2010/06/openedge-gui-for-net-testing-the-bridge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exchange Web Services Example &#8211; Part 2 &#8211; Creating Appointments</title>
		<link>http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/</link>
		<comments>http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/#comments</comments>
		<pubDate>Wed, 26 May 2010 07:13:31 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Exchange Web Services]]></category>
		<category><![CDATA[Exchange Web Services Example]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[OpenClient]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[OpenEdge AppServer]]></category>
		<category><![CDATA[4GL]]></category>
		<category><![CDATA[ABL]]></category>
		<category><![CDATA[EWS]]></category>
		<category><![CDATA[Exchange 2007]]></category>
		<category><![CDATA[Exchange 2010]]></category>
		<category><![CDATA[Exchange EWS]]></category>
		<category><![CDATA[Exchange Server 2007]]></category>
		<category><![CDATA[Exchange Server 2010]]></category>
		<category><![CDATA[Java 6]]></category>
		<category><![CDATA[Java EE 6]]></category>
		<category><![CDATA[Microsoft Exchange 2007]]></category>
		<category><![CDATA[Microsoft Exchange 2010]]></category>
		<category><![CDATA[Sample Code]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=759</guid>
		<description><![CDATA[In part 2 of this series, we are going to spend some time looking at the CalendarItem API, how it works and what it takes to create, get and delete an appointment. Before we start, you should make sure you have your environment set up per the explanation in part 1. If you have done that, you can download the example code for both the Java portion and the OpenEdge portion so you can follow along as we walk through this code together. 

Part 2 of this series of articles is dedicated to giving you an overview of the process of connecting to Exchange and doing some basic Calendar item work. Through the sample code, you will learn how to:
 - Connect to the Exchange Web Service from Java;
 - Create calendar items on the Exchange Server;
 - Get calendar items from the Exchange Server;
 - Delete calendar items from the Exchange Server; and
 - Connect to the Java service from OpenEdge to perform the same operations.

The Java functionality will be exposed as a Web Service so that other platforms can also leverage, which is how we will get at it from OpenEdge. The OpenEdge code leverages the new GUI for .NET and object-oriented extensions, so you may find the example interesting if you have not done this before. [...]]]></description>
			<content:encoded><![CDATA[<p>In part 2 of this series, we are going to spend some time looking at the CalendarItem API, how it works and what it takes to create, get and delete an appointment. Before we start, you should make sure you have your environment set up per <a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/">the explanation in part 1</a>. If you have done that, you can <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/tsgewsexample_2.zip">download the example code for both the Java portion and the OpenEdge</a> portion so you can follow along as we walk through this code together.</p>
<h3>Goals and Background</h3>
<p>Part 2 of this series of articles is dedicated to giving you an overview of the process of connecting to Exchange and doing some basic Calendar item work. Through <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/tsgewsexample_2.zip" target="_blank">the sample code</a>, you will learn how to:</p>
<ol>
<li>Connect to the Exchange Web Service from Java;</li>
<li>Create calendar items on the Exchange Server;</li>
<li>Get calendar items from the Exchange Server;</li>
<li>Delete calendar items from the Exchange Server; and</li>
<li>Connect to the Java service from OpenEdge to perform the same operations.</li>
</ol>
<p>The Java functionality will be exposed as a Web Service for other platforms to leverage, which is how we will get at it from OpenEdge. The OpenEdge code leverages the new GUI for .NET and object-oriented extensions, so you may find the example interesting if you are an OpenEdge developer who has not done this before.</p>
<p>One of the things that I have learned about integration through bitter, painful experience, is that it is much easier if you remove as many variables as possible, so, for the purposes of this exercise, I am only going to expose a few of the calendar properties. This helps to keep the code simple and this article reasonably short. I think I succeeded at the former, but the latter&#8230; not so much.</p>
<p>The code that you will be looking at is code that I wrote as part of my research into the EWS API and, as such, it is prototype code. What this means is that it is ugly. I have not spent a lot of time commenting it and it does not resemble the code that I would deploy to production from an object-model point of view. But that is OK. A prototype is intended to prove a concept.</p>
<p>There is nowhere that integration is harder than when you try and integrate Microsoft&#39;s technologies with a non-Microsoft platform. Microsoft seems to make it deliberately difficult.&nbsp;I have therefore deliberately hand-coded the SOAP messages that are used to communicate with Exchange in this example. I started out by trying to use Java frameworks like Axis 2 and JAX-WS for the SOAP piece, but I quickly ran into problems. So I decided that I would remove those variables and prove I could get the code working. Now that I am satisfied that I can do what I need to be able to do, I will go back and decide what I am going to do about integrating one of these frameworks into the mix.&nbsp;</p>
<p>Another important factor that I should point out about this prototype is that I plan to integrate this whole solution with an Enterprise Service Bus (specifically, Apache ServiceMix). So it is really important to me that this can function as a properly service-oriented solution &#8211; hence the focus on web service enablement. Ultimately the service will generate messages that can be captured and interrogated in the service bus using a complex event processing engine.</p>
<h3><a name="codesetup"></a>Setting up the Code</h3>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipsePrefLineNo.jpg" target="_blank"><img align="left" alt="Showing line numbers in Eclipse" height="442" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipsePrefLineNo.jpg" width="400" /></a>Assuming you followed my instructions in part 1and now have the environment working, you can <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/tsgewsexample_2.zip" target="_blank">download the code for this article</a>. The zip file contains two projects:</p>
<ul>
<li>EWSAPI &#8211; This is an Eclipse Java EE &nbsp;project that is intended to be deployed to a Glassfish server. It contains the Java code that does the actual communication with Exchange and accepts WebService requests from external sources.</li>
<li>OEEWS &#8211; This is an Eclipse project that is intended to be deployed in an OpenEdge Architect workspace that calls the Java WebService.</li>
</ul>
<p>Both of these projects can be imported in the same way as I described in part 1, under the heading &quot;<a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/#quicktest">Running a quick test to prove it works</a>&quot;, although you should be aware that EWSAPI should be imported into a Java EE workspace, whereas OEEWS should be imported into an OpenEdge Architect workspace. I have had problems trying to run OE Architect in the same workspace as a Java EE configuration, so I don&#39;t recommend you try it.</p>
<p>After you have imported EWSAPI into your Java EE workspace, go ahead and drag it across to the Glassfish server in the server view and it will be deployed for you, ready to run.</p>
<p>The OEEWS project does not require any special configuration. Just import it into OpenEdge Architect and you will be good to go. Note that this code was written and compiled under 10.2B01 so I don&#39;t know how compatible it is with earlier versions.</p>
<h5>Turn on line numbers</h5>
<p>In the remainder of this series of articles, I will be cross-referencing the code that I have provided in <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/tsgewsexample_2.zip" target="_blank">the zip file</a>. When I do so, I will mention specific line numbers that map to the line numbers in the source file. It will help you a lot if you turn the line number feature on for all editors in Eclipse so that you can follow along.</p>
<p>Also note that I occasionally include portions of the source code in the article for easy reference, but when I do, I do not include the line numbers so the line number reference refers to the example code.</p>
<p>To turn line numbers on, follow these steps:</p>
<ol>
<li>From the Window menu, choose &quot;Preferences&quot;</li>
<li>Expand the &quot;General-&gt;Editors&quot; nodes and select &quot;Text Editors&quot;</li>
<li>Make sure the &quot;Show line numbers&quot; check box is checked as in the screenshot at left.</li>
</ol>
<h3>Understanding Code Contents</h3>
<p>As mentioned, the code for this first article is divided into a Java EE project and an OpenEdge project. The two projects will grow over this series of articles. Here&#39;s a brief description of these two projects and how they relate to the rough architecture that I am working on.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" target="_blank"><img align="left" alt="Deployment architecture" height="275" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" width="400" /></a></p>
<h4>EWSAPI &#8211; Exchange Web Services API</h4>
<p>The EWSAPI project is a Java Web Service that accepts Web Service requests to a defined API, turns around and passes them on to Microsoft Exchange.&nbsp;</p>
<p>In the diagram at left, therefore, the EWSAPI project contains the code that is the endpoint for the arrow numbered 1.1, and the source for the arrow numbered 1.2.</p>
<p>An important part of a SOA architecture is a canonical data model that can be used to abstract the integration from the implementation, and for me, this service will later act as the separation point between the business layer and the Microsoft Exchange communication. As I work through this in more detail, it is becoming apparent that what I am currently thinking of as the EWSAPI will ultimately be split into two completely separate components. I think there is a good case to be made for an abstraction API that allows you to plug in other adapters to work for other calendar and e-mail servers.</p>
<p>The source code for this article in the EWSAPI project contains three WebService operations:</p>
<ul>
<li><a href="#CreateAppointment">CreateAppointment</a></li>
<li><a href="#GetAppointment">GetAppointment</a></li>
<li><a href="#DeleteAppointment">DeleteAppointment</a></li>
</ul>
<p>Something to be aware of is that the APIs that we are going to be working with can do substantially more than I am going to talk about in this article. For example, an appointment can have an invitee list, recurrence, attachments, and so on. I am more focused on showing you how to create the appointment on the Exchange Server, retrieve the appointment from Exchange, and delete it. I may come back to the more detailed stuff in later posts.</p>
<p>As an aside, I wrote most of this code before I decided on the structure of these articles. My test environment is already set up to support things like Exchange Impersonation and Subscriptions. As a result, some of the code that I am providing you here already supports some of that functionality, but some of it is only half-implemented, so don&#39;t go onto those things until we get to those articles because the code may not work properly.&nbsp;</p>
<h4>OEEWS &#8211; OpenEdge Exchange Web Services API</h4>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewerPopulated.jpg" target="_blank"><img align="left" alt="Appointment Viewer - Populated" height="301" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewerPopulated.jpg" width="400" /></a>The second project is the OEEWS project which contains the OpenEdge ABL code that allows you to call each of these APIs from OpenEdge. I have created a .NET style UI in OpenEdge that allows you to connect to the service, generate 10 appointments automatically and randomly, fetch an appointment from the server, view it, and delete it.</p>
<p>Yes, I know my UI is ugly, but it&#39;s a prototype so who cares. If you don&#39;t like it, fix it.</p>
<p>The OEEWS component corresponds with the trigger point for the 1.1 arrow in the diagram above, so this article is purely about communicating with Exchange. We are not worried about the subscription API (all the #2 arrows) just yet.&nbsp;</p>
<p>Another thing to know about the OEEWS code is that I have liberally mixed procedural, object-oriented and .NET UI code in together. My primary audience for the OpenEdge code is people who have never worked with the OO stuff before, so I want them to get comfortable with it and realize that it is not that complicated.</p>
<p>Now that you know what is in the mix, let&#39;s get down to the code and understand what is going on. If you are an OpenEdge ABL developer, this first section is going to look a little scary &#8211; it&#39;s Enterprise Java. You may not recognize the code, but I am pretty sure you will understand it once I have walked through it, so hang on tight. You won&#39;t want to skip down to the ABL section because there are concepts that I am going to talk about that you need to understand in the following section.</p>
<h3>The EWS API</h3>
<p>The Java-based EWSAPI consists of 5 source code files in 3 packages. The files are:</p>
<ul>
<li>EWSCalendar.java &#8211; Contains the source code file for the web service itself and it lives in the org.tsg.ews package;</li>
<li>Appointment.java &#8211; Contains a class that represents a Calendar item, including properties for the appointment and methods to create, get, and delete appointments. It lives in the org.tsg.ews.calendar package;</li>
<li>EWSResponse.java &#8211; Contains the source code for a class that acts as a container for the response that is returned from Exchange. It lives in the org.tsg.ews.service package;</li>
<li>ExchangeService.java &#8211; Contains a class that abstracts the connection to an Exchange Web Service. It lives in org.tsg.ews.service package; and</li>
<li>SOAPRequest.java &#8211; Contains a class that is responsible for actually calling the Exchange Web Service.</li>
</ul>
<p>Go ahead and open Eclipse for Java EE, and, assuming you have already imported the EWSAPI project into your workspace, expand the EWSAPI node. Underneath that, expand the &quot;Java Resources: src&quot; node and expand each of the packages. Then go ahead and open EWSCalendar.java so that your UI looks like this:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseEECalendar.jpg" target="_blank"><img alt="Eclipse for Java EE showing EWSCalendar" height="433" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseEECalendar.jpg" width="600" /></a></p>
<p>Now let&#39;s dig into this code.&nbsp;</p>
<h3>EWSCalendar</h3>
<p>The EWSCalendar class is the main entry point in the the Java code on the server. The class exposes a Web Service that consists of 3 methods:</p>
<ul>
<li>createAppointment;</li>
<li>getAppointment; and</li>
<li>deleteAppointment.</li>
</ul>
<p>Each of these methods does pretty much what its name implies. The code in EWSCalendar actually does very little work. It is the facade that exposes the service for use as a Web Service.&nbsp;</p>
<h4>Web Services Annotations</h4>
<p>Setting up a Web Service in Java EE is as simple as annotating a class for use as a Web Service. In line 15, there is an attribute that annotates the following class, EWSCalendar, as a Web Service with a name &quot;AppointmentService&quot;.&nbsp;</p>
<p>Lines 18 and 19 contain annotations that specify that createAppointment should be treated as a Web Service operation called &quot;CreateAppointment&quot; and that the node in the SOAP document that is returned from the call should have a node called &quot;Response&quot; that contains the output parameter for the call. In line 20, createAppointment is defined as returning an EWSResponse object, and the remainder of line 20 through line 30 define the parameters for the createAppointment call. Each parameter is annotated with a WebParam annotation that provides the name of the XML node that must be created for its value.</p>
<p>Lines 45 through 51 do the same thing for the GetAppointment operation and lines 58 through 64 do the same thing for DeleteAppointment. That&#39;s all that is required to define a Web Service. I don&#39;t need to generate a WSDL or anything. Java EE does that all for me automatically based on the annotations for the methods.</p>
<p>Now if you are a Java programmer looking at the parameters for this call, you may be wondering why the parameters are not defined as objects. The simple answer is because it is a lot easier to work with this call in OpenEdge if each parameter is specifically defined, than it is to expect an appointment object, say, as an input parameter for CreateAppointment.</p>
<h3><a name="CreateAppointment"></a>CreateAppointment</h3>
<p>Going back to to line 31, the code for CreateAppointment looks like this:</p>
<pre>ExchangeService srvc = new ExchangeService(hostName, domain, username, passwd);
Appointment appt = new Appointment(srvc);
appt.setDescription(description);
appt.setLocation(location);
appt.setStartDate(startDate);
appt.setEndDate(endDate);
appt.setNotes(notes);
appt.setReminder(reminder);
appt.setReminderMinutes(minutes);
EWSResponse resp = appt.create();
return resp;
</pre>
<p>In line 32, I create an ExchangeService object, using the host name for the Exchange CAS Server that hosts the Exchange Web Service API, the domain name of the user for whom an appointment is being created, and the user name and password for that user. We&#39;ll dive into what this code actually does in a few minutes, but for the moment let&#39;s finish off the createAppointment call.</p>
<p>Line 33 instantiates an Appointment object using the ExchangeService object created in the line before and lines 33 through 39 set a number of properties of that appointment. Description is actually the subject of the appointment and lines 38 and 39 set the reminder for the appointment.&nbsp;</p>
<p>Line 40 calls the create method on the appointment and this is the code that does all the work. The create method returns an EWSResponse object, which is annotated for JAXB XML serialization to produce the XML results that we need.</p>
<h4><a name="appointmentobject"></a>The Appointment Object and JAXB XML Serialization</h4>
<p>Now I&#39;d like you to open Appointment.java in the org.tsg.ews.calendar package. You can skip down to lines 22 and 23, because there is something here that affects getAppointment later. You&#39;ll note in these two lines that there are two more annotations:</p>
<pre>@XmlRootElement(name = &quot;Appointment&quot;)
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Appointment {</pre>
<p>The two @Xml annotations are for JAXB which will automatically serialize the whole Appointment class into a root element called &quot;Appointment.&quot; The second annotation tells JAXB to look at all get&#8230; and set&#8230; methods as properties and turn them into XML. If you scroll down to line 70, you&#39;ll see an annotation &quot;@XmlElement(name = &quot;Subject&quot;) just before the getDescription method that tells JAXB to serialize this property into an XML element (not an attribute) called &quot;Subject&quot;. So the value of this property will be serialized as follows:</p>
<pre>&lt;Subject&gt;Go catch some flies - 01&lt;/Subject&gt;</pre>
<p>Again, XML serialization for classes is built in to Java EE. This piece of things is important for you to understand, because the same mechanism has been applied to EWSResponse so that its data can be serialized into the SOAP message that will be the return value to the CreateAppointment call.</p>
<h4>The Create Method</h4>
<p>Now scroll down to the create() method in Appointment.java in line 278:</p>
<pre>public EWSResponse create() {
	DatatypeFactory dtf = DatatypeFactory.newInstance();
	StringBuffer request = new StringBuffer();
	request.append(&quot;&lt;CreateItem \n&quot;);
	request.append(&quot;               SendMeetingInvitations=\&quot;SendToNone\&quot;\n&quot;);
	request.append(String.format(&quot;               xmlns=\&quot;%1$s\&quot;\n&quot;, SOAPRequest.MESSAGES_URI));
	request.append(String.format(&quot;               xmlns:t=\&quot;%1$s\&quot;&gt;\n&quot;, SOAPRequest.TYPES_URI));
	request.append(&quot;    &lt;Items&gt;\n&quot;);
	request.append(&quot;        &lt;t:CalendarItem&gt;\n&quot;);
	request.append(&quot;            &lt;t:Subject&gt;&quot;);
	request.append(description);
	request.append(&quot;&lt;/t:Subject&gt;\n&quot;);
	if (notes != null) {
		request.append(&quot;            &lt;t:Body BodyType=\&quot;Text\&quot;&gt;&quot;);
		request.append(notes);
		request.append(&quot;&lt;/t:Body&gt;\n&quot;);
	}
	if (reminder) {
		request.append(&quot;            &lt;t:ReminderIsSet&gt;true&lt;/t:ReminderIsSet&gt;&quot;);
		request.append(&quot;            &lt;t:ReminderMinutesBeforeStart&gt;&quot;);
		request.append(Integer.toString(reminderMinutes));
		request.append(&quot;&lt;/t:ReminderMinutesBeforeStart&gt;\n&quot;);
	}
	if (startDate != null) {
		request.append(&quot;            &lt;t:Start&gt;&quot;);
		request.append(dtf.newXMLGregorianCalendar(startDate).toXMLFormat());
		request.append(&quot;&lt;/t:Start&gt;\n&quot;);
	}
	if (endDate != null) {
		request.append(&quot;            &lt;t:End&gt;&quot;);
		request.append(dtf.newXMLGregorianCalendar(endDate).toXMLFormat());
		request.append(&quot;&lt;/t:End&gt;\n&quot;);
	}
	if (location != null) {
		request.append(&quot;            &lt;t:Location&gt;&quot;);
		request.append(location);
		request.append(&quot;&lt;/t:Location&gt;\n&quot;);
	}
	request.append(&quot;        &lt;/t:CalendarItem&gt;\n&quot;);
	request.append(&quot;    &lt;/Items&gt;\n&quot;);
	request.append(&quot;&lt;/CreateItem&gt;\n&quot;);</pre>
<p>Lines 280 through 319 simply build up the body of the SOAP message that needs to be sent to Exchange for it to create the appointment.</p>
<p>One of the things about Exchange Web Services that is critical to understand is that there can be no mistake in this XML. It needs to appear exactly as it is defined in the Exchange SDK, otherwise it will not work. The order of the elements is absolutely critical. I have spent a lot of time trying to figure out why a call was not working, only to find that the the XML was badly formatted or a node was spelled incorrectly. Exchange does not help you here. You simply get a 500 &#8211; Internal Server Error message from the Web Server which is about as much use as an udder on a bull. &nbsp;</p>
<p>In line 282, we start out by defining a CreateItem node that contains an Items node that has one CalendarItem node in it. Namespacing is very important, so lines 284 and 285 set up the appropriate namespaces from constants defined in the SOAPRequest class.</p>
<p>Lines 288 through 290 serialize the subject while lines 291 through 295 handle the Notes or Body of the appointment. Lines 296 through 301 handle the reminder and lines 302 through 311 handle the start and end dates for the appointment. After handling the location in lines 312 through 316, we end off by closing out the XML tags.</p>
<p>The rest of the code in this method looks like this:</p>
<pre>SOAPRequest req = new SOAPRequest(request.toString(), emailAddress);
EWSResponse retVal = service.makeRequest(req);
lastResponse = retVal;
id = retVal.getId();
changeKey = retVal.getChangeKey();
return retVal;</pre>
<p>Now it&#39;s important to realize that all we have created is the part of the SOAP message that tells Exchange what we want it to do &#8211; create a calendar item. We haven&#39;t wrapped it in a SOAP message yet. Line 321 takes care of doing this by creating a SOAPRequest object based on the request string that we just created. Ignore the fact that we pass in an emailAddress at this point, because that will be used later for the Exchange Impersonation article.</p>
<p>If you want to go and explore the SOAPRequest class, feel free to do so. It simply creates the SOAP envelope and plugs the request information that we passed in into the body of the SOAP message. No rocket science in this.</p>
<p>The next step (line 322) is to call the makeRequest() method on the ExchangeService object that was passed in when we created the appointment. &nbsp;We&#39;ll dig into this call in a minute, but let&#39;s just finish out understanding what the rest of this method is doing.&nbsp;</p>
<p>The makeRequest() method call returns us an EWSResponse object that we can return to the caller. Before we do that, though, we set two very important pieces of information inside this Appointment object.</p>
<h4>Items and Item IDs</h4>
<p>When any item (e-mail, contact, task, or appointment) is created on an Exchange Server, it is allocated two pieces of information:</p>
<ol>
<li>An Item ID. This is universally unique inside Exchange. No two items will ever have the same Item ID, even across different mailboxes, and this becomes the mechanism that we need to refer to the item later;</li>
<li>A ChangeKey. This piece of information is almost like a SHA1 or MD5 checksum that tells what the state was of the item at the point that you created it. This becomes very important later when we update these items.</li>
</ol>
<p>You&#39;ll note that I have switched from referring to the things we are creating as Calendar items to simply calling them Items. That&#39;s because in Exchange, everything that can be created inside a folder (something we&#39;ll deal with later) is considered an Item. E-mail, Contacts, Tasks and Appointments are all items. This is another important concept to get clear, because if you look back at line 282, you&#39;ll note that the node that we created was a CreateItem node and that it contained a CalendarItem node inside an Items node.</p>
<p>Lines 324 and 325 set the values of the Item ID and ChangeKey for this appointment respectively. I also store the EWSResponse object in the Appointment in case it is needed later. I don&#39;t have code that uses this right now, though. Line 326 returns the EWSResponse object to the caller and lines 328 through 330 catch any exceptions and turn them into an EWSResponse object that can be serialized.</p>
<h4>ExchangeService</h4>
<p>The next thing to do is to take a look at the code in the ExchangeService class in the org,tsg.ews.service package. The guts of the communication with Exchange happens in the makeRequest method, which begins at line 57. You&#39;ll note that the first thing that makeRequest does is call &quot;setAuthenticator&quot; in line 58. The code in setAuthenticator is critical to our communication with Exchange, so scroll down to line 91 and we will pick up there.</p>
<h4>setAuthenticator</h4>
<p>The following is the code that is contained in setAuthenticator:</p>
<pre>private void setAuthenticator() {
	System.setProperty(&quot;http.auth.preference&quot;, BASIC_AUTHENTICATION);
    	System.setProperty(&quot;http.auth.digest.validateServer&quot;, &quot;false&quot;);
    	System.setProperty(&quot;http.auth.digest.validateProxy&quot;, &quot;false&quot;);

	Authenticator.setDefault(new Authenticator() {
		@Override
		protected PasswordAuthentication getPasswordAuthentication() {
			StringBuffer user = new StringBuffer(domain);
			user.append(&quot;\\&quot;);
			user.append(username);
			System.out.println(&quot;Authentication...&quot;);
	   		System.out.print(&quot;Requesting Prompt: &quot;);
			System.out.println(this.getRequestingPrompt());
	    		System.out.print(&quot;Requesting Scheme: &quot;);
			System.out.println(this.getRequestingScheme());
	   		System.out.print(&quot;Requestor Type: &quot;);
			System.out.println(this.getRequestorType());

			return new PasswordAuthentication(user.toString(), password.toCharArray());
		}

	});
}</pre>
<p>This code has gone through a number of iterations and there are a lot of debug messages that I have put in here to try and figure out what I could do about the authentication piece of things. As I mentioned in part 1, this code currently only works with basic authentication switched on. The first System.setProperty call sets the authentication mode to basic authentication. The next two properties only apply with digest authentication and you can ignore them.&nbsp;</p>
<p>The Authenticator.setDefault() call sets a default authenticator class that takes the user name and password that were supplied earlier, and makes them available for authentication purposes when the Exchange Web Service requests credentials.</p>
<p>The big problem with this code is that it sets these credentials for the entire JVM. This is a bad thing, especially in the Java EE environment, but there are solutions that I have already found to fix this problem that I will blog about later. For now, the purposes of what I am currently trying to achieve, this is good enough, and an important thing to remember is that I am looking at this as server-side code so Exchange Impersonation is a key component of the strategy going forward. In the impersonation model, the problem is not as serious as it is right now.</p>
<p>The reason this is such a serious risk right now is that you need to shut down and restart the Glassfish AppServer between changing the user for whom the appointment is being created. But I figured that as this is the only article that will use this model, we&#39;re OK with that limitation.</p>
<h4><a name="makerequest"></a>Making the call</h4>
<p>Now we need to go back to line 60 in the makeRequest function:</p>
<pre>URL ewsURL = new URL(String.format(EWS_URL, this.hostName));  // Substitute the host name into the URL.);
HttpsURLConnection ewsConn = (HttpsURLConnection) ewsURL.openConnection();
ewsConn.setRequestMethod(&quot;POST&quot;);
ewsConn.setRequestProperty(&quot;Content-type&quot;, &quot;text/xml;utf-8&quot;);
ewsConn.setDoInput(true);
ewsConn.setDoOutput(true);</pre>
<p>Line 60 sets up a URL for the Exchange Server. The String.format call substitutes the hostName provided into the EWS_URL constant so that the Exchange Web Service API is called. The constant is defined in line 25.</p>
<hr />
<p><em><strong>Update: </strong></em>Since I wrote this article, I have installed and tested Microsoft Exchange Server 2007 SP3 and Microsoft Exchange Server 2010. There is one minor modification you will need to make to the sourced code that accompanies this article for it to work with these. Line 63 of the source code file &quot;ExchangeService.java&quot; that accompanies this article reads:</p>
<pre>ewsConn.setRequestProperty(&quot;Content-type&quot;, &quot;text/xml;utf-8&quot;);</pre>
<p>It may need to be changed to read:</p>
<pre>ewsConn.setRequestProperty(&quot;Content-type&quot;, &quot;text/xml;charset=utf-8&quot;);</pre>
<hr />
<p>Next we set up an https connection, set the request method to post, and several other properties of the connection. Line 67 contains a debug message that displays the entire XML for the SOAP message just prior to posting the call to the Exchange Web Server and&nbsp;lines 69 through 72 actually post the message to the Exchange Server:</p>
<pre>PrintWriter pout = new PrintWriter(new OutputStreamWriter(ewsConn.getOutputStream(), &quot;UTF-8&quot;), true);
pout.print(message.getMessage());
pout.flush();
pout.close();</pre>
<h4>Receiving the response</h4>
<p>All calls to Exchange are followed by a response:</p>
<pre>EWSResponse resp;
if (ewsConn.getResponseCode() == HttpsURLConnection.HTTP_OK) {
        BufferedReader bin = new BufferedReader(new InputStreamReader(ewsConn.getInputStream()));

        StringBuilder result = new StringBuilder();
        String line;
        while( (line = bin.readLine()) != null )
        	result.append(line);
        System.out.println(result.toString());
        resp = new EWSResponse(result.toString());</pre>
<p>In line 75, we check to see that the response we got from the Web Service was an OK &#8211; 200. If it is, line 76 instantiates a BufferReader to read the URL connection&#39;s input stream. Lines 78 through 81 read the contents of that stream into a string which we display in line 82 so we can see the response we got from Exchange.</p>
<p>Line 83 then takes that response and instantiates an EWSResponse object with the string we got back, and the EWSResponse object parses the SOAP message that we received from Exchange and stores the response in object. Among the things that is returned is a ChangeKey, an ID and the error status of the call. I&#39;m not going to spend much time talking about EWSResponse here, other than to say that it parses the XML using the standard DOM in the JVM.</p>
<p>The remainder of the makeRequest() method deals with what happens if we don&#39;t get an OK http response:</p>
<pre>} else {
	System.out.println (String.format(&quot;Error code: %1$s - %2$s&quot;, ewsConn.getResponseCode(), ewsConn.getResponseMessage()));
	resp = new EWSResponse(&quot;HTTPError&quot;, ewsConn.getResponseCode(), ewsConn.getResponseMessage());
}
return resp;</pre>
<p>Line 85 provides the details of the response as a debug message and line 86 creates an EWSResponse object that provides details of the error. The most likely scenarios for this response are 401 errors (HTTP authentication failed) or 500 errors (the XML was not properly understood by Exchange and it reports an &quot;Internal Server Error&quot;). The 500 errors are a pain because there is no information available on why you got them. You have to guess, and it is this that made me hand-code the XML that is being sent to the Exchange Server.</p>
<p>Now that we have an EWSResponse object, it can be returned to the caller, serialized and returned from the WebService to whatever the source was.</p>
<h4>Testing it out with soapUI</h4>
<p>The next step is to try and test this. Make sure you have your Glassfish server running and that the EWSAPI code is deployed to the server. You can check this by switching to the Servers view in Eclipse for Java EE and looking at the status of the GlassFish V3 Java EE 6 server. Start the server if necessary and drag the whole EWSAPI node to the GlassFish server node and it will be deployed for you.</p>
<p>The next step is to start soapUI and create a new project. Right-click on the Projects node and create a new project. You should see the following dialog:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CreateSoapUIProject.jpg" target="_blank"><img alt="Creating the soapUI project for AppointmentService" height="450" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CreateSoapUIProject.jpg" width="600" /></a></p>
<p>The URL that need to type in the &quot;Initial WSDL/WADL&quot; field is:</p>
<pre>http://localhost:8080/EWSAPI/AppointmentService?wsdl</pre>
<p>Once you have entered that URL, make sure the check boxes are as they appear in the screenshot above, and choose the OK button. SoapUI will generate a project for AppointmentService and it will have three operations under it. Go ahead and expand the tree so that all the nodes are visible. The three operations are CreateAppointment, GetAppointment, and DeleteAppointment. Each of them has a &quot;Request 1&quot; node under it. I have renamed those nodes to &quot;CreateApptRequest&quot;, etc, so that when a request is open, I can differentiate it from the others.</p>
<p>Before we execute a call, open Outlook for the account that you are testing against so you can see what happens in Outlook when the appointment is created.</p>
<p><a name="CreateApptRequest"></a><img alt="Soap UI calling CreateRequest" height="292" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUICreateRequest.jpg" width="600" /></p>
<p>Double-click on the CreateAppointment request in soapUI and open the XML editor will open with the XML Soap message in the left-hand pane. Remember, there is no validation, so make sure you type all the right values between the tags in the XML document.</p>
<p>The first parameter for the call is the Exchange Server. You need to type the fully qualified domain name of the Exchange Web Services host that you are trying to call. Next is the domain. This is the domain that is used for the Windows login. Username and password are fairly self-explanatory, as are&nbsp;the Description, Location and Notes elements.&nbsp;</p>
<p>SetReminder should be either &quot;true&quot; or &quot;false&quot;. If &quot;true&quot;, a reminder will be set for the appointment that will go off a certain number of minutes before the appointment. ReminderMinutes is an integer that specifies how many minutes lead-time the reminder should have.</p>
<p>StartDateTime and EndDateTime are exactly what they say they are, but they are ISO dates that include a time zone. The date is in yyyy-mm-dd order and is followed by a T to indicate that the rest of the field is all time. The time is a 24 hour time format, including a 3 digit decimal for the number of milliseconds. So 5:00pm is 17:00:00.000. The last section of the time is an offset from Universal Standard Time(UTC). I&#39;m on the West Coast of the US, so in the Northern Hemisphere Summer, we are 7 hours behind UTC. Thus my timezone information is -07:00. If I were in South Africa, I&#39;d be two hours ahead of UTC which would be +02:00.</p>
<p>Once you have all these fields filled out, you can execute the call. In the right-hand pane of the request, you should get a SOAP message back that tells you what happened. If all went well, there will be a single response node that contains three attributes &#8211; ChangeKey, ItemID and ErrorStatus. The ErrorStatus should be &quot;NoError&quot; and the other two attributes will have very long strings in them that mean nothing, but I&#39;ve already explained what these are.&nbsp;</p>
<p>If you get this, your appointment has been created in Exchange and if you have Outlook open in the background, a second or two later the appointment will show up in the calendar as you can see in the screenshot above.</p>
<p>If you are having trouble getting any kind of response back, go to Eclipse for Java EE, and switch to the Glassfish Server log in the Console view as follows:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseConsoleLog.jpg" target="_blank"><img alt="Glassfish Server Log View" height="375" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseConsoleLog.jpg" width="600" /></a></p>
<p>You will need to select the down-arrow next to the console button in the toolbar in the Console view. Select the log file from the two console sources, and it will show the messages that were output as the code was running.</p>
<p>Now that we have successfully created the appointment, you need to keep the result of the call around, because you are going to need it in a few minutes when we run the GetAppointment call.</p>
<p>For the moment, though, let&#39;s switch back to the Eclipse for Java EE and look at the code for GetAppointment and DeleteAppointment.</p>
<h3><a name="GetAppointment"></a>GetAppointment</h3>
<p>If we switch back to the EWSCalendar class, lines 45 through 56 contain the code for retrieving an appointment from Exchange:</p>
<pre>@WebMethod(operationName = &quot;GetAppointment&quot;)
@WebResult(name = &quot;Appointment&quot;)
public Appointment getAppointment(@WebParam(name = &quot;ExchangeServer&quot;) String hostName,
				@WebParam(name = &quot;Domain&quot;) String domain,
				@WebParam(name = &quot;User&quot;) String username,
				@WebParam(name = &quot;Password&quot;) String passwd,
				@WebParam(name = &quot;AppointmentID&quot;) String id) {
	ExchangeService srvc = new ExchangeService(hostName, domain, username, passwd);
	Appointment appt = new Appointment(srvc);
	appt.retrieve(id);
	return appt;
}</pre>
<p>As I mentioned earlier, the first couple of lines are annotations needed for exposing this call as a Web Service called GetAppointment. Note that this method returns an object of type <a href="#appointmentobject">Appointment, the class we learned about earlier on</a>. All this call does is instantiate an ExchangeService object, instantiate an Appointment object, retrieve it, and return it. The Java EE WebServices framework takes care of serializing the Appointment object to XML.</p>
<p>The retrieve() method takes an Item ID as a parameter so that it retrieves the calendar item by means of that Item ID.</p>
<h4>Appointment.retrieve()</h4>
<p>The retrieve() method in line 157 of the Appointment class is responsible for crafting the XML message that gets sent to the Exchange Server:</p>
<pre>public EWSResponse retrieve(String itemID) {
	try {
		StringBuffer request = new StringBuffer();
	        request.append(&quot;&lt;GetItem \n&quot;);
	        request.append(String.format(&quot;               xmlns=\&quot;%1$s\&quot;\n&quot;, SOAPRequest.MESSAGES_URI));
	        request.append(String.format(&quot;               xmlns:t=\&quot;%1$s\&quot;&gt;\n&quot;, SOAPRequest.TYPES_URI));
	        request.append(&quot;    &lt;ItemShape&gt;\n&quot;);
	        request.append(&quot;          &lt;t:BaseShape&gt;Default&lt;/t:BaseShape&gt;\n&quot;);
	        request.append(&quot;          &lt;t:AdditionalProperties&gt;\n&quot;);
	        request.append(&quot;              &lt;t:FieldURI FieldURI=\&quot;item:Body\&quot;/&gt;\n&quot;);
	        request.append(&quot;              &lt;t:FieldURI FieldURI=\&quot;item:ReminderIsSet\&quot;/&gt;\n&quot;);
	        request.append(&quot;              &lt;t:FieldURI FieldURI=\&quot;item:ReminderMinutesBeforeStart\&quot;/&gt;\n&quot;);
	        request.append(&quot;          &lt;/t:AdditionalProperties&gt;\n&quot;);
	        request.append(&quot;    &lt;/ItemShape&gt;\n&quot;);
	        request.append(&quot;    &lt;ItemIds&gt;\n&quot;);
	        request.append(String.format(&quot;        &lt;t:ItemId Id=\&quot;%1$s\&quot;/&gt;\n&quot;,itemID));
	        request.append(&quot;    &lt;/ItemIds&gt;\n&quot;);
	        request.append(&quot;&lt;/GetItem&gt;\n&quot;);
		SOAPRequest req = new SOAPRequest(request.toString(), emailAddress);
		EWSResponse retVal = service.makeRequest(req);
		if ((!retVal.hasError()) &amp;&amp; retVal.getElement() != null) {
			parseItem(retVal.getElement());
		}
		lastResponse = retVal;
		return retVal;
	}
	catch (Exception e) {
		return new EWSResponse(e);
	}
}</pre>
<p>The first thing to note about this code is that there is nothing in it that indicates that the object that we are retrieving is a Calender Item. As far as Exchange is concerned, we are retrieving an item, and it does not care what type of item it is. So the call we make is a GetItem call.</p>
<p>Lines 163 through 170 define an ItemShape object. The ItemShape tells Exchange what we are interested in retrieving about this item. The BaseShape node tells it to retrieve the most basic properties of the item, but we need additional data like the Body (or notes), the Reminder flag and the number of minutes in advance that the reminder is required. So the AdditionalProperties node asks Exchange to retrieve these properties, too.</p>
<p>Lines 171 through 173 tell Exchange what item IDs to return &#8211; in our case there is always only one.</p>
<p>In line 175 we create the SOAP envelope for the call and in line 176 we call <a href="#makerequest">makeRequest</a> to retrieve the data from Exchange. Assuming all went well with the call, we set the values of all the fields in the Appointment by calling parseItem() in line 178. I&#39;m not going to spend a lot of time explaining the XML parsing. Just take it from me that the code parses the XML node for the appointment and gets the right values out.</p>
<p>Of course, if the call failed, we need the client to know that, so we store the EWSResponse object in the appointment. The advantage of that is that the EWSResponse object is XML-serializable so it will be serialized with the Appointment object. Another nice thing about JAXB is that it will ignore null elements (unless you tell it not to). What this means is that if the Appointment object&#39;s properties are null, they will not be written to the XML response.</p>
<p>That&#39;s pretty much it. Now let&#39;s see what happens when we run it.</p>
<h4>Testing GetAppointment with soapUI</h4>
<p>Before you switch back to soapUI, go to the appointment that we created earlier, and make some changes to it in Outlook. Add some stuff in the notes and change the date and time or something. Now switch back to soapUI and highlight and copy (Ctrl+C) the Item ID that is in the Response node in the right side pane of the <a href="#CreateApptRequest">CreateApptRequest window we opened earlier</a>.&nbsp;</p>
<p>Now open the GetAppointment request and set all the values for the credentials as you did earlier:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUIGetRequest.jpg" target="_blank"><img alt="soapUI showing GetAppointment" height="428" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUIGetRequest.jpg" width="600" /></a></p>
<p>The Appointment ID node needs to contain the Item ID that you copied from the CreateApptRequest above. Once you have pasted that in and executed the call, you should get a response that contains all the information about the appointment that we requested. Note that the changes that you made are retrieved with the call. I should mention that sometimes you have to wait a few seconds for Exchange to commit your changes and notify the Client Access Server before your changes become available for retrieval by Exchange Web Services.</p>
<h3><a name="DeleteAppointment"></a>DeleteAppointment</h3>
<p>Last, but not least is DeleteAppointment. The code for this is actually very simple. If we go back to Eclipse for Java EE and look at EWSCalendar again, lines 58 through 67 contain the code that does the work:</p>
<pre>@WebMethod(operationName = &quot;DeleteAppointment&quot;)
@WebResult(name = &quot;Response&quot;)
public EWSResponse deleteAppointment(@WebParam(name = &quot;ExchangeServer&quot;) String hostName,
				@WebParam(name = &quot;Domain&quot;) String domain,
				@WebParam(name = &quot;User&quot;) String username,
				@WebParam(name = &quot;Password&quot;) String passwd,
				@WebParam(name = &quot;AppointmentID&quot;) String id) {
	ExchangeService srvc = new ExchangeService(hostName, domain, username, passwd);
	EWSResponse resp = Appointment.delete(srvc, id, null);
	return resp;
}</pre>
<p>By now, hopefully you understand everything down to line 66. In line 66, we call Appointment.delete() and pass in the service and an Item ID. When the call is complete, we simply return the EWSResponse object that should give us error status.</p>
<h4>Appointment.delete()</h4>
<p>The guts of the work happens in the Appointment object, so switch to that editor and go to line 26:</p>
<pre>public static EWSResponse delete(ExchangeService srvc, String itemID, String emailAddress) {
	try {
		StringBuffer request = new StringBuffer();
	        request.append(&quot;&lt;DeleteItem \n&quot;);
	        request.append(String.format(&quot;               xmlns=\&quot;%1$s\&quot;\n&quot;, SOAPRequest.MESSAGES_URI));
	        request.append(String.format(&quot;               xmlns:t=\&quot;%1$s\&quot;\n&quot;, SOAPRequest.TYPES_URI));
	        request.append(&quot;           DeleteType=\&quot;MoveToDeletedItems\&quot;\n&quot;);
	        request.append(&quot;           SendMeetingCancellations=\&quot;SendToNone\&quot;&gt;\n&quot;);
	        request.append(&quot;    &lt;ItemIds&gt;\n&quot;);
	        request.append(String.format(&quot;        &lt;t:ItemId Id=\&quot;%1$s\&quot;/&gt;\n&quot;,itemID));
	        request.append(&quot;    &lt;/ItemIds&gt;\n&quot;);
	        request.append(&quot;&lt;/DeleteItem&gt;\n&quot;);
		SOAPRequest req = new SOAPRequest(request.toString(), emailAddress);
		EWSResponse retVal = srvc.makeRequest(req);
		return retVal;
	}
	catch (Exception e) {
		return new EWSResponse(e);
	}
}</pre>
<p>Again, hopefully this code looks very similar to the GetItem call we did earlier. The DeleteItem node has two interesting attributes in lines 32 and 33. You&#39;ll see the DeleteType attribute which tells Exchange to move the deleted appointment to the Deleted Items folder. You can specify exactly what to do with the item, including a hard delete &#8211; permanent deletion.</p>
<p>In line 33, the SendMeetingCancellations attribute tells Exchange what to do about notifying people about the cancellation of the appointment.</p>
<p>Line 34 through 36 contains the list of Item IDs to be deleted (in our case, just one).&nbsp;Lines 38 through 40 create the SOAP envelope, make the call to Exchange and obtain and return the EWSResponse object.&nbsp;That&#39;s all there is to it.</p>
<h4>Testing DeleteAppointment with soapUI</h4>
<p>The last step in the Java tests is to see if the DeleteAppointment API works. Make sure you have the Item ID for the appointment you created earlier, and open the DeleteAppointment request. As with the GetAppointment API, paste the Item ID into the Appointment ID node:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUIDeleteRequest.jpg" target="_blank"><img alt="Delete Appointment Request in soapUI" height="428" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUIDeleteRequest.jpg" width="600" /></a></p>
<p>If all goes well, the response will be contained in a Response node and the ErrorStatus will be NoError. If you switch to Outlook, the appointment has been removed and if you switch to the Deleted Items folder, you will see the Calendar Item in that folder.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OutlookDeletedItems.jpg" target="_blank"><img alt="Outlook Deleted Items" height="407" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OutlookDeletedItems.jpg" width="600" /></a></p>
<h3>Java Summary</h3>
<p>That&#39;s all there is to the Java side of things for this article. You have now learned how to use Java to create, get and delete calendar items using the Exchange Web Services API. The next article will focus on Exchange Impersonation.</p>
<p>If you&#39;re a Java developer, and you have no interest in the OpenEdge component, thank you for your attention. I hope this was useful to you.</p>
<p>If you are an OpenEdge developer, don&#39;t go anywhere &#8211; we&#39;re going to see how to call this Web Service from inside OpenEdge.&nbsp;</p>
<h3>The OE EWS Components</h3>
<p>If you have been following the code up until now, you have a running instance of Glassfish and it&#39;s ready for you to test the OpenEdge code that calls these three Web Service operations. Go ahead and open OpenEdge Architect and make sure you have imported the OEEWS project into OpenEdge Architect.</p>
<p>Once you have imported it, expand the src folder all the way down until your Resources are expanded as in the screenshot below:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OEEditorAppointment.jpg"><img alt="OEArchitect1" height="375" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OEEditorAppointment.jpg" width="600" /></a></p>
<p>Just so there is no confusion, my screenshots were taken of the code as I have it checked into my Subversion repository, so you can ignore the date, time and user name next to each source code element. That is information that Subversion adds.</p>
<p>The first code that we are going to look at is in the CreateAppointments.p procedure as this code creates a batch of 10 appointments, so go ahead and open this procedure in OE Architect.</p>
<h3>CreateAppointments.p</h3>
<p>There really is no rocket science about this code. For the most part, it is ordinary OpenEdge ABL/4GL code. Lines 14 and 15 of the source file do contain two statements that are specific to object-oriented ABL:</p>
<pre>USING Progress.Lang.*.
USING com.tsg.ews.*.</pre>
<p>These two lines tell the compiler that my code references objects in the Progress.Lang package and in the com.tsg.ews package. Don&#39;t fret about this just yet.</p>
<p>Line 20 references a temp-table definition that is in an include file while lines 21 through 24 define 3 input parameters and an output parameter table for the temp-table defined in the include file.</p>
<p>The rest of the code down to line 39 is pretty standard 4GL, but in line 39, I define a variable called &quot;appt&quot; that is of type com.tsg.ews.Appointment. If you cast your eyes across to the Resources view, you will see a file called Appointment.cls under the src/com/tsg/ews folder. Appointment.cls contains an OpenEdge class definition, and we will look at this code a little later. The Using statement in line 15 told Progress to look in the com/tsg/ews folder for any classes that I refer to.</p>
<p>The interesting code starts in line 43 (I have removed comments below for brevity):</p>
<pre>REPEAT iCount = 1 TO 10:

    appt = new Appointment().
    appt:Subject = pcDescription + &quot; - &quot; + STRING(iCount, &quot;99&quot;).
    appt:Location = pcLocation.
    appt:Notes = pcNotes.
    appt:StartDateTime = figureOutStartDate(dWorkDate).
    appt:EndDateTime = DATETIME-TZ(DATE(appt:StartDateTime), MTIME(appt:StartDateTime) + iDuration, TIMEZONE ).
    dWorkDate = appt:EndDateTime.

    appt:SaveAppointment().        

    CREATE ttAppointment.
    IF appt:ItemID &lt;&gt; ? AND
       appt:ItemID &lt;&gt; &quot;&quot; THEN
       cString = appt:ItemID.
    ELSE
       cString = STRING(iCount).  

    ASSIGN
        ttAppointment.description = appt:Subject
        ttAppointment.startdate = DATETIME(DATE(appt:StartDateTime), MTIME(appt:StartDateTime)).
        ttAppointment.enddate = DATETIME(DATE(appt:EndDateTime), MTIME(appt:EndDateTime)).
        ttAppointment.itemid = cString.
    .

END.</pre>
<p>This repeat loop occurs 10 times. In line 46, I create a new instance of an Appointment object and I assign the reference to the appt variable. What this means is that I have an empty Appointment object. In lines 21- 23 I defined 3 input parameters for the appointment description, location and notes. In 47, 48 and 49, I set the Appointment&#39;s corresponding properties from these input parameters.</p>
<p>In line 50, I set the start date and time for the appointment to the return value of the figureOutStartDate function. I&#39;m not going to walk through the code for the function here, but I&#39;ll tell you that it goes and calculates a date on a work day (Monday through Friday) between 9 and 5, skipping an hour for lunch at 12:00pm. It also sets a variable that is global to this procedure called iDuration. This contains the length of the appointment in milliseconds. In line 51, I set the end date and time to the start date and time plus the duration.</p>
<p>The upshot is that I will get 10 appointments that follow each other of random duration and with random gaps between them starting from now, until all 10 appointments are scheduled.</p>
<p>Line 57 calls SaveAppointment and this method on the Appointment object is responsible for calling the Web Service. We&#39;ll get to this code in a minute or two. When the appointment is successfully saved, we set the ItemID property of the Appointment object to the return value from Exchange.</p>
<p>Lines 60 through 72 create a temp-table record for this appointment and store the subject, start date, end date and item id. This is just regular 4GL code.&nbsp;</p>
<h4>Appointment.cls</h4>
<p>&nbsp;</p>
<p>Next, we&#39;ll take a look at the code in Appointment.cls. Go ahead an open it in the editor.</p>
<p>Appointment.cls is an OpenEdge ABL class that uses OpenEdge Object-Orientation. Lines 16 through 20 declare the class and define some variables. Lines 22 through 24 define the default constructor for the Appointment object. This is the code that is called when an object is instantiated as it was in line 46 of CreateAppointment.p. Line 26 through 30 declares a constructor that we will use later for GetAppointment.&nbsp;</p>
<p>Lines 32 through 68 declare several properties for the Appointment object that we used to set the appointment values in lines 47 through 51 of CreateAppointments.p above.</p>
<p>Skip on down to line 87, and we will take a look at the code that actually saves the appointment:</p>
<pre>METHOD PUBLIC LOGICAL SaveAppointment():
    DEFINE VARIABLE srvc AS EWSService NO-UNDO.
    DEFINE VARIABLE hHandle AS HANDLE NO-UNDO.
    DEFINE VARIABLE cRetVal AS LONGCHAR NO-UNDO.
    DEFINE VARIABLE cNotes AS LONGCHAR NO-UNDO.
    cNotes = &quot;&lt;![CDATA[&quot; + THIS-OBJECT:Notes + &quot;]]&gt;&quot;.
    srvc = EWSService:GetService().
    hHandle = srvc:CalenderAPI.
    RUN CreateAppointment IN hHandle
       (INPUT srvc:ExchangeServer,
        INPUT srvc:Domain,
        INPUT srvc:UserName,
        INPUT srvc:Password,
        INPUT THIS-OBJECT:Subject,
        INPUT THIS-OBJECT:Location,
        INPUT THIS-OBJECT:StartDateTime,
        INPUT THIS-OBJECT:EndDateTime,
        INPUT cNotes,
        INPUT THIS-OBJECT:ShouldSetReminder,
        INPUT THIS-OBJECT:ReminderMinutes,
        OUTPUT cRetVal).
    parseResponse(cRetVal).
    RETURN TRUE.
END.</pre>
<p>The first few lines (88-91) define variables that we will use later. In line 92, we wrap the Notes field in a CDATA node so that we can handle any data that can be put in it. It could contain HTML, XML or any other kind of data.&nbsp;</p>
<p>Line 93 calls the GetService method on the EWSService object. EWSService is another class that I created and all it does is wrap the processing around the connection information for the Java and Exchange Web Services. It also takes care of establishing the connection to the Java Web Service. In line 94, we get the handle to that Web Service connection and in lines 96 through 107, we make the call to the Web Service and receive the response in the cRetVal variable.</p>
<p>Line 108 takes care of parsing the response so that the ItemID is stored into the appointment object.</p>
<p>That is all there is to it. Now let&#39;s take a look at how we call this code.&nbsp;</p>
<h4>AppointmentViewer.cls</h4>
<p>Go to the Resources view and right-click on the AppointmentViewer.cls file. From the context menu, select &quot;Open with&#8230;-&gt;OpenEdge Visual Designer.&quot; Your screen should look like this:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OEEditorApptViewer.jpg" target="_blank"><img alt="OpenEdge Appointment Viewer" height="375" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OEEditorApptViewer.jpg" width="600" /></a></p>
<p>The AppointmentViewer class is a .NET style UI with OpenEdge code behind it. Double-click on the &quot;Generate Appointments&quot; button and you will be taken to a section of code in this form that calls the CreateAppointments.p procedure we looked at earlier. The code is in line 81 through 92 of the editor that is now open:</p>
<pre>METHOD PRIVATE VOID btnGenerate_Click( INPUT sender AS System.Object, INPUT e AS System.EventArgs ):
    CLOSE QUERY qAppointment.
    RUN CreateAppointments.p (INPUT txtSubject:Text, INPUT txtLocation:Text, INPUT txtNotes:Text, OUTPUT TABLE ttAppointment).
    OPEN QUERY qAppointment
        FOR EACH ttAppointment NO-LOCK
            BY ttAppointment.startdate.
    THIS-OBJECT:bindingSource1:Handle = QUERY qAppointment:HANDLE.
    bindingSource1:RefreshAll().
    dataGridView1:Refresh().
    RETURN.
END METHOD.</pre>
<p>This code closes the qAppointment quert, which is a query based on the ttAppointment temp-table defined in the ttappointment.i include file. The code then calls CreateAppointments.p which returns the ttAppointment table. The input parameters for this call are derived from the Subject, Location and Notes text boxes that are at the top of the Appointments tab in the AppointmentViewer window. Once the call is complete, we reopen the query, refresh the binding source and data grid so that the data is displayed on the screen.</p>
<h4>Running the Appointment Viewer</h4>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewerEmpty.jpg" target="_blank"><img align="left" alt="Empty appointment viewer" height="301" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewerEmpty.jpg" width="400" /></a>Now it&#39;s time to run the Appointment Viewer. From the OpenEdge Architect Run menu, choose Run-&gt;Run as&#8230;-&gt;OpenEdge Application. If you are asked to save the file, you can go ahead and do so. When you run the code, you should see the screen at left.</p>
<p>Enter the name of your Java Server and make sure you include the port number, which, by default, will be 8080. For these initial runs, you can make the call using localhost for the name of the server.</p>
<p>The other prompts in the top half of the screen are the same as those we referred to in the calls that we made from soapUI above.</p>
<p>Before you generate the appointments, you should make sure that Outlook is open in the background so you can see the effect of the call.</p>
<p>Once you enter the password, the Generate Appointments button is enabled. Go ahead and enter a Subject, Location and some notes and then choose the Generate Appointments button.</p>
<p>If things are working properly, you will see a slight pause and the grid at the bottom of the screen will populate with a list of appointments that were automatically generated for you by the CreateAppointments.p procedure.&nbsp;</p>
<p>Your populated screen should look something like the following screen. It is possible that you will see a series of numbers in the Item ID column. If you do, there was a problem creating the appointments on the server. If the appointments were created properly, you will see the ItemID populated with very long strings of characters as below:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewerPopulated.jpg" target="_blank"><img alt="Populated appointment viewer" height="452" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewerPopulated.jpg" width="600" /></a></p>
<p>In Outlook, you should now see a set of 10 appointments that were created that correspond with the dates and times in the data grid in the Appointment Viewer. Select a row by clicking on the gray area to the left of the data grid. When you have selected a row, the entire row will be highlighted an the Get Appointment button will become active. Choose the Get Appointment button and your screen should look like this:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG1.jpg" target="_blank"><img alt="Viewing appointments 1" height="351" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG1.jpg" width="600" /></a></p>
<p>You will note that the data in the AppointmentView dialog that pops up includes data that we do not have in the temp-table. That&#39;s because we fetched the appointment from the Exchange Server, not from the local cache. If you compare the appointment with the appointment properties for the corresponding appointment in Outlook, you will see that they match, so go ahead and edit the contents of the appointment in Outlook &#8211; something like this:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG2.jpg" target="_blank"><img alt="Outlook vs Appointment View" height="350" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG2.jpg" width="600" /></a></p>
<p>Now save and close the appointment in Outlook and give yourself a good 10 to 15 seconds so that Exchange has a chance to let the Client Access Server know about the change, then close the AppointmentView dialog by choosing the OK button, and open it again by choosing the Get Appointment button. The changes that you made in Exchange will now show up in the Appointment View dialog:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG3.jpg" target="_blank"><img alt="Updated Appointment" height="352" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG3.jpg" width="600" /></a></p>
<p>Finally, choose the Delete button in the AppointmentView dialog, and the appointment will be removed from the calendar:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG4.jpg" target="_blank"><img alt="Delete Appointment" height="350" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ApptViewOutlookBG4.jpg" width="600" /></a></p>
<p>If you go and look at the Deleted Items folder in Outlook, you will find the deleted appointment there.</p>
<h4>Get Appointment and Delete Appointment</h4>
<p>Close down the AppoinmentViewer and go back to OpenEdge Architect. If you go to line 100 of the code for the AppointmentViewer.cls class, you will find the code that fetches the appointment from the server. The code determines which line was highlighted in the data grid and obtains the ItemID from the data grid. It then uses that ItemID to create a new appointment object and the Appointment class calls GetAppointment in the constructor. GetAppointment, which is in line 70 of Appointment.cls simply calls the Java Web Service to get the information.</p>
<p>When it is done, the AppointmentView dialog is displayed with the contents of the Appointment object.</p>
<p>If you right-click on the AppointmentView (not AppointmentViewer) class in the Resources view and you choose &quot;Open With&#8230;-&gt;OpenEdge Visual Designer&quot;, you will get the AppointmentView dialog opened in OpenEdge Architect:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OEEditorApptView.jpg" target="_blank"><img alt="Appointment View Dialog" height="375" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OEEditorApptView.jpg" width="600" /></a></p>
<p>If you now double-click the Delete button, you will see the code that calls DeleteAppointment on the Appointment class. In the Appointment class, this code simply calls the DeleteAppointment operation on the Java Web Service.</p>
<h3>Summary</h3>
<p>That&#39;s it. The code that does all of this is fairly simple and straight-forward, once you understand what it is doing. Most of the complexity associated with this code is really around the communication between Java and the Exchange Server. The OpenEdge connectivity is reasonably simple because the Java code handles the complex work.</p>
<p>This is just the beginning of a prototype that we will expand on over the next few articles. I hope this has been helpful and interesting. Feel free to dig into the code that is supplied.&nbsp;</p>
<p>In the next article, we will dive into Exchange Impersonation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Exchange Web Services Example &#8211; Part 1 &#8211; Introduction and Set up</title>
		<link>http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/</link>
		<comments>http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/#comments</comments>
		<pubDate>Wed, 19 May 2010 05:24:26 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Exchange Web Services]]></category>
		<category><![CDATA[Exchange Web Services Example]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[4GL]]></category>
		<category><![CDATA[ABL]]></category>
		<category><![CDATA[EWS]]></category>
		<category><![CDATA[Exchange 2007]]></category>
		<category><![CDATA[Exchange 2010]]></category>
		<category><![CDATA[Exchange EWS]]></category>
		<category><![CDATA[Glassfish]]></category>
		<category><![CDATA[Glassfish V3]]></category>
		<category><![CDATA[Java 6]]></category>
		<category><![CDATA[Java EE 6]]></category>
		<category><![CDATA[Microsoft Exchange 2007]]></category>
		<category><![CDATA[Microsoft Exchange 2010]]></category>
		<category><![CDATA[Sample Code]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=657</guid>
		<description><![CDATA[A few weeks ago I wrote about my experiences starting out with the Microsoft Exchange Web Services API and on using the subscription API. In the second article, I said I would write a code walk through that shows how to do the stuff. I had thought of doing a complete walk through like the Dynamic OpenClient code that I did back in November last year, but I wasn't as busy back then as I am now, and I had the time to actually write up the example properly.

This is part 1 of a multi-part series that will cover the process of connecting to Microsoft Exchange Web Services, submitting requests to Exchange, receiving notifications from Exchange,  creating appointments, tasks, and e-mail, and using Exchange Impersonation. There will also be OpenEdge examples interspersed within it. Each part in the series (except this one) will have a downloadable zip file with the code in it that actually runs (at least in my environment) [...]
]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago I wrote about my experiences <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-starting-out/">starting out</a> with the Microsoft Exchange Web Services API and on using the <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/">subscription API</a>. In the second article, I said I would write a code walk through that shows how to do the stuff. I had thought of doing a complete walk through like the <a href="http://www.thesoftwaregorilla.com/2009/11/openedge-dynamic-openclient-java-example/">Dynamic OpenClient code that I did back in November last year</a>, but I wasn&#39;t as busy back then as I am now, and I had the time to actually write up the example properly.</p>
<p>I also know that a lot of people are very interested in this, based on the comments that I have have in off-line posts and in response to the survey for the OpenEdge client stuff, and I really don&#39;t want to neglect those of you that have asked about it.&nbsp;So I&#39;m compromising, and hopefully this will provide enough information for those that care.</p>
<p>This is part 1 of a multi-part series that will cover the process of connecting to Microsoft Exchange Web Services, submitting requests to Exchange, receiving notifications from Exchange, &nbsp;creating appointments, tasks, and e-mail, and using Exchange Impersonation. There will also be OpenEdge examples interspersed within it. Each part in the series will have a downloadable zip file with the code in it that actually runs (at least in my environment).&nbsp;</p>
<p>This post is going to talk about the series of posts and get you set up to start working with it. I am assuming very little, so if you find that things are pretty boring, or you know how to do something, feel free to skip ahead.</p>
<h3>Background</h3>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" target="_blank"><img align="left" alt="Exchange Web Services Subscriptions" height="275" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/04/Exchange-Web-Service-Subscriptions.jpg" width="400" /></a>In the article that I wrote on the <a href="http://www.thesoftwaregorilla.com/2010/04/exchange-web-services-subscriptions-and-notifications/" target="_blank">subscription API</a>, I walked through the way that subscription model works. Over the course of this series of articles, we are going to build the Java EWS Web Service and the Java HTTP Servlet.</p>
<p>We&#39;ll be running the code on our local workstations so that you don&#39;t need a Linux installation.</p>
<p>My interest is in exposing this API to OpenEdge, so I will also be providing some prototype code that shows the OpenEdge EWS API and the ABL Event Handling, although I expect that the majority of Java developers will not really be interested in this.</p>
<p>As my interest is in a service-oriented solution, I also have to concern myself with the complexities of things like Exchange Impersonation which allows a domain user to act on behalf of other users.</p>
<p>There are a lot of moving parts in this prototype so this article will focus on how you go about configuring your environment so you are ready to work through the examples I will be building in the remaining parts. At this point, I don&#39;t know how many parts there will be to this series. I know that I will have at least the following articles:</p>
<ul>
<li>Part 1 &#8211; Introduction and Setup (this article)</li>
<li><a href="http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-2-creating-appointments/">Part 2 &#8211; Creating an Appointment</a></li>
<li><a href="http://www.thesoftwaregorilla.com/2010/06/exchange-web-services-example-part-3-exchange-impersonation/" target="_blank">Part 3 &#8211; Using Exchange Impersonation</a></li>
<li>Part 4 &#8211; Setting up a Subscription</li>
<li>Part 5 &#8211; Getting User Availability</li>
<li>Part 6 &#8211; Creating a Task</li>
<li>Part 7 &#8211; Creating an E-Mail&nbsp;</li>
</ul>
<p>Needless to say, this list may change, but I know I need to cover these areas. There are likely to be more further down the line.&nbsp;</p>
<h3>Setup</h3>
<p>The rest of this article is dedicated to helping you get your environment set up so that you can work through the examples in the rest of the series. There are several things that you need to have running, and some of them I am going to take for granted that you have set up. For example, I am not going to walk through setting up your OpenEdge Architect environment or your Windows Server/Microsoft Exchange Server configuration. Those are your problems to resolve.</p>
<p>Later, when we get to Exchange Impersonation, I am going to walk you through how to set up an impersonation account, but that is not part of this initial set up. For this initial setup I will assume that you have a working Microsoft Exchange Server that you can get at <em>and play on it</em>. I suggest asking your Exchange admin to create you three or four recipient mailboxes for experimentation. I have four that I created:</p>
<ul>
<li>Freddie F. Frogg (froggf@example.com)</li>
<li>Harriet H. Hippo (hippoh@example.com)</li>
<li>Edward E. Elifant (elifante@example.com)</li>
<li>Gerald G. Gerarf (gerarfg@example.com)</li>
</ul>
<p>I also have an Exchange Impersonation account (ewsproxy@example.com) that I will be using for Exchange impersonation later. Don&#39;t worry about this account just yet. We&#39;ll get to it later.</p>
<p>So here is the list of software that you need to install to get things going:</p>
<ul>
<li><strong>Microsoft Exchange Server 2007</strong> &#8211; This code should work with the first 2007 commercial release. I ran and tested against 2007 Service Pack 2. There is nothing special in this code, though. I&#39;ll talk more about Exchange Configuration a little later.</li>
<li><strong><a href="http://java.sun.com/javaee/downloads/index.jsp" target="_blank">Java EE6 and Glassfish V3</a></strong> &#8211; This is a really simple installation process. All you need to do is set it up with its default parameters, and you should be good to go.</li>
<li><a href="http://www.soapui.org/" target="_blank"><strong>soapUI 3.5</strong></a> &#8211; You will need this to prove that the Web Service is working.</li>
<li><strong>OpenEdge 10.2B</strong> &#8211; installed on a client and on an AppServer. You will need a full AppServer license as the one that comes with OpenEdge Architect does not allow remote connections if my memory serves me right.</li>
<li><a href="http://www.eclipse.org/downloads/moreinfo/jee.php" target="_blank"><strong>Eclipse for Java EE</strong></a> &#8211; All the Java code is built inside Eclipse (3.5.2) with the Java EE IDE feature (1.2.2.2). I have the Web Tools Platform (3.1.1) installed as well. As I always install this with Java EE, I&#39;m not sure how much of this is used. There is also a Glassfish plugin for Eclipse EE that you really should install as it makes testing so much easier.</li>
<li><strong>OpenEdge Architect</strong> or Eclipse pointing to the OpenEdge Architect plugins.</li>
</ul>
<hr />
<p><em><strong>Update: </strong></em>Since I wrote this article, I have installed and tested Microsoft Exchange Server 2007 SP3 and Microsoft Exchange Server 2010. There is one minor modification you will need to make to the sourced code that accompanies this article for it to work with these. Line 132 of the source code file &quot;EWSTest.java&quot; that accompanies this article reads:</p>
<pre>ewsConn.setRequestProperty(&quot;Content-type&quot;, &quot;text/xml;utf-8&quot;);</pre>
<p>It may need to be changed to read:</p>
<pre>ewsConn.setRequestProperty(&quot;Content-type&quot;, &quot;text/xml;charset=utf-8&quot;);</pre>
<hr />
<p>Because so many of you are OpenEdge developers who have little to no experience with Java, and because this solution is predicated on a Java connection, I am going to spend some time walking through the setup of your Java install. Once we have walked through the Java install, I am going to point out how to resolve several problems that you are likely to encounter. So the rest of this article covers:</p>
<ul>
<li><a href="#javaglassfish">Installing Java EE6 and Glassfish</a></li>
<li><a href="#eclipseglassfish">Installing Eclipse EE and setting it up to work with Glassfish</a></li>
<li><a href="#certificates">Fixing certificate problems</a></li>
<li><a href="#folderperms">Changing the EWS folder permissions</a></li>
<li><a href="#quicktest">Running a quick test to prove it all works</a></li>
</ul>
<p>Let&#39;s get started.</p>
<h3><a name="javaglassfish"></a>Installing Java EE6 and Glassfish</h3>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/GlassfishLogin.jpg" target="_blank"><img align="left" alt="Glassfish Login" height="344" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/GlassfishLogin.jpg" width="400" /></a>The Java EE6 and Glassfish installation is a reasonably simple installation. Before you install Java EE6, though you need to make sure you have a Java SE6 JDK (not just JRE) installed. If you do not have an SE6 JDK installed, <a href="http://java.sun.com/javase/downloads/widget/jdk6.jsp" target="_blank">download</a> and install it. Accept all the defaults during the install and it will be installed in C:\Program Files\Java\jdk1.6.0_xx. If you are running a 64-bit version of Windows, the JDK will be installed in C:\Program Files (x86)\Java\jdk1.6.0_xx.</p>
<p>Once you have installed the JDK, go ahead and <a href="http://java.sun.com/javaee/downloads/index.jsp" target="_blank">download</a> and install the Java EE6 and Glassfish V3 Application Server. The install is also a fairly easy installation. Just make sure that as you go through the install, you point the code at the JDK that you just installed. Also, make sure you remember the password for the admin user because you will need it later. My own install of Glassfish is in C:\Apps\GlassfishV3.&nbsp;</p>
<p>Once you have installed Glassfish, a new program group will be added to your Programs folder called &quot;Java EE 6 SDK&quot;. Find this group, open it, and choose the &quot;Start Application Server&quot; option. Once the server has started (the command window will disappear), double click on the &quot;Administration Console&quot; and your browser will open the Glassfish Enterprise Server Administration Console.</p>
<p>Once the Administration Console has run, login using the admin user and password. Assuming your login works, things are as good as they can get for now and we will test it later. The next step is to install the Eclipse Enterprise Edition and configure it to work with Java.&nbsp;</p>
<p>Just before we do that, go back to the &quot;Java EE 6 SDK&quot; program group, and choose the &quot;Stop Application Server&quot; option.</p>
<h3><a name="eclipseglassfish"></a>Installing Eclipse EE and setting it up to work with Glassfish</h3>
<p>The next step is to <a href="http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/galileo/SR2/eclipse-jee-galileo-SR2-win32.zip" target="_blank">download</a> and install the Eclipse IDE for Java EE developers. This is a 190MB download so it takes a little while if you are on a slow line. Once you have downloaded it, install it by unzipping it into a directory (for me, C:\Apps\Eclipse\EclipseEE). Create a shortcut to the &quot;eclipse.exe&quot; file that is in the &quot;eclipse&quot; directory under your install path.</p>
<p>Now go ahead and start Eclipse for the first time. When you do, you will be prompted for a workspace. Choose a path to a new, empty directory. You will then be presented with the &quot;eclipse Java EE ide&quot; welcome screen. Click the &quot;Workbench&quot; icon in the top right corner of the screen.</p>
<p>The next thing to do is make sure that you have the latest patches. From the Help menu, choose &quot;Check for Updates&quot;.</p>
<h4>Setting the default Java Runtime Environment</h4>
<p>The next step is to set up Eclipse to use the Java JDK that you installed a little earlier. From the Eclipse &quot;Window&quot; menu, choose &quot;Preferences&quot; (the last menu option). In the tree on the right of the Preferences window, expand the &quot;Java&quot; node and select &quot;Installed JREs&quot;.&nbsp;</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseJREConfig.jpg" target="_blank"><img alt="Eclipse JRE Configuration" height="493" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseJREConfig.jpg" width="600" /></a></p>
<p>Choose the &quot;Add&#8230;&quot; button on the right side of the &quot;Installed JREs&quot; pane and you will be presented with a dialog entitled &quot;Add JRE&quot;. Select &quot;Standard VM&quot; in the selection list and choose the &quot;Next &gt;&quot; button.</p>
<p>On the &quot;JRE Definition&quot; wizard page, select the &quot;Directory&#8230;&quot; button and navigate to the install directory for the JDK that you installed above (normally&nbsp;C:\Program Files\Java\jdk1.6.0_xx). Choose the OK button and the Finish button on the wizard page and you will be returned to the Preferences page.</p>
<p>In the list of installed JREs, make sure that the new JDK that you just added has a check mark to the left of it so that it becomes the default JRE for Eclipse. Choose the OK button for the Preferences page, and we are done with the JDK setup.</p>
<h4>Setting up Eclipse to work with Glassfish</h4>
<p>The next step is to configure Eclipse so that it is easy to deploy code to the Glassfish server. At the bottom of the Eclipse window is a tab entitled &quot;Servers&quot;. Select this tab. Right-click inside the pane for the Servers tab, and select &quot;New-&gt;Server&quot;. Just below the &quot;Server&#39;s host name&quot; prompt is a hyperlink entitled &quot;Download additional server adapters&quot;. Select this link.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish1.jpg" target="_blank"><img alt="Eclipse Glassfish Server downloads" height="502" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish1.jpg" width="600" /></a></p>
<p>In the &quot;Install New Extension&quot; dialog, select &quot;Glassfish Java EE5, Java EE6&quot; and choose next. Complete the wizard, and the Glassfish adapter will be installed. Once it is installed, you will be presented with the New Server dialog.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish2.jpg" target="_blank"><img alt="Eclipse Glassfish New Server Dialog" height="502" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish2.jpg" width="600" /></a></p>
<p>Make sure you select the &quot;Glassfish V3 Java EE 6&quot; option from the Glassfish folder, and choose the &quot;Next &gt;&quot; button.</p>
<p><img alt="New Server Wizard page 2" height="561" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish3.jpg" width="500" /></p>
<p>On the next page, select the JDK JRE that you set up earlier and make sure to point the Application Server Directory to your Glassfish install directory. Note that under the directory that you installed Glassfish, there is a subdirectory called &quot;glassfish&quot;. You need to be pointing at that directory.</p>
<p><img alt="New Server Wizard page 3" height="561" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish4.jpg" width="504" /></p>
<p>On the next page of the wizard, you are asked for the user name and password for the administrator. As this is a development machine, go ahead and specify it and check the &quot;Preserve Sessions across Redeployment&quot; flag. You can then go ahead and choose the Finish button and the New Server Wizard will close. In the Servers tab, you should now see a entry entitled &quot;GlassFish v3 Java EE 6 at localhost&quot;.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish5.jpg" target="_blank"><img alt="Eclipse EE Window with Glassfish Admin Console" height="493" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EclipseGlassfish5.jpg" width="600" /></a></p>
<p>Select the server that you just added, and choose the green and white arrow button in the toolbar at the top right of the &quot;Servers&quot; pane. Eclipse will automatically switch to the Console tab and you should see output like the following in that pane:</p>
<pre>Waiting for DAS to start ..........
Started domain: domain1
Domain location: C:\Apps\glassfishv3\glassfish\domains\domain1
Log file: C:\Apps\glassfishv3\glassfish\domains\domain1\logs\server.log
Admin port for the domain: 4848
Command start-domain executed successfully.</pre>
<p>If you now switch back to the &quot;Servers&quot; pane, right-click on the &quot;GlassFish v3 Java EE 6 at localhost&quot; line, and choose &quot;GlassFish Enterprise Server -&gt; View Admin Console&quot;, you should end up with a window as above. Your GlassFish Server now works from inside your Eclipse EE environment.</p>
<h3><a name="certificates"></a>Fixing Certificate Problems</h3>
<p>The first problem you are likely to run into with Exchange Server is a certificate related issue with your Exchange Web Server. To figure out if this is a problem, make sure that you can get at the Exchange Web Services WSDL. The Exchange Web Service is installed by default on the Client Access Server (CAS). Ask your Exchange Administrator for the name of this machine. The URL to the WSDL is:</p>
<pre>https://exchange.cas.server/ews/Services.wsdl</pre>
<p>If you type this URL into Microsoft Internet Explorer, you may get a certificate error as shown in this screenshot. If you get this error, you need to import this certificate into your browser&#39;s certificate store and you need to add it to the Glassfish certificate store, too.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateError.jpg" target="_blank"><img alt="Certificate Error" height="450" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateError.jpg" width="600" /></a></p>
<h4>Importing the certificate into the browser&#39;s certificate store</h4>
<p>You need to choose the &quot;Continue to this website&quot; link if you see this and when you do you will be prompted to log in. After logging in with your domain username and password, you will see a page full of XML with a certificate error in the title bar. Right-click in the pane that contains the XML, and choose &quot;Properties&quot;. You will be presented with a dialog with a &quot;Certificate&quot; button at the bottom right. Choose the &quot;Certificate&quot; button and you will arrive at the following dialog:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/InstallingCertificate1.jpg" target="_blank"><img alt="Certificate Installation" height="465" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/InstallingCertificate1.jpg" width="600" /></a></p>
<p>Your certificate will likely have different information in it. What I am going to recommend right now is not the way that I would do this in production. Right now I am working around a problem that you need to deal with to be able to make this stuff work. In production, you really do need to set up a trusted certificate authority within the organization, but that is way beyond the scope of this article.</p>
<p>The next step is to choose the &quot;Install Certificate&quot; button above. This will start the &quot;Certificate Import Wizard.&quot; You will need to install this certificate in the &quot;Trusted Root Certification Authorities&quot; Certificate Store. Page 2 of the Certificate Import Wizard contains a radio-set that allows you to select where to install the certificate. Choose the &quot;Place certificates in the following store&quot; option and then choose the &quot;Browse&#8230;&quot; button. You will then be presented with a dialog that allows you to select the certificate store.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/InstallingCertificate2.jpg" target="_blank"><img alt="Trusted Root Certification Authority" height="467" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/InstallingCertificate2.jpg" width="600" /></a></p>
<p>Choose the &quot;Trusted Root Certification Authorities&quot; entry and choose the OK button. Finish going through the wizard and you will eventually be presented with the following dialog (or something a lot like it):</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateWarning.jpg" target="_blank"><img alt="Security Warning" height="409" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateWarning.jpg" width="496" /></a></p>
<p>Choose the &quot;Yes&quot; button and the certificate will be installed for you. Close down your browser, open it up again, and try and navigate to the URL above again. This time you should not see the Certificate Error message that we saw above and you should be able to log in and get to the WSDL.&nbsp;</p>
<h4>Exporting the certificate</h4>
<p>We&#39;re not done with the certificates yet, though. The next thing we have to do is export the certificate from the certificate store so we can load it into Glassfish&#39;s certificate store. With Internet Explorer open, choose &quot;Internet Options&quot; from the &quot;Tools&quot; menu. When the Internet Options dialog opens, select the &quot;Content&quot; tab as below:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateOptions.jpg" target="_blank"><img alt="Internet Options - Certificates" height="450" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateOptions.jpg" width="600" /></a></p>
<p>Choose the &quot;Certificates&quot; button in the middle of the dialog and you will be presented with the &quot;Certificates&quot; dialog. Choose the &quot;Trusted Root Certification Authorities&quot; tab and scroll down and select your certificate from the certificate store:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/TrustedCertStore.jpg" target="_blank"><img alt="Trusted Certificate Store" height="448" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/TrustedCertStore.jpg" width="600" /></a></p>
<p>Now choose the &quot;Export&quot; button as you will need to create a certificate file that can be imported into the Glassfish certificate store. The &quot;Certificate Export Wizard&quot; will now be presented and you should choose the &quot;Next&quot; button, making sure to select the &quot;DER encoded binary X.509 (.CER)&quot; option:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateExport.jpg" target="_blank"><img alt="Certificate Export" height="451" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/CertificateExport.jpg" width="600" /></a></p>
<p>Finish off the wizard by selecting a destination in which to store the certificate file.&nbsp;</p>
<h4>Importing the certificate into the Glassfish certificate store</h4>
<p>To import the certificate into the Glassfish certificate store, open a command line prompt and change directories to the directory in which Glassfish is installed. I installed it at C:\Apps\Glassfishv3. Once in that directory, issue the following command (I am assuming that the Java/bin root directory is in your path):&nbsp;</p>
<pre>cd glassfish\domains\domain1\config
keytool -importcert -v -trustcacerts -keystore cacerts.jks -file c:\&lt;pathtocertificate&gt;\&lt;certificatefile&gt;.cer</pre>
<p>You will be prompted for a password. If you have never changed the password for the certificate store, the password defaults to &quot;changeit&quot;. Import the certificate into the store, and you should be almost ready to start using Glassfish to communicate with the Exchange Web Service.</p>
<h3><a name="folderperms"></a>Change EWS folder permissions</h3>
<p>The next step to making this code function is to change the permissions on the EWS folder on the Microsoft Exchange Client Access Server to which you will be connecting. This requires administrative privileges on the server.</p>
<hr />
<p><strong>Warning:</strong> I do not recommend that you do this on your production Exchange Client Access Server, especially if it is an internet-facing server. Making this change significantly changes the security level of your Exchange server and could make it vulnerable to attack. I have a test Exchange server specifically set up for this.</p>
<hr />
<p>Run the &quot;Internet Information Services (IIS) Manager&quot; tool (also accessible from Server Manager as shown below. Assuming your server is named EXCHANGESERVER, expand the EXCHANGESERVER node. Under it you will find a &quot;Sites&quot; node. Expand that and the &quot;Default Web Sites&quot; node under it. Under that you will find an &quot;EWS&quot; folder. Select that folder.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EWSPermissions1.jpg" target="_blank"><img alt="Server Manager" height="452" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EWSPermissions1.jpg" width="600" /></a></p>
<p>In the &quot;/EWS Home&quot; pane that now opens, there is an icon for &quot;Authentication&quot; in the &quot;IIS&quot; group of icons (In the above screenshot, it is the third icon from the bottom on the left of the pane). Double-click this icon and the pane will change to look like this:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EWSPermissions2.jpg" target="_blank"><img alt="Changing EWS permissions" height="453" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/EWSPermissions2.jpg" width="600" /></a>&nbsp;.</p>
<p>In the Authentication pane (the new pane) there is one item that you need to change. Click on the line that says &quot;Basic authentication&quot; and then right-click on it. This line should currently have the word &quot;Disabled&quot; in the &quot;Status&quot; column. In the popup menu that now displays, select &quot;Enable&quot;.</p>
<p>That should do it. The configuration changes you have now made should work for you.</p>
<h3><a name="quicktest"></a>Running a quick test to prove it works</h3>
<p>As I mentioned earlier in this post, you are going to need soapUI to be able to do any testing, so if you have not done so, <a href="http://www.soapui.org/" target="_blank">now would be a good time to download and install soapUI</a>. Once you have done that, the other thing you will need is a zip file that you can <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ewstest.zip">download here</a> that contains a sample Web Service to test the communication with Exchange Web Server.</p>
<p>Once you have the zip file downloaded, start Eclipse EE. In the &quot;Project Exporer&quot; pane at left, right-click and from the context menu select &quot;Import -&gt; Import&#8230;&quot; and the &quot;Import&quot; dialog below will appear. Expand the &quot;General&quot; folder and select &quot;Existing Projects into Workspace&quot; and choose the &quot;Next &gt;&quot; button.</p>
<p><img alt="Import Project" height="550" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ImportProject1.jpg" width="525" /></p>
<p>On the next page of the Import wizard, choose the &quot;Select archive file&quot; radio-set and browse to the zip file that you just downloaded. In the &quot;Projects:&quot; selection list, make sure that EWSTest is checked and choose the Finish button.</p>
<p><img alt="Import Project 2" height="615" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/ImportProject2.jpg" width="525" /></p>
<p>If all is good, there will be no little red and white &quot;x&quot; on the EWSTest project. If there is, it&#39;s probably because the JDK version that you have installed is different from the one I am using. To fix that, right-click on the EWSTest project and select &quot;Properties&quot; from the context menu. In the Properties window, select the &quot;Java Build Path&quot; property set and choose the &quot;Libraries&quot; tab. Select the &quot;JRE System Library&quot; and then choose the Remove button. Now choose the &quot;Add Library&#8230;&quot; button, select &quot;JRE System Library&quot; in the &quot;Add Library&quot; wizard page and choose next. &nbsp;Make sure the &quot;Workspace default JRE&quot; is selected and choose the &quot;Finish&quot; button. Choose OK on the Properties page and the little red and white &quot;x&quot; should disappear.</p>
<p>Now that you have a properly compiled version of EWSTest project, you need to start your Glassfish server if it is not already running. Drag the EWSTest project from the Project Explorer pane to the &quot;GlassFish v3 Java EE 6 at localhost&quot; entry in the Server pane. If you expand the Glassfish node in the Server pane, you should now see &quot;EWSTest [Synchronized]&quot; under the GlassFish node as follows:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/DeployedProject.jpg" target="_blank"><img alt="Deployed Project" height="518" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/DeployedProject.jpg" width="600" /></a></p>
<p>Now comes time to test it all out. &nbsp;Make sure you leave Eclipse running &#8211; we need that Application Server. Now go and start soapUI, and right-click on the &quot;Projects&quot; node in the Navigator. From the context menus choose &quot;New soapUI Project&quot;.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUINewProject.jpg" target="_blank"><img alt="SoapUI New Project" height="449" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUINewProject.jpg" width="599" /></a></p>
<p>In the &quot;Initial WSDL/WADL:&quot; prompt, type the following:</p>
<pre>http://localhost:8080/EWSTest/EWSTestService?wsdl</pre>
<p>Choose the OK button and soapUI will create a project for you called EWSTestService. Expand the CreateAppointment node and under it there is a Request 1 node. Double-click the Request 1 node and fill in the contents of the XML pane on the left.</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUIExecutedCall.jpg" target="_blank"><img alt="SoapUI Executed Call" height="525" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/SoapUIExecutedCall.jpg" width="700" /></a></p>
<p>The node in the XML document need to be completed as follows:</p>
<ul>
<li>ExchangeServer &#8211; The fully qualified domain name of your Exchange Client Access Server that is running your Exchange Web Service;</li>
<li>DomainUser &#8211; Your test recipient account qualified with a domain name &#8211; so DOMAIN\user;</li>
<li>DomainPassword &#8211; Your test recipient account&#39;s password;</li>
<li>Description &#8211; A description to appear at the top of the appointment;</li>
<li>Location &#8211; A location where the meeting should take place;</li>
<li>StartDateTime &#8211; A date and time at which the appointment should start in the format yyyy-mm-ddThh:mm:ss (the T is required);</li>
<li>EndDateTime &#8211; A date and time at which the appointment should end in the same format as the StartDateTime. Note that if this date and time is less than the start, you will get a &quot;Bad post&#8230; 500&quot; error.</li>
</ul>
<p>Once you have filled all of these fields out, choose the green arrow button &#8211; tooltip: &quot;Submit request to specified endpoint URL&quot; &#8211; and the call will execute. If it is successful, you will get a SOAP document in the right-hand pane with a &quot;CreateAppointmentResponse&quot; node that includes a &quot;return&quot; node with a CDATA node inside it. The return node is fairly long and includes an &quot;Item&quot; node with &quot;ID&quot; and &quot;ChangeKey&quot; attributes.</p>
<p>Of course, your ultimate test is to login to the test user&#39;s account and start Outlook for him. You can celebrate when you see the appointment created:</p>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OutlookAppointment.jpg"><img alt="Outlook showing appointment" height="397" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OutlookAppointment.jpg" width="600" /></a></p>
<p>If you double-click the appointment, you will note that the details have been filled in exactly as you would expect:</p>
<p><img alt="Appointment details" height="500" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2010/05/OutlookAppointment1.jpg" width="594" /></p>
<hr />
<p><strong>Caution:</strong> The test code that I included here could cause you some trouble if you try and create appointments in different users&#39; calendars without restarting the Glassfish server in-between. It won&#39;t do that and we&#39;ll get into why in one of the next posts. Just be careful not to use this to mess up real calendars inadvertently.</p>
<hr />
<h3>Summary</h3>
<p>At this point you have a working Exchange Web Services call happening from Java. This is the first step. In the next part to this series, we will walk through the code that actually creates the appointment to understand what it is doing. That code will be commented to help explain what it does.</p>
<p>Please feel free to leave any comments you may have and please let me know if you run into problems with the instructions that I have given here.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2010/05/exchange-web-services-example-part-1-introduction-and-set-up/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
	</channel>
</rss>

