HTTP Logs Made Easy
If you are like me and have used the IBM HTTP Server for AS/400, you no doubt have started logging activity and errors on your Web site. I found right away that storing these logs in DDS format wouldn’t work for me, so I used the Common log format, which produces logs in a standard format used by other HTTP servers. When I wanted to view these logs, I would view them by using Notepad, resulting in a continuous string of text that was hard to read.
As my site received more hits, my logs reached that magic point where “This file is too large for Notepad to open.” Using WordPad instead turned out to be great. Apparently, in the logs are end-of-line characters that Notepad doesn’t recognize but that WordPad thankfully does! Each entry in the logs was on a separate line, and that made studying the logs a lot easier.
— Bradley V. Stone Associate Technical Editor
Midrange Computing
Printer Open for Business
Q: In OCL36, there was a way (with // PRINTER CONTINUE-YES) to keep a file open between programs yet produce only one printout, etc. Is there a way to do this with RPG and CL?
— Larry Katerzynske
A: The OVRPRTF FILE(printer_file_name) SHARE(*YES) command allows you to reuse formats between programs. With this command, the printer file will remain open.
— Alan A. Urtubia
Lock Down Client Access Security Holes
If you have smart PC users at your office or users who think they’re smart, you may have come across folks who have discovered how to get to your AS/400 files and programs in the QSYS.LIB file system by using Windows Explorer. It’s actually very easy to do. With Client Access/400 installed on a user’s PC, you simply map a network drive to the AS/400, and you’re in. With Client Access Express, you also have easy access to the library file system if the user is set up to use file and print sharing via NetServer on the AS/400. A
user can even click the Windows Start button, click Find, click Computer, and type in the name of your AS/400. Windows will return a link to your system, and the user can easily navigate to QSYS.LIB.
Now, if you follow good security practices, your users probably can’t get into anything they are not specifically authorized to anyway. However, if you use the old
“menu-level security” method, which has been so prevalent in the past (especially with vendor-packaged software), you may have a serious security hole. The best thing to do is to create a security policy that defines what level of authority a given user has to a given object. If that doesn’t work, you should, at the very minimum, plug the hole in security that gives Client Access users access to QSYS.LIB from Windows Explorer. To do this, change the AS/400 authorization list from QPWFSERVER authority to *PUBLIC *EXCLUDE. This prevents all users from getting to QSYS.LIB from a PC. If you need to grant this type of access to specific users, add them to the authorization list authority for this object on a case-by-case basis.
— Shannon O’Donnell Senior Technical Editor
Midrange Computing
Using DELETE with a Key Value
I have seen many programs coded to use SETLL/READE or CHAIN and then DELETE when deleting records by a certain key value. You can use a key value with DELETE. Using DELETE with a key value deletes the first record found containing the specified key value; you do not need to use SETLL/READE, READ, or CHAIN before executing the delete. To delete multiple records with the same key value, use the following command:
*in99 doueq ‘1’
key delete file 99 (=)
endif
Doing this deletes all records containing the specified key value. You can use a field, data structure name, key list, or constant in factor 1.
— Greg Leister Design Systems Inc.
Time to LEAVE
In V4R4, an op code called LEAVESR was added to RPG IV. LEAVESR lets you “manually” control program flow by specifying the point at which logic jumps out of a given subroutine. Pretty handy, but I have been using a technique that gives me the same ability without having to write a whole lot more code. I use it most often in edit subroutines for situations where an error is found and I want to exit the subroutine. To perform this functionality that is equivalent to that of LEAVESR, I use a single DO statement at the top of a subroutine and place the ENDDO statement at the bottom of the subroutine. Now when I want to exit the subroutine, I simply use the LEAVE op code to leave that DO loop. When program flow reaches LEAVE, control is passed outside to the next statement past the ENDDO statement, which, in this case, is the ENDSR op code. This causes the program to exit the subroutine. Of course, once I move to V4R4, I’ll start using LEAVESR.
— Greg Leister Design Systems Inc.
Is My Web Site Up or Down?
Have you been looking for a simple way to read the HTML content of a Web site or to know whether your Web site is up or down? ScanURL is a small Java utility that does both. When run as a batch job, ScanURL generates a nice spool file that contains the HTML content of a Web site. If the Web site cannot be found or if the content cannot be retrieved, ScanURL sends a message to the QSYSOPR message queue. At my company, we use ScanURL to monitor our main Web site continuously and send a page to the operators when the site goes down.
Because the tool is written in Java, you can run it on the AS/400 or almost anywhere else. (I run it from my PC.) If you don’t know Java, don’t worry. The sample code, which is downloadable from the MC Web site at www.midrangecomputing.com/mc, has a CL driver (shown in Figure 1 [on page 111]) that you can easily customize to change the parameters used by the tool.
Assuming that you already have licensed program 5769JV1 (AS/400 Developer Kit for Java and AS/400 Toolbox for Java) installed, follow these steps to install ScanURL on the AS/400:
1. Download the ScanURL.zip file from the MC Web site and unzip it on your PC.
2. Copy the ScanURL.class file and the ScanURL.java file (shown in Figure 2) from your PC to the /home directory of your AS/400. The easiest way to do this is to map a drive from your PC to the AS/400 root directory or, as they say, to “ask your system administrator for assistance.” You can also use FTP to send the class and source files to a directory on your AS/400.
3. Edit the SCANURL ILE CL program (shown in Figure 1) and enter a valid AS/400 user profile and password as well as the URL of the Web site for which you want to retrieve the HTML source. You could also modify this program very easily to accept the URL as a parameter from a command interface.
4. To compile the SCANURL ILE CL program, use the following command: Assuming that you already have a Java Development Kit (JDK) or Java Runtime Environment (JRE; 1.1.7 or better) installed on your PC and already have the IBM AS/400 Toolbox for Java in the CLASSPATH on your PC, follow these steps to install ScanURL on a PC:
1. Download the ScanURLPC.zip file from the MC Web site and unzip it on your PC.
2. Edit the ScanURL.bat file and set your AS/400 user profile and password. You also need to edit the URL that you want to scan.
CRTBNDCL PGM(xxx/SCANURL) +
SRCFILE(xxx/QCLSRC)
SRCFILE(xxx/QCLSRC)
5. To run ScanURL in batch, use the following command:
SBMJOB CMD(CALL PGM(xxx/SCANURL)) +
JOBQ(QBATCH) ALWMLTTHD(*YES)
JOBQ(QBATCH) ALWMLTTHD(*YES)
ALWMLTTHD indicates that this job accepts multithreading.
6. To run ScanURL interactively, use the following command:
CALL PGM(xxx/SCANURL)
3. Run the ScanURL.bat file.
The program will still send a message to the QSYSOPR message queue on your AS/400 if the Web site can’t be found, even though it’s running on your PC.
— Alex Garrison Logistics Technology, Inc.
/********************************************************************/
/* */
/* To Compile: CRTBNDCL PGM(xxx/SCANURL) SRCFILE(xxx/QCLSRC) + */
/* SRCMBR(SCANURL) */
/* */
/* pgm : scanurl */
/* desc: retrieve the contents of a website. */
/* send a message to QSYSOPR if the website cant be retrieved.*/
/* When run as a batch job, optionally generates a spool file */
/* with the html content of a web site. */
/********************************************************************/
/* */
/* 1. replace the &username and password with a valid as/400 */
/* usrprf. */
/* 2. &urlname = website to be retrieved. For example */
/* ‘http://www.midrangecomputing.com’ */
/* 3. &echoon = generates a list of the html content if set */
/* to ‘ECHOON’. If you just want to want to monitor the website*/
/* and dont care about the actual html content, set this value */
/* to ‘ECHOOFF’. */
/********************************************************************/
pgm
DCL VAR(&USERNAME) TYPE(*CHAR) LEN(10) +
VALUE(‘USERPRF’)
DCL VAR(&PASSWORD) TYPE(*CHAR) LEN(10) +
VALUE(‘PASWD’)
DCL VAR(&URLNAME) TYPE(*CHAR) LEN(256) +
VALUE(‘http://www.shareware.com’)
DCL VAR(&ECHOON) TYPE(*CHAR) LEN(7) VALUE(‘ECHOON’)
MONMSG MSGID(CPF0000)
ADDLNK OBJ(‘/QIBM/ProdData/Java400/lib’) +
NEWLNK(IBMJAVA)
ADDENVVAR ENVVAR(CLASSPATH) +
VALUE(‘IBMJAVA/rawt_classes.zip:IBMJAVA/jav+
a.zip:IBMJAVA/sun.zip:/home:/QIBM/ProdData/+
Java400:/QIBM/ProdData/HTTP/Public/jt400/li+
b/jt400.jar:’)
QSYS/RUNJVA CLASS(ScanURL) PARM(localhost &USERNAME +
&PASSWORD &URLNAME &ECHOON)
endpgm ///////////////////////////////////////////////////////////////////////
// This Java application will read the HTML contents of any website
//
// To compile:
// CRTJVAPGM CLSF('/yourDir/ScanURL.java')
//
//////////////////////////////////////////////////////////////////////
import java.net.*;
import java.io.*;
import java.util.*;
import java.text.*;
import com.ibm.as400.access.*;
class ScanURL
{
private AS400 host = null;
private MessageQueue qsysoprMsgq = null;
private String as400Name = null;
private String userName = null;
Figure 1: Use this CL program to execute the ScanURL class on your AS/400.
private String password = null;
private String urlName = null;
private boolean echoContent = false;
public ScanURL(String argAs400Name, String argUserName, String argPassword, String argURLName,boolean
argEchoContent)
{
super(); if(argAs400Name.equals("") || argUserName.equals("") || argPassword.equals("") || argURLName.equals(""))
System.exit(0);
as400Name = argAs400Name;
userName = argUserName;
password = argPassword;
urlName = argURLName;
echoContent = argEchoContent;
host = new AS400(as400Name,userName,password);
try
{
host.connectService(AS400.COMMAND);
}
catch(Exception e)
{
try{System.out.println("Cant connect to as/400." + host + ". Exception detail =" + e);}
catch(Exception ex){}
System.exit(0);
}
Vector urlContent = new Vector();
readURL(urlContent);
if(echoContent)
{
for(int i=0;i
System.out.println(urlContent.elementAt(i));
}
}
}
public static void main(java.lang.String[] args)
{
String username = null;
String password = null;
String urlname = null;
String as400name = null;
boolean echoContent = false;
if(args.length < 4)
{
System.out.println("Not enough input parms. Parms are as400name,username,password,urlname,[ECHOON].");
System.exit(0);
}
as400name = args[0].trim();
username = args[1].toUpperCase().trim();
password = args[2].toUpperCase().trim();
urlname = args[3].trim();
if(args.length >= 5)
{
if(args[4].toUpperCase().trim().equals("ECHOON"))
echoContent = true;
}
ScanURL f = new ScanURL(as400name,username,password,urlname,echoContent);
System.exit(0);
}
//returns true if all content was read. Vector urlData contains the content.
public boolean readURL(Vector urlData)
{
boolean readOK = true;
SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
String today = df.format(new GregorianCalendar().getTime());
if(urlData == null)
urlData = new Vector();
try
{
URL testURL = new URL(urlName);
try
{
BufferedReader rdr = null;
Object inobj = testURL.getContent();
rdr = new BufferedReader(new InputStreamReader((InputStream) inobj));
String line = null;
while((line = rdr.readLine()) != null)
{
urlData.addElement(line);
}
System.out.println(today + " OK URL " + urlName);
}
catch(Exception e)
{
readOK = false;
try
{
String msg = new String(today + " Could not connect to website " + urlName);
if(qsysoprMsgq == null)
{
QSYSObjectPathName path = new QSYSObjectPathName("%LIBL%","QSYSOPR","MSGQ");
qsysoprMsgq = new MessageQueue(host,path.getPath());
}
qsysoprMsgq.sendInformational(msg);
System.out.println(today + " **ERROR URL " + urlName + ". Error =" + e);
}
catch(Exception e1)
{
try{System.out.println("Error sending msg to msgq=" + e1);}
catch(Exception ex){}
}
}
}
catch(MalformedURLException e)
{
readOK = false;
try{System.out.println(urlName + " is not a valid URL string.");}
catch(Exception ex){}
}
return readOK;
}
}
Figure 2: You will use Java code to read the HTML content from a Web site.
LATEST COMMENTS
MC Press Online