A service program: a program that can be called by many other programs and which basically serves as a holder for a variety of sub-procedures.
Editor's Note: This article is excerpted from article 9 of 21st Century RPG: /Free, ILE, and MVC, by David Shirey.
Service programs are a natural part of ILE and the culmination of what it promises.
And the drawback? Well, I guess it would be that just the idea of service programs scares some people, but there is no reason for that. To be perfectly honest, service programs are just a hair more complicated than either of the previous two options. And I am not being tongue in cheek when I say “just a hair.”
The truth is, in some ways, service programs are like one of those haunted Halloween houses, all smoke and mirrors. Once you get into it and understand the basics of prototyping (which you do by now), service programs are no big deal, and even someone like you can use them extensively. And people say I have no tact. Ha!
So let’s stop talking and get started.
The Service Program Scenario
This scenario consists of two programs, just like it did with the CALLP example in chapter 8.
There is the calling program: the program that would like to use the services (sub-procedures) contained in the service program.
And there is the service program itself, standing alone, cold, and aloof.
The difference between this scenario and the standard CALLP model is that we are going to actually bind the two programs together in a tighter bind than is possible with just the CALLP. This will make a call to a service program very fast. And it will also produce a bind that is more resistant to changes in the called module than if we had used the CRTRPGMOD/CRTPGM combo.
The end result will be a connection that is very fast and uses very little resources as it is processed. And that is why “time travel is not only possible but has probably already happened.” Or in this case, that is why “service programs are a big deal.”
The Service Program: DWS0260SRV
So far we have started with the calling program, but this time let’s start with our old friend the product number validation program and set it up as a sub-procedure in a service program. Are you listening to me? This program is not the program that calls the service program. The program below is the service program. Got that? You always create the service program first, although many times it already exists when you go to use it. OK, good, here we go. Oh, and I am naming this DWS0260SRV. We will need that name when we go to bind everything together.
Not really too bad. That’s all there is to a service program with a single sub- procedure. Of course, most self-respecting service programs will contain more than one sub-procedure, sometimes many more than one, but this will give you
the idea. In reality, for all their street rep, service programs are really just a sheath, something that goes around a group of procedures.
Where should you keep your service program source? Well, you could create another source file to put your service programs into, but that’s up to you. They don’t have a special source type; they are just RPGLE like everything else. The object type is different, of course: it’s *SRVPGM instead of plain old *PGM. Just don’t put them in QSRVSRC. You will want to keep this available for the binding language source that we will talk about later (as in chapter 20).
Now let’s play.
We start with another H-spec, and this one is required. What it basically says is that there will be no main logic to this program. This wipes out the RPG cycle, but who cares. It clears the way to have a program that consists of just (gasp) sub-procedures.
Remember before when we had the sub-procedure embedded in a program, we also had mainline logic. This is not the way it works in service programs: all you have is sub-procedures, and to make this legal, you need the NOMAIN spec.
Service programs are not created through the CRTBNDRPG command and cannot be created in an OPM environment. We will look at just how we create the service program in a minute, but for now, just know that because of this we do not need the DFTACTGRP H-spec.
Next, we have our F-spec for the file we will use in the sub-procedure.
If we were at a newer level of the operating system (V6.1 or above), we could just put this in the sub-procedure that is coming up, but with antiquated 5.4 we don’t have that option. Not a big deal. The advantage of putting it in the sub- procedure is that if you have several files defined in your service program, then you don’t open them all when the service program starts. You will wait till you get into the sub-procedure and then open just the ones required for that.
Then, without so much as a “have an apple,” we start the first sub-procedure by having the B P-spec. Remember that everything that comes after this is part of the sub-procedure. If the service program contained several procedures (which it almost always will), then you list them one right after the other. And remember that this is not a D-spec. It is a new type of spec, the P-spec, that defines when a sub-procedure begins and ends.
We are not going to talk about exporting now (that will happen when we talk about binding language in chapter 20), but we need to put EXPORT as a keyword on the beginning P-spec. Trust me. This is very important, and nothing will work in this example if you don’t do that. You’ll thank me later.
Next we have D-specs that define the prototype.
Technically you can put the PR up above in the global part of the program (that is, before the first P-spec), but I see no reason to split them up, so I put it in the sub- procedure with the PI.
The PR and the PI must be identical, and the name on the PR D-spec must be the same as the name on the associated PI D-spec. So, it’s not like you can get away with one global PR, even if the subfields on the different PIs were identical. But it’s up to you where you put it. I don’t really care.
Often, people will use a copybook to bring the PR or PI in, and it is up to you if you like that kind of action. In fact, that is probably the default with all the cool kids. Not the first time I have bucked the trend. I have included a commented-out Copy statement, just to show you how it would replace the PR D-spec. If you use the Copy statement, then you don’t need the D-spec.
This is followed by the logic statements, which you should be quite familiar with now. The key for the read was passed in via the prototype, and the message is set in this code.
Also, please note that there is no *INLR logic. No need for it. There is no main procedure in the service program. I’m serious. Can you dig it?
Finally, here is the end P-spec to close the sub-procedure. And that’s it. If there were more sub-procedures here, then we would start with another B P-spec. If this were the end of the service program, which it is in this case, then this would be the end. There is no *INLR or anything else. We don’t need the *INLR because there is no main procedure to end. Neat, eh?
Compiling the Service Program
Now before we go any further, that is, before we create the program that calls the service program, we need to look at how to compile the service program because it’s just a tad different from what we did before.
And this must be done before we compile the calling program, so we might as well get it out of the way now. The reason for this is that when we compile the calling program, we want to actually bind the object for the service program into the object for the calling program. So, the service program object must exist before we compile the calling program.
To create the service program object, issue the following two commands:
CRTRPGMOD MODULE(MyLib/'service program') SRCFILE(MyLib/QRPGLESRC) CRTSRVPGM SRVPGM(MyLib/'service program') EXPORT(*ALL)
Note: specifying EXPORT(*ALL) is important, and it is not the default. There are other values for the EXPORT parm, but right now just use *ALL and don’t worry about it. We will talk about it later. And yes, that was a threat.
And that’s all you need to do to create your service program object. I know it’s two steps and doesn’t use option 14 (for the PDM crowd), but heck fire, boy, it’s not like you are going to be doing this every day. Once you get them set, you probably won’t touch them. Maybe. Actually, it’s pretty simple, eh? A lot of it is just what we did when we created the program with the sub-procedure. You see, it all fits together once you get your head out ... well, once you start getting into it.
Debugging? If you want to debug a service program, you have to set the DBG parm in the CRTRPGMOD command to *SOURCE when you do the CRTRPGMOD for the service program. You do not, however, do a STRDBG command for the service program module. Instead, you can do it for the program that calls the service program and then use F22 instead of F10 to step into the service program.
Now let’s look at the program that calls the service program.
Program That Calls a Service Program
Ah, you thought we were done, didn’t you? But no, we still need to define the program that calls a service program. Although, as we will see, we are really not calling the “service program,” rather we are going to call a sub-procedure within the service program. This will be a stripped-down version that focuses just on the call. Remember, a normal program that calls a service program will probably have other logic in it that has nothing to do with that call.
And that’s it. I know. Looks too small, doesn’t it? Man, you people complain about everything, don’t you?
Now, piece by piece, just like always.
First, I have not included an H-spec. We are going to tie this program to the service program and so will be using a CRTRPGMOD rather than the CRTBNDRPG. As a result, the program will by default be ILE, and the H-spec is not required. You could still use the H-spec to set the activation group we will use if you don’t want to specify it in the CRTRPGMOD command. I will leave that to you.
F-specs, just like always, for the display file where we are getting the product number we need to verify.
Then we have the D-specs. Note that this is a prototype D-spec, so we also need to define the fields to the program via a separate definition.
Also note that there are no P-specs in this program (because there are no sub-procedures, they are in the service program).
Then the code. Just a simple CALLP to the service program with the parameters defined in the PR D-spec. And that’s it. Pretty simple, eh? You betcha, by golly. Just be sure that you notice that we didn’t CALLP DWS0996SRV, which is the actual name of the service program. Instead, we accessed the sub-procedure in that program that we needed, VAL_PRDNO. There are two theories on why it is this way.
One is that this is just the way it is, and so the service programs hate the sub- procedures they contain and who get all the publicity. IBM thus created a situation analogous to one where a caretaker is forced to care for someone they despise, a situation that almost always ends in a grisly murder.
The other, and this is probably a bit far-fetched, is that the service programs were originally created as part of a secret government project, and so their identities have to be concealed from the general public. I know, that is ridiculous. After all, if it were true then we would undoubtedly have heard about it in X2: X-Men United when they breached that secret government fortress. But as I have said before, some people will believe anything.
Compiling the Calling Program
Once you have the program coded that is going to call a service program, you have to compile it, and you can’t use CRTBNDRPG. Because it involves something a little different (object binding), you are going to have to execute the following commands:
CRTRPGMOD MODULE(MyLib/'calling program') DBGVIEW(*SOURCE) SRCFILE(MyLib/QRPGLESRC)
CRTPGM PGM(MyLib/'calling program') BNDSRVPGM('service program') ACTGRP(*NEW)
You can see why the service program needs to be created first, and you can see how it is bound into the calling program where the CRTPGM command lists the calling program in the module section and the service program in the BNDSRVPGM parameter.
Growing and Organizing Your Service Program Farm
Want to start a fight in a Service Program Bar? Just get people talking about how they will organize and grow their collection of service programs. There are definitely several schools of thought, and it is hard to say who is right and who is righter.
Where should you put your service programs?
Probably the best place is just in QRPGLESRC. Some folks like to put them in a separate source file, but I am not sure I see a need for that. And it may mean that you occasionally have to override a default to QRPGLESRC in the compile commands.
But it’s up to you. If you like the idea of having all your service programs in a separate source file, go for it. Just don’t use QSRVSRC. It will interfere with your using binding language.
Do you want to have just one service program for your whole system or many service programs?
Some people prefer one gigantic service program. Hard to argue that doesn’t make it easy to find a specific sub-procedure. On the other hand, it is sort of weird to have a huge service program when everyone is hawking modular. But there’s nothing really wrong with it. Not my cup of tea, though.
Most people like to have a number, perhaps even a large number of service programs, generally with each one targeting a different area. For example, you may have one that contains all the sub-procedures that update the Product Master. And another that affects inventory. You get the idea.
Neither is better than the other, probably. In the end it often boils down to your particular environment and what feels most intuitive to you. Just don’t make it hard to find a particular sub-procedure. That will drive you crazy.
What is unlikely is that you will have only one sub-procedure in each service program.
One thing you should know about sub-procedures is that they are very gregarious. And they get lonely very quickly. Yes, they are needy in that way.
So it makes sense to put a bunch of them together. You get to decide how many is too many and how many is not quite enough.
Is there a particular scheme that should be used to name sub-procedures and service programs?
The name of the service program is not all that important in my mind because you don’t call the service program by its name but rather by the name of the sub-procedure. If you did not have them in a separate source file, it would be good to put some sort of designation on them that identified them as service programs. Maybe. Maybe not. You could always keep a certain program ID sequence for all service programs. Or you may want to put “SRV” or “SP” or something somewhere in the name.
Sub-procedure names require a bit more thought. Some people like the fact that you can give them English language-type names like VAL_PRDNO or CHECK_CREDIT, and I do agree that is nice. This makes it a lot easier to see what the sub-procedure does than if you call it DWS00337. And yet, there is something to be said for including the name of the service program in there somewhere. Maybe SP337_VAL_PRDNO or something like that, where your service program name is DWS0337SP. Just a suggestion.
Bottom line: naming is not the most important thing, but it is close. The one thing you don’t want to do is create a bunch of sub-procedures and service programs and then spend the rest of your days looking for this sub-procedure or that. Give it some thought and decide what naming convention you like. Then stick with that.
Do you really need to use service programs?
And the answer is, of course not. You don’t have to use any of this stuff. But can you give me a good reason for not using them?
Despite their street rep, service programs are not at all hard to do. Yes, there is an extra compile step or two, but good grief, you can’t let that scare you away. Look at what the troops in WWI had to endure. And you think you’ve got it tough.
Service programs are the best way to encapsulate logic that can then be used by many programs in a very fast and efficient connection. What’s not to like?
My opinion is that you should start thinking today of what logic you can convert to sub-procedures and of what service programs you can start building and incorporating into your environment. Putting this off only robs you of the benefits they bring to your system.
What Ya Shoulda Learned
OK, I have to ask.
How are ya feelin’ right now? Have you dealt with service programs before? Or did you feel that you were just too butt dumb stupid to ever use them?
Well, I hope that now you realize that even someone like yourself can understand and use service programs. I mean, it’s not like it’s that hard. There are just a few things you need to know and do.
First, did you go through and actually create a service program and a calling program? It’s really important that you do that. Remember what Han Solo said. “Look, good against remotes is one thing. Good against the living? That’s something else.” And the same is true for service programs (or any of this stuff). Just reading about it is cool, and all but you are not going to learn it just from reading. You have to do the code.
It is almost a certainty that even if you follow exactly what I have done, you will still have problems. Don’t panic. Take a deep breath, pour out another couple of ounces of scotch or bourbon, and work through it. That’s what I do. The new is always unfamiliar.
You should especially understand the compile and binding required to make the service programs work. In reality, what we have done in this chapter is just one type of service program connection (relax, there are really only two). Near the end of this book we will look at the other option.
Finally, before the frost is off the pumpkin, take some time to really think about the naming conventions and service program organization you want to use. Best to get this laid out right off the bat.
Want to learn more? You can pick up Dave Shirey's book, 21st Century RPG: /Free, ILE, and MVC, at the MC Press Bookstore Today!
LATEST COMMENTS
MC Press Online