- Introduction
- The Logon Architecture
- Parsing the XML Response
- Email Interaction
- Error Messages
- Summary
The Logon Architecture
The logon architecture comprises a number of Curl classes, some of which will also be utilized in other application modules. Before discussing these classes in detail, it's important to have an overall picture of how these classes work together. Figure 31 illustrates their execution to display a Logon window.
Figure 31 Enterprise Curl Logon window.
This simple Logon window actually includes a number of advanced features, which will be used elsewhere in the flexible framework architecture being developed. For example, the window is based on an abstract response or dialog window that includes the ability to call a server-side authentication module over HTTP. The response generated from the server-side process will be in the form of an XML message, and the Curl application will parse and translate this data before evaluating which application module to execute. These elements are illustrated in the object model in Figure 32.
Figure 32 Logon object model.
The remainder of this chapter will discuss the classes introduced in the logon object model in Figure 32, describing their key features and interfaces.
The Response Class
COM.ENT-CURL.WINDOW.Response is a custom class created specifically to be a base for all framework response windows. By creating this ancestor, we can ensure that all application response windows have a common look and feel, as well as a number of core methods and variables available to them.
The Curl language allows developers to create their own classes, which is one of the key fundamental elements of any object-oriented language. As previously stated, we will not delve into great detail on a number of associated technologies relevant to Curl. It is outside the scope of this book to define and explain the nature of classes in an object-oriented architecture, but by reviewing the example code presented in this book, you will see how a Curl class is indeed true to the definition of a class within any object-oriented language.
Curl supports multiple inheritance, meaning a class can be defined from one or more ancestor classes. This is a very powerful language construct and one alien to a number of other object-oriented languages, including Java. By using the multiple inheritance relationship, you can create a class that incorporates behaviors and states previously defined and tested in any number of other classes. This greatly reduces development time and increases the overall quality of your work. Figure 32 illustrates how the Response class inherits from two ancestor classes, namely Dialog and WindowBase.
The Response class has one {constructor}, which enforces a consistent approach of how a framework response window will appear to the user. Application parameters are stored in a single class, called AppParameters, and this class can be used to quickly configure many framework-wide settings. The Response window class uses the AppParameters class to determine the width, height, background color, and other visual settings, as can be seen from the code in Figure 33.
Figure 33 Response class.
While reviewing Figure 33 and the logon module object model in Figure 32, you may wonder where the app-parms reference comes from. This reference originates from a package variable within the COM.ENT-CURL.LOGON package, declared as being accessible by all classes defined to it. Figure 34 shows the COM.ENT-CURL.LOGON package import statement.
Figure 34 COM.ENT-CURL.LOGON Import statement
Using the Response class as the ancestor for all modal framework windows is a very powerful feature of this enterprise Curl architecture. Furthermore, using the AppParameters class to hold application-level settings to define visual characteristics gives an example of one design pattern you may employ to create a flexible and configurable architecture. This example may be extended to incorporate the specific requirements of your enterprise. The AppParameters class will be explained later on in this chapter.
As you can see from the Response class code in Figure 33, the class makes use of functionality and attributes defined in two ancestor classes through the use of a multiple inheritance relationship. These are the Dialog and WindowBase classes.
The Dialog Class
CURL.GUI.CONTROL-BASE.Dialog is a Curl system class that has the ability to present GUI controls on a form-like interface. It is intended to be used either embedded on a Web page or as a container for controls presented on a modal or non-modal window. It provides tabbing functionality, as well as methods for opening and closing windows. It is based on an inheritance relationship with a number of other Curl classes: StandardActiveTraversalContainer, ControlContainer, and Observer. To find out more about the functionality available to you within these classes, refer to the Curl Help documentation available with the IDE.
The object model presented in Figure 32 includes one Dialog class method, {show}. This method opens the control in its own window and allows the developer to select a number of core behaviors by passing across parameters when the method is executed. For example, you can control whether the window is modal or non-modal, specify the window's title, whether the window is to be centered on the screen, and even if the window is resizable or not.
Because the Dialog class is a system class defined in the Curl language, the full code will not be illustrated here. Refer to the Curl Help documentation for further details.
The WindowBase Class
The Response class is also based on an inheritance with a custom class called CURL.ENT-CURL.WINDOW.WindowBase.
WindowBase is a base ancestor for all COM.ENT-CURL package windows, for example, Response, Frame, and Sheet. It provides core services required across all application windows. The logon object model presented in Figure 32 shows that the WindowBase class consists of a single protected class variable. The Curl language has the ability to define a scope to variables, which is a powerful object-oriented feature. By assigning a scope to a class variable, you can define the classes in the application that can gain access to the contents of that variable, thereby enforcing necessary security and inheritance characteristics. The protected declaration means that only those classes in the same package or those that are sub-classes to WindowBase have access to these variables. The other declaration options are public, package, and private.
The code for the WindowBase class is presented in Figure 35.
Figure 35 The WindowBase class.
The variable defined in WindowBase is a reference to the GUIFactory class, which controls the creation of all application GUI controls.
The GUIFactory Class
The GUIFactory class is a framework custom class used to control the instantiation of all graphical components presented to the user. For example, all radio buttons, check boxes, and single-line edit controls are created through this class. The intention is to have a single place where application controls are created, thereby allowing you to define a consistent look and feel that will be applied throughout the framework.
In most enterprise application development projects, there are a number of developers involved in the creation of the final product, all working simultaneously on different modules. In such large-scale development projects, it is typical to have a GUI control document, which defines the visual characteristics of each graphical control used in the application. By creating such a document and involving the developers, the aim is to have all graphical controls look the same. In practice, this is rarely the outcome.
The GUIFactory class ensures a consistent look and feel to graphical components, as all the developers working on different modules use this single class to create graphical controls. Rules such as which font family, size, and weight to apply to command buttons are defined in one place, and consistently applied throughout the project.
Figure 36 shows the code for GUIFactory, which may be extended to instantiate other visual controls, including those that your enterprise may create in the future. Figure 36 shows how GUIFactory makes use of the AppParameters class to determine the visual characteristics of controls. This design has been created to have a single place for defining and changing all application parameters.
Figure 36 The WindowBase class.
You may notice that all the methods are very similar; the difference is in the control returned. Each method contains a set of arguments that helps define the exact visual characteristics of the control, with the remaining options obtained from the AppParameters class or through the control's default settings. To obtain the fastest execution of these methods, and to minimize the number of objects being created by the runtime engine, each method creates the control in the {return} statement.
The code presented in Figure 36 shows how the enterprise application framework makes extensive use of the AppParameters class, which holds constants for defining how graphical controls should be created. This following section fully explains how this class is constructed.
The AppParameters Class
Any enterprise framework has to be as flexible and configurable as possible. To promote code reuse and ensure the applications are created in the shortest possible time, the framework has to be designed with a number of core runtime characteristics defined and kept in a parameter store. Examples of this exist within the Windows operating system environment, where application parameters that control how the baseline product appears when executed are stored in the Windows Registry. For example, notice how Word keeps track of the last four documents you have edited and displays them in a list on the File menu. This information is stored and accessed from the Registry.
The enterprise Curl framework presented in this book makes use of this design pattern, but cannot store certain application parameters directly on the user's machine. This is because Curl application programming instructions are downloaded from a Web server and require immediate knowledge of some key application parameters. This design also ensures that there is one central place, AppParameters, that controls how the interface looks. To solve this design problem, we will make use of the AppParameters class, which contains a list of public constant variables available to all classes.
It is important to note that application data can actually be stored on the user's computer by using the client-side persisted data capabilities of Curl. Indeed, we will make use of this later in the development of the VMS Motors application to store user preferences. But for parameters that control how application graphical controls are presented, for storing window titles, and for recording the correct server-side Web address for some processing, we will make use of the AppParameters class shown in Figure 37.
Figure 37 The AppParameters class.
The AppParameters code listed in Figure 37 contains a number of key items that need further explanation. First, the declaration statement assigned to each variable is public constant. This constant keyword means that the value cannot be changed during runtime execution. If you wrote a line of code such as {set app-parms. service-statusbar? = false}, you would receive a runtime error message stating, "Can't assign to constant field ´service-statusbar?'" Defining variables as constants provides an element of security, as no malicious programming instruction can change the logon URL to send the user name and password information to an unintended server-side component. Furthermore, this variable definition ensures that the application generates behavior and presents itself visually in the manner designed by the architect and implemented by the developer.
The second key element of the AppParameters class is its use of another custom class, called AppFont, to store specific font information relevant to different controls.
The AppFont Class
The AppFont class is used to control and define the font characteristics of visual controls, enabling each control to have a different font style, size and weight.
We saw earlier in this chapter how the GUIFactory class is used to create all application visual controls, and how it obtains certain control settings from the AppParameters class. Looking at the code displayed in Figure 37, you can see that we define two constant variables called label and field, each based on the default AppFont constructor. Looking at the code for the AppFont class displayed in Figure 38, you can see that the default constructor simply accepts the default class variable settings for font family, weight, and size.
Figure 38 The AppFont class.
Looking closer at the AppFont code in Figure 38, you see that there is a secondary constructor that accepts parameters passed into it. This constructor is used to change the default font settings eventually applied to a certain type of visual control. If, for example, you wanted to change the default font settings for a label, you would change the variable declaration in AppParameters, as displayed in Figure 39.
Figure 39 Overriding the default font settings in AppParameters.
Using the AppParameters definition listed in Figure 39 would result in all framework labels having the same visual characteristics of a courier font, size 10pt, and bold.
The Logon Window
Everything discussed so far in this chapter has been focused on creating the framework for a logon component. Now we will look at how the actual Logon window is created and displayed to the user, based on the window layout design shown in Figure 310.
Figure 310 Logon window layout design.
As can be seen in the logon object model presented in Figure 32, the Logon window is a descendent of the Response class. This ensures that it behaves as a modal window, with all the instantiation logic and functionality defined in the ancestor class. We now need to code the Logon window class to have the specific visual controls and processing instructions required by our application. Figure 311 contains a listing of the Logon class code.
Figure 311 The Logon Class.
All the visual controls are created by the ancestor reference to a variable defined as the GUIFactory class, and each one is stored in a private class variable. You can see that we are using a special type of class variable declaration with the # operator. This indicates that the variable can have a null value and will be initially declared as null. We define the class visual controls in this manner because they will be set based on a class created by GUIFactory. This type of definition has a slight performance advantage because the Curl runtime engine does not have to create a full instance of the visual control when the Logon class is instantiated.
Another important item to note about the Logon class is the use of the system VBox control to hold all other visual controls. The Dialog class, which is one of the ancestors of Logon, can have only one visual control defined to and displayed by it. Therefore, we need to have a visual container that manages all of the labels, fields, and buttons required on the Logon window. For this task, we use a VBox. A VBox is an instance of a SequenceBox and has the ability to arrange its contents in a vertical fashion, ensuring that objects placed under its control do not overlap. Refer to the Curl Help documentation for further details regarding the VBox system control.
Event Handling
Curl provides developers the ability to create events and associate them with controls after the controls have been instantiated. This is a very powerful language construct.
For example, in the normal declaration of a CommandButton, you define its visual characteristics, such as label, font, and size, as well as the event instructions to be executed when it is clicked. Figure 312 shows such a declaration.
Figure 312 Typical CommandButton declaration.
However, you can also define the event processing instructions applied to a control after it has been instantiated, and our enterprise framework makes extensive use of this capability. We saw earlier how the GUIFactory class is used to control the consistent appearance of visual controls. But for those controls that need events associated with them, this factory design has a flaw in that it does not define the events and another approach is required.
An EventHandler is a Curl system object that defines a piece of processing logic, and because it is an object, it can be created as needed. An EventHandler needs to be associated with a specific EventTarget for its processing to be initiated. EventTargets are typically visual controls such as CommandButtons, RadioButtons, and CheckButtons. So by integrating an EventHandler with a visual control generated from the GUIFactory, we can achieve maximum flexibility and reusability throughout our enterprise architecture.
An example of such an approach is illustrated in Figure 313, where the Logon.{create-logon-controls} method has been enhanced to define an EventHandler and associate it with the login-button control.
Figure 313 Additional code requirements for the Logon.create-logon-controls method.
The {add-event-handler} method is used to define and associate specific EventHandler instructions with a control. We do not have to specifically instantiate the EventHandler in this code example, as the {on Action do} procedure actually creates an instance of an EventHandler.
Another design pattern would be to define a local variable of type Event Handler, create an instance, and then use the variable name within the {add-event-handler} method. Using this approach, it is possible to define a single EventHandler and associate it with multiple controls. This process reduces the number of lines the developers have to write and test.
The Cancel button is the other control on the Logon window that requires event processing. The code listed in Figure 314 will be added to the Logon.{create-logon-controls} method to handle this.
Figure 314 Cancel button EventHandler.
The EventHandler code for the logon-button variable in Figure 313 makes use of client-side persisted data as well as the HTTPCommunication class. In the following sections, we will further investigate these processing instructions.
HTTPCommunication Class
In the execution of an enterprise Curl application, there will be repeated calls to any number of server-side processes to obtain and change data. Therefore, we should develop a single HTTPCommunication class to abstract out this functionality and ensure that a consistent approach is applied throughout. This class is listed in Figure 315.
Figure 315 HTTPCommunication class listing.
The HTTPCommunication class has a single method called {connect}, which takes a String as an argument. Developers call this method by passing across the URL of the server-side process to execute, and they receive a class called ServerResponse that is populated with the returned XML, a return code, and any communication error messages.
The first few lines of the {connect} method simply define a number of local variables required for communication processing. Next, we check the runtime option set in the AppParameters class to see whether the logon process is being executed on a Web server or if it is simply reading the XML file on the local file system. This design enables maximum flexibility because the code can be created and run locally before introducing the added complexity of Web server processing. When the time comes to move the code into production, and to run against a production Web server with a different URL, a quick change to a configuration variable in the AppParameters class resolves the issue.
Looking further through the {connect} method, we come across a {try-catch} block, which is where the actual HTTP connection is made.
The {read-open} procedure takes a variable of type CURL.IO. CORE-FILE.Url as its first parameter, and in our example, this Url is generated through executing the {parse-url} procedure. If an HTTPException is thrown while trying to connect, it will be generated at this point and an appropriate return code and error message will be set within the ServerResponse class. We will discuss the ServerResponse class in the next section.
If the connection made through the {read-open} procedure was successful, the input-stream variable will contain the XML data read from the URL.
The HTTPCommunication class will be used throughout our application as the single place where server-side communication over HTTP can occur. Every time this class is instantiated and the {connect} method is executed, it will access a variety of server-side resources, each returning different data. Because of this fact, it has been designed to pass back a ServerResponse class that represents a structure and is capable of containing all possible server responses.
ServerResponse Class
The ServerResponse class acts as a container or structure for multiple data elements obtained or calculated as a result of executing a call to a server-side process. It consists of three public class variables, which means that any Curl class that can access the ServerResponse class can read or change the contents of these variables.
A typical design pattern for such a class implemented in other object-oriented languages might define these variables with a private scope and enable access to them through a number of get-variable and set-variable public methods. Such an approach is certainly appropriate where greater security is required for object variables, or where the get-variable and set-variable methods actually apply some further business processing other than just reading and writing. As neither situation applies in our scenario, we will take a less stringent design model of having public class variables with an implied get/set operation as shown in Figure 316.
Figure 316 ServerResponse class listing.
So far, we have developed enough functionality to connect to a server-side process over HTTP and store the response data and codes in a structure class. The next stage is to create the logic that translates the response into a usable form; specifically, in our example it will parse the XML data and generate a GUI or evaluating application workflow based on the contents of the XML return message.