Archive for July 2012
This post illustrates how to create a new widget so that it can be included into a new project or existing project.
The widget will present a list of items from which the user may select one, some or all to be included into a working list. As they are select from the original list to be added to the working list they are removed from the list on the left.
Shown here is the widget as it appears in the designer.
The widget includes several functions that allow the developer to establish short descriptions that appear above each list and to populate each ListMulti widget with values. The buttons are left as they appear and let the user move the selected items from one list to another.
Here is an example of the widget as it is used by the main application after it has been fully initialized.
Below is the source code for this very short web-page. The start function does all the work of initializing. In this case the list is filled with different types of aircraft. The user may select one or more from the list at the left and then select the button with the “>” arrow which moves the selected item(s) to the list shown on the right. Modifying the list of selected items (at right) is performed the same way; select the desired items from the list at right and select the button marked as “<" and the items are placed back into the list on the left.
Fig.1 – An example of an application using the widget.
Note the start function’s use of the widget’s functions that let the developer initialize the list entries, the short descriptions that appear above each in addition to the length and width of each list. The widget’s functions are listed here.
- setSelectList(stringArray String) Sets the list of selectable items shown on the left side of the widget.
- setSelectTextLabel(labelText String) Sets the text label appearing over the selection list shown at the left of the widget.
- setIncludeTextLabel(stringArray String) Sets the text label appearing over the include list shown at the right of the widget.
- setListWidths(widths int) Sets the widths of the list windows.
- setListSizes(sizes int) Sets the sizes of the list windows in terms of the number of entries that are visible before a scroll bar is made visible.
Below is the full source listing for the widget. To use it, simply add the code to your project and then drag-n-drop it into your page.
Fig.2 – The full source for the widget.
This post showed how custom widgets can be used and re-used across difference applications. Designing EGL applications in this manner can result in productivity gains by reducing development and testing times.
This post presents a number of important and useful programming conventions. If you follow them your EGL code will be self-documenting and easier to read and maintain.
Naming and Capitalization Conventions
The standards that follow are derived from David Flanagan’s book, “Java In A Nutshell”, third edition. Since EGL development is similar to Java development these standards can apply to EGL as well. EGL development can often include Java code to help with tasks that EGL cannot perform and so adopting these standards will naturally apply to any Java source members included into the EGL project. Later, when the EGL developer endeavours to embark upon developing web applications using Java alone, they can apply the same standards they have been using all along for EGL and will serve to make that transition much easier.
The naming conventions refer to packages, EGL parts (programs, services, records, libraries, external types, etc.), functions, fields and constants in EGL. Because these conventions are universally followed in the Java development community and to some degree by the .NET community they are very well suited for the EGL development community. The naming standards for fields and functions can also be applied to RPG-Free.
EGL source files, whether they are for RichUI Handers, Services, External Types or Records, are organized into related groups known as packages and should be made unique by prefixing them with the inverted name of an internet name, such as “com.mig.application”.
Whether for Java or EGL, packages should follow the convention as shown.
com.mig.[project name].[package name].
Naming in this way will ensure they are unique enough to avoid name collision if packages encapsulated within a .jar file are included in the project. All package names should be lowercase.
- EGL Parts
All EGL parts are files used to create EGL applications. These are Logic parts including Program parts and Library parts, which are general-use parts, as well as Service parts, External-Type parts, and Handler parts, which have more specialized uses.
EGL part names should be nouns as they represent “things” or “objects”. (e.g. Customer, Invoice, Policy, etc.) The names for these parts should begin with a capital letter and be written in mixed case. If a part name consists of more than one word, each word should begin with a capital letter (e.g. CancerPolicyService, CustomerEntryHandler, ClaimsService etc.). If an EGL part, or one of the words in the part name is an acronym, the acronym can be written using capital letters (e.g. URL, HTMLParser).
Interface names follow the same capitalization conventions as EGL Parts. When an interface is used to provide additional information about the par that implements it, it is common to choose an interface name that is an adjective (e.g. Runnable, Cloneable, Serializable, DataInput). When an interface works more like an abstract representation of the part, use nouns (e.g. Document, FileName, Collection).
Function names should contain a verb as they are used to make an EGL Handler, Service or Program perform an action. Adjectives and nouns can be included in its name.
function showPage(newPage int in)
function toPage(newPage int in)
A function name always begins with a lowercase letter. If the name contains more than one word, every word after the first begins with a capital letter (e.g. insert(), addPolicy(), updateClaim(), etc.). Function names are typically chosen so that the first word is a verb. Function names can be as long as needed to make their purpose clear, but choose succinct names where possible.
- Variables and Constants
Nonconstant variable names should be nouns and should follow the same capitalization conventions as function names. If a field is a constant it should be written in uppercase. If the name of the constant includes more than one word, the words should be separated with underscores (e.g. MAX_VALUE, EMAIL_ADDRESS, MACHINE_ID, USER_PASSWORD, etc.) A field name should be chosen to best describe the purpose of the field or the value it holds.
The names of function parameters appear in the documentation for a function as presented by the IDE’s code assist facility. Therefore, you should choose names that make the purpose of the parameters as clear as possible. Try to keep parameter names to a single word and use them consistently. For example, if a CancerClaimService service-part defines many functions that accept a claim number as the first parameter, name this parameter claimNumber in each function.
- Local Variables
Local variable names are an implementation detail and never visible outside of the EGL Part. Nevertheless, choosing good names makes your code easier to read, understand, and maintain. Variables are typically named following the same conventions as functions and fields.
This post presents source code to be used as a starting point for coding a Rich UI handler. Presented are two variations giving a “minimalist” appearance based on the philosophy of “less is more”. The screens are not exposed to an internet based audience where flashy presentations designed to capture and keep the attention of the user is not a requirement. On the contrary, the screens are deliberately austere in appearance allowing the user to focus on the task at hand which is to enter and/or maintain information as it relates to the business where distractions impacting accuracy must be minimized.
The source creates a header for a title and an area below it for a collection of menu items. The menu items are just place holders to indicate this is the area where they should reside and until logic is added they essentially do nothing. If the page design does not require menu options the developer should delete them but leave the bar in which they would normally reside.
What remains below the menu bar constitutes the main body of the web page which is further divided into two sections. The first section is intended to contain widgets allowing for input of data to be provided by the user. The user data supplied is then used to retrieve information from the database to be presented in the second section that is presented below the first. If there are no business requirements that must allow the user to enter such data (i.e. part number, customer account number, policy number, etc.) then the first section should be deleted.
As mentioned above, the second section constitutes the main area where data is presented. More often than not the data presented here is retrieved using user-supplied data provided in widgets contained in the first section described above. If the application is a browse/select type where the user is allowed to see a list of data then a data grid would be presented in this section. As another example, if the first section allows for information to be entered for a new inventory item number, a customer account number or policy number, the second section would then be filled with the appropriate widgets or components to display the related data for the purpose of inquiry or maintenance.
Because the two sections are contained in a title pane the user can collapse them by selecting the downward pointing arrow at the left of each of the pane’s titles. The user may select the arrow after supplying select criteria or a policy number to retrieve the information related to minimize its space on the browser screen.
The Source Code
Presented below is source code for a Rich UI handler that acts as a template or starting point for all web applications. Using a template such as this will serve to ensure all web pages are presented with a uniform appearance and behavior. This in turn will minimize training time and expense and ensure the user’s understanding of screen behavior can be applied to the next application in the system without having to rely upon guessing.
Source Template for a Rich UI Handler – Variation 1
Presented below is the source code for the first variation of the overall look which can be best described as having a “minimalist” appearance.
Fig.1 – Source template for a Rich UI handler
Source Template for a Rich UI Handler – Variation 2
Presented below is the source code for the second variation of the overall look. The only difference is the header section containing the title which has been filled with a blue color ( backgroundColor = “RGB(40,95,175)” ) with a white color for the title font.
Fig.2 – Source template for a Rich UI handler
Shown below is a screen shot for the above source code.
This post illustrates the start-up processing phase of an arbitrary EGL based web application. The focus will be about how to incorporate some of the building blocks already presented which are used to help initialize the application.
The code to acquire the runtime environment variable is contained within runtimeEnvironment.jar. The code used to read the XML file is contained within appUtilities.jar.
Ask a member of the development team for these files so they can be included into your project.
Most web applications will have configurable program values stored in a file external to the application. The values are usually contained within an XML file. Shown below is an XML containing values for a comment, a version number and three values for an email address.
Fig.1 – A simple set of property values in an XML file.
The entries for <comment> and <entry key=”version”> is pretty much self-explanatory. The first is to hold a simple comment for the developer while the second contains a version number for the application.
The entries for <entry key=”localhost.emailAddress”>, <entry key=”TEST.emailAddress”> and <entry key=”PROD.emailAddress”> hold values reserved for one of the 3 possible servers in which the application will run. Each entry for email address is preceded with either ‘localhost’, ‘TEST’ or ‘PROD’ which represent the server running on the developer’s machine (i.e. 127.0.0.1, a.k.a ‘localhost’) the server assigned to the role of application testing (“TEST’) and the server assigned to the production role (‘PROD’).
In this situation, this approach of assigning application property values allows the developer to test the email application so that during the development-testing phase, emails will only be sent to the developer rather than a community of users. The same holds true for the TEST server. When the application is finally deployed to the production server the correct production-oriented email address is used.
By prefixing each property value with a server identifier, a unique value can be established for each server. This allows the application to pick up the correct value that has been assigned for the server in which the application is running. The only trick now is to get the application to determine which server it happens to be running on.
Placement of the Property File Within the EGL Project
As previously stated, the code used to read the XML file is contained within appUtilities.jar. As a consequence the XML file must be placed into a directory known to it, as shown below.
In addition, the XML file must be named ‘applicationConfig.xml’.
Determining The Server’s Role During Startup
Getting the right value during run-time rests upon the application’s ability to determine which server it happens to be running on. This is done by assigning an externally-defined value to each of the servers. To see how this is accomplished please refer to this post.
Once this value (‘TEST’ or ‘PROD’) has been established the application can read it which usually occurs at the very beginning when the application is first started.
The idea here is to read this value (‘TEST’ or ‘PROD’) and use it to append to the property name so that the retrieval process picks up the correct value which is then cached inside the application so that it can refer to it when needed. In this case, that would be when the application needs to send an email.
This post illustrates how to create EGL code to read the environment variable (EV) assigned to Tomcat’s JVM.
Reading Application Properties From The XML File
This section will illustrate how to create an External Type that is the interface to an external Java application.
The first thing to do is to create an EGL External Type so that the Java methods that are used to read the XML file can be called from the EGL Service program
Two functions have been crossed out from the list as they will not be discussed here.
Fig.2 – An EGL External Type used to read property values in an XML file.
Each entry following the ‘externalType’ entry represents methods to be used in this process. Each of these are described below.
- static function getInstance() returns(ConfigurationCache);
This function is used to get an instance of the Java class called ConfigurationCache. It is the program that handles all of the I/O to the XML file holding the application’s configuration values.
- function setRuntimeEnvironment(runtimeEnvironment String in);
Once an instance of ConfigurationCache is obtained use this method to inform it about the runtime environment in which it is running. This value is used to enable ConfigurationCache to read the correct set of values assigned for each server role.
This function gets properties that have been identified as basic properties common to all applications. Examples of these are shown here:
function setPropertyTableEntry(propertyName String in, propertyValue String in );
This function allows the developer to set an arbitrary name-value pair into the cache, however this function makes no sense in an EGL setting.
- function cacheAppPropertyValues(listOfPropertyNames String in);
This function is best explained with by the set of code that appears below. It shows the creation of a dynamic array that is used to hold 5 entries, each of which is a named property. In this case, the dynamic array of names will be used to hold just two values i.e. ‘version’ and ’emailAddress’ which are referenced using constants defined elsewhere in the program. (See the XML at the beginning of this post to see the entries for ‘version’ and ’emailAddress’.)
The idea is to ‘push’ the names of each property into the array and then pass the array of values to the function cacheAppPropertyValues(listOfPropertyNames String in); that reads and caches them. When control is returned to the caller, calls to the next function (presented below) will retrieve each individual value for the name specified on the function’s parameter.
Fig.3 – This code goes into the Service program called on startup.
- function getPropertyTableEntry(propertyName String in ) returns (String);
This function retrieves the value of the property specified by the passed parameter. Retrieval is dependent upon the preceding step that caches the property value. See the function cacheAppPropertyValues(listOfPropertyNames String in);, above.
This post showed how to set up an EGL External Type to describe the interface to Java methods that allows access to discrete data elements residing in an external XML file. The nature of the values contained within the XML file are used to control program behavior that must differ across multiple server environments. The solution presented prevents the need for the program to be modified each time it is deployed to a new environment.
Attached to his post is a .PDF document that illustrates how to use Subversion (SVN), which is a version control tool that has been integrated with “Rational Developer for i” (RDi) so that EGL project source can be safe guarded.
The document presents three main topics the first of which covers the installation of Tortoise, a graphical application that provides tools to be used by Subversion administrators to manipulate source code repositories. The tool is not often used once a repository has been created. Although Tortoise is intended for use only by administrators, the topic showing installation and use is presented as background information and for reference purposes. For this reason the developer can skip this topic if they choose. The topics that follow are intended for developers.
After RDi has been installed on the developer’s machine, the document’s second topic shows how to install a plug-in for RDi so that it sees the source code repository. Once installed, the third topic presented provides the ability to enroll projects into the SVN repository, commit changes and manage conflicts with other developers.
Rather than create a somewhat long web-page chock full of images to upload the document can be downloaded by clicking this link.
On some browsers the download may not present the first page. If this occurs simply scroll down using the mouse’s scroll wheel and the first page should appear.