<?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; 4GL</title>
	<atom:link href="http://www.thesoftwaregorilla.com/tag/4gl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.thesoftwaregorilla.com</link>
	<description>The Software Gorilla</description>
	<lastBuildDate>Thu, 08 Jul 2010 07:23:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<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>6</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>22</slash:comments>
		</item>
		<item>
		<title>OpenEdge Dynamic OpenClient Java Example</title>
		<link>http://www.thesoftwaregorilla.com/2009/11/openedge-dynamic-openclient-java-example/</link>
		<comments>http://www.thesoftwaregorilla.com/2009/11/openedge-dynamic-openclient-java-example/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 02:27:48 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[OpenClient]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[4GL]]></category>
		<category><![CDATA[ABL]]></category>
		<category><![CDATA[Application Server]]></category>
		<category><![CDATA[AppServer]]></category>
		<category><![CDATA[AVM]]></category>
		<category><![CDATA[Dynamic OpenClient]]></category>
		<category><![CDATA[Java OpenClient]]></category>
		<category><![CDATA[OpenEdge OpenClient]]></category>
		<category><![CDATA[Progress]]></category>
		<category><![CDATA[Progress AppServer]]></category>
		<category><![CDATA[Progress OpenClient]]></category>
		<category><![CDATA[PVM]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=90</guid>
		<description><![CDATA[In a previous post, I said I would post an example that demonstrates the use of the OpenEdge Dynamic OpenClient. Well here is the Java version of it. This post is an extensive discussion of the example and how it is structured. Enjoy.]]></description>
			<content:encoded><![CDATA[<p>In a previous post, I said I would post an example that demonstrates the use of the OpenEdge Dynamic OpenClient. Well <a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/11/DynamicOpenClient.zip">here is the Java version of it</a>.</p>
<p>It took me a while to get this done, not so much because of the code, but because the documentation that accompanies it is pretty extensive and I have been in the middle of some significant career changes.</p>
<p>This post is long primarily because I walk through the highlights of the what the code does and how this bolsters what I was saying in my earlier post.</p>
<p>Inside the zip file are 2 zip files and&nbsp;3 PDF files:</p>
<ul>
<li><strong>DynamicOpenClientJar.zip</strong> is the compiled version of the code. It contains a jar file, the input.xml, a batch file, and the Progress source code.</li>
<li><strong>DynamicOpenClientJar.pdf</strong> contains setup instructions to set it up and run it.</li>
<li><strong>DynamicOpenClientSrc.zip</strong> is the source code.</li>
<li><strong>DynamicOpenClientSrc.pdf</strong>&nbsp;contains the instructions that&nbsp;that tells you how to set&nbsp;the source code up to work with Eclipse.</li>
<li><strong>DynamicOpenClient.pdf </strong>is a detailed tour of the code and describes how it works.</li>
</ul>
<h4>This is Sample Code</h4>
<p>Before you dig into the code and say &quot;Wow!! This code sucks!!&quot; it is important to understand that this is sample code. There are a lot of things about it that are ugly. Some of the object model needs serious refining. There are cleaner ways of doing the XML&nbsp;parsing and it is nowhere near as defensive as it should be. There are those who believe that bad code samples lead to bad code in production, but there is another line of thought that goes that if you don&#39;t recognize those bad examples, you should not be coding to start with. The point with this code is that it demonstrates concepts and that&#39;s what it was intended to do.</p>
<h4>Code Limitations</h4>
<p>For the sake of brevity, I&nbsp;have deliberately not covered stuff like supporting supporting ProDataSets and all of the different Progress data types.&nbsp;I have covered the most common ones and temp-tables. ProDataSets are really an extension of temp-tables and you can feel free to go and look at the code in a generated proxy to see how they work. I&nbsp;also stopped short of supporting the building of temp-tables from an input XML&nbsp;file. The extra code to do this did not seem like it would really add that much to the example. This code example also does not support persistent procedures because they are a lot more complicated than this code will allow.</p>
<h4>Set it up and try it</h4>
<p>Having said all of that, I wanted to spend some time in this post elaborating on the comments that I made in the earlier post about why Dynamic OpenClient is such a powerful technology, using the example code that I am presenting here. So I am going to assume for the rest of this article that you have at least set up and run the example and that you have the source code accessible to follow along.</p>
<h4>How it Works</h4>
<p><a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/08/Sequence-Diagram.jpg" target="_blank"><img align="right" alt="Dynamic Open Client Utility Sequence Diagram - Click for full size" border="0" height="192" hspace="2" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/08/Sequence-Diagram.jpg" vspace="2" width="300" /></a>The Dynamic Open&nbsp;Client code takes an XML&nbsp;file and parses it for AppServer connection parameters, R-Code signatures and calls that need to be made to the Progress/OpenEdge R-Code files. The sequence diagram at right (click on it for a full-size image)&nbsp;shows the process.</p>
<p>Once the XML file has been parsed, the utility executes each of the calls and serializes the results of the call&#39;s execution to an internal XML document. Once all the calls have been executed and serialized, the results are written out to another XML file that is specified in the input.xml file. More information on the XML file&#39;s format is in the DynamicOpenClient.pdf file.</p>
<h4>The Main Components</h4>
<p>To understand how this utility works, you need to understand the core of the class model. So let me start by dividing the class model into its major areas.</p>
<p>You can pretty much ignore the <em>com.tsg.common</em> project.&nbsp;It contains&nbsp;an interface -&nbsp;<em>INamedItem</em> &#8211; used&nbsp;by a few classes that&nbsp;simply has a getName() method declaration.&nbsp;<em>INamedItem</em> is&nbsp;implemented by some of the classes in the <em>com.tsg.dynamicopenclient</em> project. This interface is specifically used for objects that may be stored in a <em>com.tsg.common.collections.OrdinalList</em> &#8211; a specialized list that is ordinal like an ArrayList, but expects uniquely named items in the list.&nbsp;<em>OrdinalList</em> is used&nbsp;for things like field lists and parameter lists where the fields need to be in a specific order, but the names have to be unique.</p>
<p>The <em>com.tsg.dynamicopenclient</em> project contains three packages:<a href="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/08/Class-Model.jpg" target="_blank"><img align="right" alt="Dynamic Open Client Sample Utility Class Model" height="200" hspace="2" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/08/Class-Model.jpg" vspace="2" width="300" /></a></p>
<ul>
<li><em>com.tsg.dynamicopenclient </em>- This package contains&nbsp;the code that does most of the work;</li>
<li><em>com.tsg.dynamicopenclient.data </em>- This package&nbsp;contains the&nbsp;class hierarchy for parameter and other&nbsp;data element&nbsp;definitions;</li>
<li><em>com.tsg.dynamicopenclient.valueholders </em>- This package contains&nbsp;the class hierarchy for all the value holders that&nbsp;are used to contain&nbsp;the values of input and&nbsp;output parameters.</li>
</ul>
<h5>Data Types</h5>
<p>One of the most&nbsp;important aspects of the&nbsp;communication between the&nbsp;OpenClient and the AppServer, is the mapping of data types from Java to Progress. To&nbsp;make sure that this is done consistently, there is a&nbsp;<em>DataType</em> <em><strong><a href="http://java.sun.com/docs/books/tutorial/java/javaOO/enum.html" target="_blank">enumeration</a></strong></em> in&nbsp;<em>com.tsg.dynamicopenclient</em>.&nbsp;If you have not worked with Java 5, enumerations may be a new concept to you and this one is particularly more so than others. An enumeration is a great way to deal with hard-coded constants and it is particularly useful where a map of constants is necessary. In this&nbsp;particular case we have to map an OpenClient numeric constant to a string representation of the data type, a Java class that can be used to map to that type and a valueholder class that can be used to contain the Java type. The following definition of the INTEGER data type demonstrates the mechanism:</p>
<pre>INTEGER
  (Parameter.PRO_INTEGER, // Progress numeric constant
   Parameter.PRO_INTEGER_NAME, // Progress character constant
   &quot;java.lang.Integer&quot;, // Java class to be used to map
   &quot;com.tsg.dynamicopenclient.valueholders.IntegerValueHolder&quot;),&nbsp;// Dynamic OpenClient valueholder
</pre>
<p>The DataType enumeration has several methods associated with it to retrieve a constant based on the string name of the data type or to obtain the Java class, value holder class&nbsp;or Progress data type constant. It also contains code that will instantiate an object of either the Java class to contain the data type or the value holder. This enumeration truly is at the core of the code.</p>
<h5>Data Elements</h5>
<p>The <em>com.tsg.dynamicopenclient.data</em> package contains a set of classes that define the behavior of data elements. A data element is any item that has a name and a datatype associated with it. Thus, fields and parameters are all data elements. Data elements only store the definition of the element. They do not store the value. The value is stored in a <a href="#ValueHolder">value holder</a>. The abstract base <em>DataElement</em> class contains all the behavior for parsing parameter and field definition information from an XML node.</p>
<p>The <em>Parameter</em> class extends it by providing support for parameter modes (INPUT, INPUT-OUTPUT and OUTPUT)&nbsp;which are mapped in&nbsp;an enumeration called <em>ParameterMode</em> in <em>com.tsg.dynamicopenclient</em>.</p>
<p>The <em>TempTableParameter</em> class extends the <em>Parameter</em> class further by providing support for parsing temp-table definitions from the source code and supporting the construction of ProDataGraphMetaData objects that are used to build the ProDataGraph to transport temp-tables between AppServer and client.</p>
<h5><a name="ValueHolder"></a>Value Holders</h5>
<p>The <em>com.tsg.dynamicopenclient.valueholders</em> package contains a set of classes and an interface that are used to standardize the way that data types are dealt with. Looking at the class model, the value holder hierarchy is to the right of the diagram. This hierarchy leverages the concept of <strong><em><a href="http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf" target="_blank">generics</a></em></strong> that was introduced in Java 5.</p>
<p>The <em>IValueHolder</em> interface is the base of the hierarchy and the <em>ValueHolder</em> abstract class contains the generic behavior for value holders. These classes provide support for the Progress UNKNOWN value as well as reasonable default values that match the Progress defaults for its data types.</p>
<p>Value holders are used to set the value of input parameters and to contain the&nbsp;values of output parameters.</p>
<h5>DynamicOpenClient Class</h5>
<p>The DynamicOpenClient class in <em>com.tsg.dynamicopenclient</em> contains the <em>main()</em> method&nbsp;- the entry point to the utility. It starts out by parsing the parameters to determine where the XML file is that contains the signatures and input parameters for the calls. The input.xml file&#39;s structure is detailed in the DynamicOpenClient.pdf file that accompanies the source code. In essence, though, there are 4 types of nodes that are important:</p>
<ul>
<li><strong>dynamicoc</strong> &#8211; This is the root node for the document and it contains an OutputFile attribute that has the name of the file that should be used for the results of the calls.</li>
<li><strong>appserver</strong> &#8211; This node contains the signature and call nodes and a set of attributes that define the connection parameters for the AppServer.</li>
<li><strong>signature</strong> &#8211; This node contains the signature of a call that will be executed against the AppServer. The signature node may contain a set of parameter nodes which will be all of the parameters for a procedure. These parameters must be specified in the order that they are specified in the ABL source code. If the parameter&#39;s&nbsp;DataType attribute&nbsp;is TABLE, the node will contain child nodes that are the field and indexes for the table.</li>
<li><strong>call</strong> &#8211; This node contains a list of calls that need to be executed against the AppServer. Each of them should refer (by means of the Procedure attribute) to a previously specified signature. call Nodes may contain subordinate parametervalue nodes that reference a parameter in the signature by name and specify the value to be used as the input value for that parameter.</li>
</ul>
<p>The following code extract&nbsp;comes from&nbsp;the <em>main()</em> method.</p>
<pre>//Extracted from <strong>main()</strong> method.
//

//Instantiate the CallManager
CallManager manager = CallManager.getInstance();

//Parse the XML file.
try {
	parse(fileName);
}
catch (Exception e) {
	System.out.println(e.getMessage());
	return;
}
.
.
.
Iterator&lt;Call&gt; iter = manager.iterator();
while (iter.hasNext()) {
	Call call = iter.next();&nbsp; //Get the call
	call.executeCall();&nbsp;&nbsp; //Execute the call
	outRoot.appendChild(call.serializeResults(outputDocument));
	iter.remove();
}
.
.
.
try {
	writeResults();&nbsp; // Write the XML results file out to disk.
}
catch (Exception e) {
	System.out.println(e.getMessage());
	return;
}</pre>
<p>Before doing anything else, the code instantiates the Singleton CallManager to hold onto all the data that will be parsed from the XML file.</p>
<p>The <em>main() </em>method calls the static <em>parse() </em>method with the name of the XML file to be parsed. This method parses the XML document and iterates through the four element nodes mentioned above. It also sets up a DOM document that will be used as the output document for the results of the calls.</p>
<p>For each element, it instantiates an object of the appropriate class and passes it the XML node that needs to be instantiated. This&nbsp;object is then added to the CallManager where it will be retrieved later.</p>
<pre>//Extracted from <strong>parse()</strong> method.
//
Node elementNode = null;
while((elementNode = iterator.nextNode()) != null) { // Loop through elements

	// Handle root node.
	if (elementNode.getNodeName().equalsIgnoreCase(XMLStrings.INPUT_ROOT_NODE.toString())) { 	

		// Setup the output file.
		String attrValue = XMLStrings.getAttribute(elementNode, XMLStrings.OUTPUT_FILE_ATTR.toString());
		if (attrValue != null) {
			outputFileName = attrValue;
		}
	}

	// Handle appserver node
	if (elementNode.getNodeName().equalsIgnoreCase(XMLStrings.APPSERVER_NODE.toString()) ) {
		manager.setAppServerConnection(new AppServerConnection(elementNode));
	}

	// Handle signature node
	if (elementNode.getNodeName().equalsIgnoreCase(XMLStrings.SIGNATURE_NODE.toString()) ) {
		manager.setSignature(new Signature(elementNode));
	}

&nbsp;	// Handle call node
	if (elementNode.getNodeName().equalsIgnoreCase(XMLStrings.CALL_NODE.toString()) ) {
		manager.addCall(new Call(elementNode));&nbsp;
 	}
}</pre>
<p>The <em>CallManager</em> implements the <em>Iterable</em> interface for the <em>Call</em> class.&nbsp;Back in the <em>main()</em> method, the next thing we do is iterate through all&nbsp;of the <em>Call</em> objects in the <em>CallManager</em> and we execute the call. This is where the real work happens and a description of it is below. When execution is complete, the parameter values will have been stored in the <em>Call</em> object and a call to <em>serializeResults()</em> will return an XML node that can be appended to the output document. The <em>Call</em> object is then deleted from the list of calls to free up the memory that any temp-tables will occupy.</p>
<p>Once all the calls have been executed, a call is made to writeResults() which writes the output XML document to disk.</p>
<h4>Executing the Call</h4>
<p>A&nbsp;call&nbsp;is actually executed by&nbsp;a call to&nbsp;<em>executeCall()</em>&nbsp;on the <em>Call</em> object. The <em>executeCall()</em> method simply builds a parameter array, calls the <em>runProcedure() </em>method on the AppServerConnection object, builds the output parameter value set and handles any exceptions. The thing that makes this client dynamic is the code in <em>buildParamArray()</em> and <em>buildOutputValues()</em>.</p>
<h5>buildParamArray()</h5>
<p>In order to make a call to the AppServer, the OpenClient needs a procedure name to call and a parameter array (<em>com.progress.openABL.javaproxy.ParamArray</em>) for the call. The parameter array needs to contain a full description of each parameter as well as the value to be set for the parameter. The <em>Call</em> object has a procedure name and it has the values of the input parameters. The name of the procedure maps to a <em>Signature</em> object which can be obtained from the <em>CallManager</em> and it contains the definitions of all of the parameters that are needed for the call. Thus, <em>buildParamArray()</em> obtains the <em>Signature</em> object and builds a <em>ParamArray</em> object with each of the parameter definitions in the <em>Signature</em> object. As it attempts to add each parameter to the <em>ParamArray</em>, it obtains a IValueHolder object to contain the parameter&#39;s input or output parameter value.&nbsp;It then&nbsp;checks for a corresponding input value in the <em>Call</em> object. If it finds a corresponding value it sets the input value in the <em>ParamArray</em> from this value. This is how the <em>Call</em> information in the XML file can specify the parameter values by name in any order and only specify the ones that have values associated with them.</p>
<pre>//Extracted from <strong>buildParamArray()</strong> method.
//

CallManager manager = CallManager.getInstance();
Signature sig = manager.getSignature(getProcedureName()); //Get the signature for this call
if (sig == null) {
	throw new DynamicOpenClientException(...);
}
ParamArray params = new ParamArray(sig.getParameterCount()); //Instantiate a ParamArray object

int idx = 0;

// Iterate through all the parameters in the signature.
for (Parameter param : sig) { 

	// Instantiate an IValueHolder for this data type.
	IValueHolder&lt;?&gt; valueHolder = DataType.getValueHolder(param.getDataType());
	paramValues.add(valueHolder); // Put the value holder into the paramValues list.

	// If we can find a parameter value that was set for this call,
	// set the value of the IValueHolder to the input value.
	if (inputValues.containsKey(param.getName())) {&nbsp;
		valueHolder.setObject(inputValues.get(param.getName()));
	}</pre>
<p>Now that the data we&nbsp;need is available (ie, the parameter type information and input values have been set), we can go about setting the values, but we need to treat the&nbsp;TABLE and TABLE-HANDLE types differently from the the other data types. The reason is that they need a ProDataGraph and its metadata. The code for setting the values is therefore as follows:</p>
<pre>Object value = null;
switch(param.getDataType()) {
	case TABLE:
	case TABLE_HANDLE:
		TempTableParameter ttParam = (TempTableParameter) param;
		ProDataGraphValueHolder graphHolder = (ProDataGraphValueHolder) valueHolder;
		ProDataGraphMetaData metaData = null;
		switch(param.getMode()) {
			case OUTPUT:
				// For a table we need the table structure. TABLE_HANDLE needs null.
				if (param.getDataType() == DataType.TABLE) {
					metaData = ttParam.getProDataGraphMetaData();
				}
				break;
			default:
				value = graphHolder.getProDataGraph();
				metaData = graphHolder.getProDataGraph().getMetaData();
				break;
		}

		// Add a parameter to the ParamArray with the appropriate value.
		params.addParameter(idx, value, ttParam.getMode().getModeCode(),
			ttParam.getDataType().getTypeCode(),
			ttParam.getExtent(),
			metaData);
		break;
	default:
		// Now get the object from the IValueHolder that has the value in it.
		value = valueHolder.get(); 

		// Add a parameter to the ParamArray with the appropriate value.
		params.addParameter(idx, value, param.getMode().getModeCode(),
			param.getDataType().getTypeCode(),
			param.getExtent(),
			(ProDataGraphMetaData) null);
		break;
}
</pre>
<p>The outer switch in this code handles the difference between TABLE, TABLE-HANDLE and other parameters. So skip the first cases and look at the default case (the last 11 lines of this code block from the word &quot;default:&quot; on.&nbsp;All this code does is grab the object that&nbsp;is in&nbsp;<em>ValueHolder</em> and&nbsp;assign it to the value variable. It then adds a parameter specifying the&nbsp;ordinal position (idx), the value, the&nbsp;parameter&nbsp;mode (INPUT, OUTPUT or&nbsp;INPUT-OUTPUT), the Progress DataType Code from the <em>DataType</em>, the extent and a null for the <em>ProDataGraphMetaData</em>.</p>
<p>The TABLE and TABLE-HANDLE&nbsp;cases are slightly more complicated. For a TABLE&nbsp;or TABLE-HANDLE if the parameter is either an INPUT or INPUT-OUTPUT parameter, the value has to be set to the <em>ProDataGraph</em> that will&nbsp;be&nbsp;used to contain the return value. The <em>ProDataGraphMetaData</em> needs to be specified to supply the table structure. In the case of an OUTPUT parameter, a TABLE parameter requires <em>ProDataGraphMetaData</em> but null in the value parameter and in the case of a TABLE-HANDLE, both the metadata and the value need to be null. In both cases, the <em>Parameter</em> object will have been specialized as a <em>TempTableParameter</em> object so that it could build the temp-table structure.</p>
<p>Once the parameters have all been added to the <em>ParamArray</em>, it is returned to the caller (executeCall) and is now ready to invoke the call.</p>
<h5>runProcedure()</h5>
<p>The <em>runProcedure()</em> method call is run on the <em>AppServerConnection</em> object that is contained in the <em>CallManager</em>. The AppServerConnection class performs 2 functions:</p>
<ol>
<li>It stores the AppServer connection parameter values; and</li>
<li>It executes calls against the AppServer.</li>
</ol>
<p>The first thing <em>runProcedure()</em> does is call <em>obtainAppObject()</em>. The <em>OpenAppObject </em>class provides access to AppServer connections from the connection pool and supports all communication with the AppServer. The <em>obtainAppObject()</em> call instantiates a <em>Connection</em> object and then an <em>OpenAppObject</em> if they have not already been instantiated. This establishes the connection to the AppServer.</p>
<p>Once the connection is established, the <em>runProc()</em> method on the <em>OpenAppObject</em> is run with the&nbsp;<em>ParamArray</em> that was passed in and any exceptions are thrown back to the caller.&nbsp;If this code completes successfully, the AppServer call has succeeded.</p>
<h5>buildOutputValues()</h5>
<p>After the call has completed, <em>executeCall()</em> calls <em>buildOutputValues() </em>with the <em>ParamArray</em> that was used&nbsp;in&nbsp;<em>runProcedure()</em>.&nbsp;</p>
<pre>//Extracted from <strong>buildOutputValues()</strong>
//
returnValue = params.getProcReturnString();
if (returnValue == null) {
	returnValue = &quot;null/Unknown (?)&quot;;
}
int idx = 0;
for (Parameter param : sig) { // Loop through each parameter in the signature.
	switch (param.getMode()) { // Check the parameter mode.
		case INPUT_OUTPUT:
		case OUTPUT:

			// Get the value of the parameter from the paramArray.
			Object outputValue = params.getOutputParameter(idx); 

			// Set the value of the parameter in our internal array to be the result
			paramValues.get(idx).setObject(outputValue);
	}
	idx++;
}</pre>
<p>The buildOutputValues() method&nbsp;does 2 things:</p>
<ol>
<li>It obtains the value of the RETURN-VALUE string from Progress; and</li>
<li>It loops through all OUTPUT or INPUT-OUTPUT parameters and sets the value in the <em>IValueHolder</em> from the value in the&nbsp;<em>ParamArray.</em></li>
</ol>
<p>The output parameter values are thus available to the <em>Call</em> object for serialization.&nbsp;</p>
<h4>Why this is so powerful&nbsp;</h4>
<p>That is the crux of the code in the Dynamic OpenClient Sample Utility. It&#39;s not really that complicated and although this is a crude example, it does show the relative ease with which one can build a&nbsp;client that invokes calls for which all signature information is obtained at runtime.</p>
<p>If you work through the associated document that contains a description of running the utility, you will notice how easy it is to edit the ABL code and change temp-table structures or any other signature related information, modify the corresponding signature in the XML file and re-run the utility without changing the Java code.</p>
<p>If you go ahead and automate the generation of the XML signatures into a post-compile operation and post it on a web-server or some other centralized resource, there is never a need to change the Java code unless you discover a bug in it or Progress adds a data type.</p>
<p>There&#39;s another interesting side effect to this. It would not take much effort beyond this to build an automated mechanism for dynamic WSDL generation so that you dynamically expose any ABL procedure as a WebService. Taking it further, exposing it as an EJB or J2EE container or a JMS endpoint would be fairly simple too and would mean very little would ever need to be changed in the plumbing between the client and the server. You see, as far as I am concerned, everything related to ProxyGen is plumbing that should never require a recompile unless the underpinnings change. ProxyGen forces that each time a temp-table definition is changed.</p>
<p>Hopefully this example is useful. I am planning a .NET equivalent later on.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2009/11/openedge-dynamic-openclient-java-example/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>OpenEdge Dynamic OpenClient</title>
		<link>http://www.thesoftwaregorilla.com/2009/07/openedge-dynamic-openclient/</link>
		<comments>http://www.thesoftwaregorilla.com/2009/07/openedge-dynamic-openclient/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 20:06:47 +0000</pubDate>
		<dc:creator>Bruce Gruenbaum</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[OpenClient]]></category>
		<category><![CDATA[OpenEdge]]></category>
		<category><![CDATA[n-tier Development]]></category>
		<category><![CDATA[4GL]]></category>
		<category><![CDATA[ABL]]></category>
		<category><![CDATA[Application Server]]></category>
		<category><![CDATA[AppServer]]></category>
		<category><![CDATA[AVM]]></category>
		<category><![CDATA[Dynamic OpenClient]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java OpenClient]]></category>
		<category><![CDATA[OpenEdge AppServer]]></category>
		<category><![CDATA[OpenEdge OpenClient]]></category>
		<category><![CDATA[Progress]]></category>
		<category><![CDATA[Progress AppServer]]></category>
		<category><![CDATA[Progress OpenClient]]></category>
		<category><![CDATA[PVM]]></category>

		<guid isPermaLink="false">http://www.thesoftwaregorilla.com/?p=75</guid>
		<description><![CDATA[In one of the more recent versions of OpenClient, the API that the OpenClient uses is documented so that it is now possible to dynamically construct the proxy calls at run-time. The overarching benefit in this lies in the ability to now define the temp-table definitions on the fly. The Java/.NET code can now define the temp-table dynamically at run-time so that if a change is made to the definition, the client can deal with the change with no impact on the OpenClient source code.]]></description>
			<content:encoded><![CDATA[<p>I forget how long ago it is that the OpenEdge OpenClient was released. It must be easily close on 10 years, but I am willing to accept that may be an exaggeration. OpenClient is a cool technology.&nbsp;&nbsp;For the&nbsp;uninitiated, the OpenClient is&nbsp;a very powerful&nbsp;library of&nbsp;code and&nbsp;a set of tools that allows&nbsp;.NET, Java and WebService access to the OpenEdge AppServer. It allows you to build&nbsp;your business logic in the OpenEdge ABL&nbsp;and access it from whatever client you choose.</p>
<p>In order for the OpenClient to be able to connect to the AppServer, make a call and return the output parameters, there is a&nbsp;certain amount of code that you need&nbsp;on the client (Java or .NET) that wraps the OpenClient library.&nbsp;In an effort to simplify the&nbsp;process of writing that code,&nbsp;OpenEdge includes&nbsp;a utility called &quot;ProxyGen&quot;&nbsp;that parses the OpenEdge ABL&nbsp;code and generates a&nbsp;proxy class&nbsp;that wraps all of the code needed and exposes it as a simple method call. Once you have generated the proxy, you simply include the generated class in your code (either as a .jar or a .NET assembly, or even directly as source code) and you can make whatever call you need.</p>
<p>The problem with ProxyGen is that you have to regenerate the proxy and potentially rebuild the client each time the ABL&nbsp;procedure changes its signature. That would be&nbsp;okay if the ProDataset and Temp-Table definitions were not part of the signature, but they are and adding a field to a temp-table should not cause a proxy to break.</p>
<p>&quot;Hang on, Bruce,&quot; I can hear you say, &quot;Why is the signature of the temp-table not a change to the signature to the API?&quot; I&#39;m not saying that it isn&#39;t, but I&nbsp;am saying that it is far more difficult to avoid making this mistake. Here&#39;s why:</p>
<p><img align="right" alt="Temp-Table Definitions being included in classes and procedures" height="193" src="http://www.thesoftwaregorilla.com/wp-content/uploads/2009/07/TempTableInclude.jpg" width="500" />Typically, temp-tables that form part of the in-memory data model are defined in include files and then used in procedures and classes as in the&nbsp;attached diagram.</p>
<p>Let&#39;s assume that Procedure1.p and Procedure2.p are deployed to the AppServer and that&nbsp;Procedure1.p accepts the temp-table as an input parameter and Procedure2.p uses it as an input-output parameter.</p>
<p>As a result of a necessary change to the in-memory data model, a field or two are added to&nbsp;the&nbsp;temp-table definition for the purposes of the Class1.cls and Class2.cls.&nbsp; As part of the build, the code is recompiled and the new code deployment to the AppServer is completed successfully. Note that there has been no planned change to the Procedure1.p and Procedure2.p.</p>
<p>The problem that we now face is that the proxies that were generated for the Procedure1.p and Procedure2.p are now invalid. The temp-table definition is no longer correct and a run-time&nbsp;error will now occur for the client when these procedures are called.</p>
<p>Another problem with proxies is the complexity associated with unit-testing and verifying each individual proxy. Each time a proxy is changed, each of the unit tests for each call in the proxy has to be rerun and retested. There is no way to generically test them to verify the Java/.NET code.</p>
<p>In one of the more recent versions of OpenClient, the API that the OpenClient uses is documented so that it is now possible to dynamically construct the proxy calls at run-time. The overarching benefit in this lies in the ability to now define the temp-table definitions on the fly. The Java/.NET code can now&nbsp;define the temp-table dynamically at run-time so that if a change is made to the definition, the client can deal with the change with no impact on the OpenClient source code.</p>
<p>This functionality is, in fact, so powerful that the entire signature, including all&nbsp;parameter definitions,&nbsp;can be discovered and defined at run-time.</p>
<p>This concept becomes even more interesting as you consider using it for WebServices. ProxyGen can generate the WSDL for a procedure that is to be exposed as a WebService, although it suffers from the same issues if the signature changes. The dynamic OpenClient API makes it possible to dynamically generate&nbsp;the WSDL at run-time from the procedure. Obviously there are overheads associated with auto-discovering a procedure&#39;s signature. It makes sense, therefore, to build out this functionality so that the signature discovery is done as seldom as possible.</p>
<p>In a future article I will provide some code samples that show you how to use the Dynamic OpenClient.</p>
<p><strong>UPDATE: </strong>I have subsequently made this code sample available. You can refer to it <a href="/2009/11/openedge-dynamic-openclient-java-example/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesoftwaregorilla.com/2009/07/openedge-dynamic-openclient/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
