Richard (Rik) Brooks

Subscribe to Richard (Rik) Brooks: eMailAlertsEmail Alerts
Get Richard (Rik) Brooks via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

PowerBuilder: Article

Jaguar Mail Server II

Jaguar Mail Server II

In the October issue of PBDJ we worked on the design for our mail server on Jaguar. This is more accurately called an MDA, or Mail Delivery Agent. What we're writing isn't the application that will receive raw messages from the Internet, parse them out, then store them for another application to download. It in fact does the downloading.

This relationship is beyond the scope of this series, but it needs to be addressed simply to avoid confusion. What we're considering is something far closer to a Microsoft Outlook than a SendMail.

So why write a replacement for Microsoft Outlook? Actually I'm a big fan of that product. I use it daily. We're doing this because it's a fairly straightforward exercise in building Jaguar components and is in fact about as purely distributed as anything can be. During the course of this article we'll find more tangible reasons to write this application, but for now just consider it an exercise.

So let's get back to our work here. It's been a while since the first article so let's review. Figure 1 came from that article. Let's look at it again.

What's most important to this article is the middle objects, the mail server and the mail customer. In the previous article we got started on the mail server. We created stubbed-out methods for getting headers, logging on and off, saving, and sending messages. We're going to have to flesh this out.

This is where I reveal a little secret about object-oriented design. There's a concept in OO technology called stochastic animism. To oversimplify this issue, each object should in some way model an object in the real world. It's distinguished by the question: What does this object know how to do?

In our case we want two distinct sets of functionality. We want an object that handles the connection to our MAPI. This would be our mail customer, who knows how to send and retrieve mail. Basically he's our interface to the MAPI functions.

The MailServer component is tasked with gathering this information and returning it to the user the way we want it. He presents the information to the user. He handles the html. If we decide to enhance our application down the road, it would be he who communicates with other objects to bring the entire application to a cohesive front for the user. Suppose we want to add e-mail lists to our application. We'd create a list manager component and reference it from our server. Our user would communicate with the server to ask to send e-mail to a list. Our server would combine the list manager and the mail customer to handle that request and return HTML to our user, each object doing only what it knows how to do and nothing more. This is the essence of stochastic animism. It's served me well in my career and has greatly simplified the design of objects for me. I'll follow this methodology in our series here.

Now that that's settled.... In my previous article we created stubs for several functions. Now we're going to use them. The first thing we need to do is create our mail customer component. The mail server will use it to process those actions that the user requires. The mail customer component will never be used by the end user, only by the mail server. That means - and this is important - we don't have to be CORBA compliant with it. In other words, we can pass and return any kind of variable that PowerBuilder understands, not just the primitive variables that CORBA understands. This gives us a lot more flexibility.

So let's create the component. You'll click on New, then make sure you're in the Object tab page. Double-click on Jaguar Component Wizard - just as in Figure 2. It's important that you choose this one. There are two other places where you can create a Jaguar Component: in the Start Wizards and in the Projects tab pages. You want a component added to this project, though. so this is the appropriate selection.

I'm not going to step you through all the dialogs of this wizard. Just select the defaults until you get to "Specify New Component." The default for that will be the component you already have. Change it to your new component name. I changed mine from the default "n_jagMailServer" to "n_jagMailCustomer".

Eventually you'll have to select a package. Choose the one that contains your mail server.

You'll be asked if this is a Standard, Shared, or Service Component; it's Standard.

In the Specify Transaction Support you'll need to make sure that the Auto Demarcation/Deactivation remains off. This is a deviation from my normal components. It means that the component will be stateful and remain in memory from one method call to the next. If we checked this box, it would be stateless and we'd have to reconnect every time we wanted to call a method. I always make components that will communicate with the user stateless, but since I have full control of this component from my mail server, I feel safe in making it stateful. In another article we'll create functionality to deal with time-outs and deactivating these components.

In the Specify Other Component Options we want to Support Remote Debugging. Whether you support live editing (automatically deploys the component every time you save it) is up to you. I find it annoying so I don't do it. It does mean that I need a separate project for it to deploy the component, but I get annoyed when I make a tiny change, then have to wait for the component to deploy when I save it.

In the Specify Dynamic Library Options you should check the box that lets you include unreferenced objects in the consolidated PBD. This way I don't have to worry about accidentally forgetting to put something into a PBR file.

Now we have our object. Open it in a painter and let's get started with it. First you want a mail session as an instance variable. The definition is:

private MailSession ims_mailsession

You now want to create a logon method that will be called from the mail server. Basically, the mail server is going to get a request from the user to log on. He'll create a copy of your mail customer component and call the logon method of that. He'll then translate the return value to a CORB-compliant return value and return it. You now need a method called of_logon that will return a MailReturnCode and take a name, password, and mailLogon-Option as arguments. This is just one line of code so I'll add it right here:

return ims_mailsession.maillogon(as_username, as_password, ao_option)

Now we have a method that our server can call. That brings us back to the issue of the relationship between the server and the customer. We already settled that the server would handle multiple customers. Clearly that means an array of customer components. However, we need to keep track of whether a component is active. Look at it this way; we'll create these customer components in our server and do things with them. At some point we'll no longer need them. We can either return them or hold on to them and reconnect them at a later date. I like the idea of holding on to them. To handle that we need another instance variable in our customer to tell us if the component is logged on. Add this line of code to the instance variables:

privateWrite boolean ib_connected = FALSE

By default, all instance variables are public. In this case I want my server to be able to read the variable directly, so I can leave the Read attribute public. I don't want my server to be able to change the value though. I want only this particular object to be able to change it and do so only in response to a successful logon. That explains the privateWrite.

I now have to modify my of_logon method to set this instance variable. Oh, well, that's how component design works. Go back to your of_logon and change it so that instead of the one line, it now matches Listing 1.

Back to Our Server
Now we have something we can call. We can log on (hopefully). Let's go back to our n_jagMailServer and create that line between the customer and server shown in Figure 1.

The first thing we need is an array of customers. We should make that an instance variable. Go to the instance variables of n_jagMailServer and add:

private n_jagMailCustomer io_customers[]

We need to write a little code to handle this array. It's a simple method that will loop through the array looking for customers that aren't connected. These are components that were connected once but have finished their tasks and are waiting to be reused. If it finds one, it will have to reuse that array element. It won't need to create a new one. I call this method of_findAHole. It returns the array index to an unused element or creates another customer and adds it to the last array element, returning that index. The code for this method is in Listing 2.

We finally get back to our of_logon in the server. It takes three strings as arguments and returns an integer. This doesn't match our customer logon. We need to translate. The mailOption argument passed in is fairly simple. Let's just code that right in the method. Translating the return value from our customer though is a little different. I'll probably want to do this sort of conversion all over the place, so I have to create yet another method to promote reuse. This time I'll create a method called of_returnValue. that will take a mailReturnCode and convert it to an integer. I like that. I can standardize the return code to the user this way. You'll find the code for this method in Listing 3.

We're finally back to the of_logon method in the server. With the proper setup it's a simple method, just 12 lines (see Listing 4). It finds a hole, converts one of the arguments passed in from CORBA compliant to something the customer component likes, then calls the customer and returns the value returned from the customer (after passing it through our conversion routine).

Oh, Well...
Again, dear readers, we've run out of space. I'd hoped to get just a little further because our next step ties everything together. Now we have the relationship between the mail server and the mail customer well defined. We're able to connect. In the next article I'll define the relationship between a browser and our mail server. We'll create an environment in which the browser can request a login and get back the headers for all of his mail. From that point on, it's just plain fun.

More Stories By Richard (Rik) Brooks

Rik Brooks has been programming in PowerBuilder since the final beta release before version 1. He has authored or co-authored five books on PowerBuilder including “The Definitive DataWindow”. Currently he lives in Mississippi and works in Memphis, Tennessee.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.