I am now officially a pain in the EGL team's neck. Whether or not they say it publicly, I'm absolutely certain I've caused at least one person on the team to shake his or her head in dismay and considering adding me to the spam filter. But in the end, I think through extraordinary patience, they've managed to explain their vision of the future to me, which to be fair is not System i–centric.
At the same time, they've been willing to widen their view a little bit to encompass what are some unique requirements of those us in the System i community. This is a very difficult thing for a language design team; the grimy details of what is needed in the field so very often just don't coincide with the elegance of a new language. This isn't unique to language developers, certainly; my guess is I'm not the only one who has occasionally muttered to himself, "Programming would be a lot more fun if it weren't for those pesky users!" But language designers by definition must be more concerned with the vision of their product, and user requirements can indeed get very annoying. And in this case, I am the proverbial fly in the EGL ointment.
But I'll tell you that this willingness to take the time to listen and explain their position even when they disagree with me is what is really starting to brighten my outlook for the language and in turn for the future of this wonderful platform. If they're willing to consider my issues while I'm prototyping and learning, then I feel quite comfortable that they'll really be even more concerned about making the language work for you when you're implementing mission-critical systems.
So Where Were We?
In my last article, I gave an example of a largely theoretical connection between EGL and RPG. I showed how EGL's Record concept made it very easy to create simple, powerful Web pages and then connect them to a data source on the back-end. And while the primary focus of the EGL team is generating SQL code, I explained how most of the tooling could just as easily be used to call business logic written in your favorite System i language.
If you'll remember, however, I left off last month by making a little hack in the generated code. This in turn called some Java code. All of this was included, and the hack really wasn't that difficult:
Figure 1: This was the hack that I threw into the code in my previous article. (Click images to enlarge.)
And while this was a very simple hack, it had two strikes against it. First, the hack itself required writing Java code, and for some shops that's simply not an option. Even though I tried to explain that the amount of Java you'll need to learn and maintain is no more of a challenge than, say, learning OPNQRYF or learning to code a subfile, people still balk at the idea of using Java. More and more, this confuses me; people will happily spend hours, days, weeks learning some intricacy of SQL, but they immediately throw up their hands at the thought of learning a few lines of Java. But I digress. The second strike was the more deadly one: It required code that would be wiped out whenever you made a change to the EGL code and regenerated the application. I haven't even really broached to the EGL team the subject of somehow allowing such hacks into the code. It wouldn't be impossible to allow a sort of "inline" capability that would allow you to insert your own Java code, but even if they were to consider it, I doubt it would be high on the priority list—nor would I expect it to be. So without that ability, the fact that I had to change the generated code means that the hack I introduced last time just isn't feasible in a production environment.
The EGL Philosophy
So it's time to consider the available options. But before we do that, let me first show you the near-Nirvana that the EGL team has managed to put in place for SQL. The EGL concept centers on an object called an SQLRecord. First, let's take a look at what is required to define one:
Figure 2: This is a typical SQL record definition in EGL.
Figure 2 illustrates one of the standard ways to define SQL data using an SQLRecord. In the definition, you see the table name and the key field name, followed by definitions of each of the fields. Note that in this case, all of the fields use a "reference" type. For example, customer_id is defined as a field of type CUSTOMER_ID. A second file not shown here contains the definition of CUSTOMER_ID as an integer field. This is roughly equivalent to the concept of using a field reference file when defining a physical file on the System i. Just as you don't need to use a field reference file, you don't need to predefine your types either. This record could have just as easily been set up defining customer_id as a field of type int rather than type CUSTOMER_ID. Which style of field definition you choose is up to you. It's a bit verbose and perhaps a little tedious, but how often do you set up your database? The only time you need to modify this part of the application is when you change your database. The next picture, though, shows the ultimate benefits of the EGL philosophy.
Figure 3: This is the entire routine to load a Customer array.
Figure 3 contains the sum total of the code required to load an array of customers. This shows a library function called getAllCustomers, which loads an array of customer records with a single EGL instruction. In fact, most of the code here is overhead; I could just put the single line "get Customers" in my page handler. However, encapsulating it this way would allow for future expansion in case I decided I needed to do something a little more complex; then I could just change the library function, and any programs calling it would change. The point that I want to make, though, is that under the covers EGL actually generates all of the SQL required, as shown in Figure 4:
Figure 4: This is the SQL that EGL automatically generates.
As you can see, EGL actually does quite a bit under the covers. Note, though, that the SQL that is generated follows strict rules based on the information specified in the SQLRecord shown earlier in Figure 2. Things like key fields and so on are all specified in that record; you will notice that the order of the records is ascending by key. If you wanted the data in a different order, you would have to do a little tinkering.
The good news is that EGL does let you tinker but doesn't require you to. This is an example of what is being called the "DRY" philosophy: Don't Repeat Yourself. The concept is that, since I defined the key fields in the SQLRecord, then I should use this information wherever possible, but I can override it if necessary. This concept is also applied when creating CRUD pages (CRUD stands for Create, Read, Update and Delete and is the acronym used to refer to standard database maintenance functions). Key fields are protected on updates but unprotected when creating a new record. Add on the ability to specify a fairly robust set of validations, and you can knock together basic maintenance applications very, very quickly.
The Available Options
So SQL is pretty well taken care of. The problem now is how to take advantage of this powerful framework to attach to RPG business logic. Well, from a very high level, there are three ways to go about it:
Extend the EGL syntax to allow Records to specify a remote program (such as an RPG program on the System i) to handle the CRUD and query operations and generate all the necessary code automatically.
Provide keywords to call remote programs passing Records as structures, and allow programmers to code their own load logic.
Pass EGL objects directly to Java so that programmers can use packages such as the IBM Java Toolbox to access remote programs.
The third option is the most flexible and would allow not only the use of host programs, but also the ability to use just about any other possible mechanism as a data source. For example, a Web service would be a perfectly viable connection for business logic if it were appropriately wrapped in Java. The downside to this, of course, is that you need to wrap things in Java! For those shops that cannot justify the effort to learn even the simple procedural Java I was talking about earlier, this is certainly not going to be a viable option. However, if Java expertise is not a show stopper for you, then this might be a path to consider.
The first option is the one I like the best: extending the Record to support all the necessary keywords such as host machine identification and program name. There are a number of potent arguments for this, including the fact that you could give the program and a stubbed-out database to Web designers, let them do all of the design work, and then make that program talk to the System i by just changing the Record parameters. This, however, would require a bit of work, especially in the case of identifying the appropriate parameters for the new RecordType. I've pleaded my case, but the return on investment currently doesn't make sense to the EGL team. I hope they change their mind someday; I think it would be a piece of cake to sell EGL if switching from SQL to RPG were really only a matter of switching a couple of definitions in the Record.
The Second Option
All this brings us to the second option, which is already in place with a few minor issues. I've tested the code, and I have actually written an AJAX-enabled application that can access multiple RPG server programs to load data onto a page. Click on a line in one pane, and data is loaded into other panes on the page. Here's the code that's required:
Figure 5: The left pane shows data definitions; the right side shows the code that calls the RPG.
I used the field-reference technique but kept both the field reference and the individual records in the same source file. One thing I like about EGL is the fact that it's pretty flexible about where you put definitions. This could possibly be an issue in a larger project, so before you embark on such a mission, I highly recommend that you come up with some standards for which elements go into which parts and how they are named. Anyway, I've defined a bunch of basic types and then used those to define three records. TRNLIN and TRNSCH map directly to files on my System i; the third record, QueryOptions, is a standard data structure that is passed to all my query programs.
My servers all share the same basic design: EGL calls the server using the query options and the appropriate record, and the program returns either the next record from the file or an EOF condition. The query options start with an opcode "IN", which initializes the server and tells it to fetch the first record, while the opcode "NX" instructs the server to return the next available record. The return code in the query options data structure indicates whether a record was retrieved or not.
This is so common a business pattern that the EGL team is considering modifying the CALL opcode to support looping. Right now, I simply call the program and check the return code in an EGL loop, as shown in the right side of Figure 5. Received records are added to the array, which grows itself and also drives the display.
Problems
There are still a number of issues, ranging from minor to crucial, that need to be addressed before I can sign off on the tool for production work. The biggest problem is that AS400 objects are created for every page (AS400 is the name of the class used by the toolbox to encapsulate a connection to an eServer box, be it AS/400, iSeries, or System i). I need the AS400 object to be persistent across pages so that I don't need to keep opening and closing connections (and files and whatever else I need to have persistent access to). This enhancement is already scheduled.
The second is a strange bug (or feature) that occurs when I attempt to invoke the same JSP twice in a row. Even if I have different parameters on the URL, something causes the server to send me the same data without invoking the EGL program. The JSP is being run (I know that from some logging), but the onPageLoad function of the page handler is not getting invoked. For now, I can work around the issue by invoking a different JSP between page views, but it's definitely a long-term problem.
There is also one potentially very dangerous problem that has to do with placing JSPs in folders. The tool does not quite recognize these correctly and duplicates the JSP. In extreme cases, I have been able to cause EGL code to be deleted. I'm working with some of the EGL gurus to try to identify the problem, but until then I just have to be really careful not to break any rules or delete things I don't recognize.
If these issues get fixed, I believe I can use EGL to build some pretty good-looking applications. However, I am still withholding judgment until I get a chance to review the validation code and see how easy it is to build not just a functional UI but one that looks very good and at the same time provides all the business logic capabilities we're used to in our applications. But once that occurs, I will have a hard time understanding why anybody wouldn't want to at least take a look at EGL.
Joe Pluta is the founder and chief architect of Pluta Brothers Design, Inc. and has been extending the IBM midrange since the days of the IBM System/3. Joe uses WebSphere extensively, especially as the base for PSC/400, the only product that can move your legacy systems to the Web using simple green-screen commands. He has written several books, including E-Deployment: The Fastest Path to the Web, Eclipse: Step by Step, and WDSC: Step by Step. Joe performs onsite mentoring and speaks at user groups around the country. You can reach him at
LATEST COMMENTS
MC Press Online