Category: Java

Pinging and Posting from PeopleCode

I had a need to Ping a server to see if the server could get to it.  I also tried to post to it.  This code could be helpful for others, so I want to share it.  A post should normally go through the Integration Broker, but I first developed it at a time when I had a product that was supposed to go on servers with diverse versions of Integration Broker.

The Ping code doesn’t seem very reliable for some reason.  Something on the Java side doesn’t always work.  Still it might be helpful.

   Local JavaObject &url;
   Local JavaObject &conn;
   Local JavaObject &r;
   Local any &line;
   Local string &output;
   Local JavaObject &inet;
   Local string &address;

   MessageBox(0, "", 0, 0, "hostname: " | GetJavaClass("java.net.InetAddress").getLocalHost().getHostName());

   &address = "localhost";
   &inet = GetJavaClass("java.net.InetAddress").getByName(&address);
   MessageBox(0, "", 0, 0, &address | "(" | &inet.getHostAddress() | ") reachable: " | &inet.isReachable(5000));
   &address = "www.google.com";
   &inet = GetJavaClass("java.net.InetAddress").getByName(&address);
   MessageBox(0, "", 0, 0, &address | "(" | &inet.getHostAddress() | ") reachable: " | &inet.isReachable(5000));

   &url = CreateJavaObject("java.net.URL", "http://www.google.com");
   &conn = &url.openConnection();
   &conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
   &conn.setRequestProperty("accept", "text/xml/html");
   &conn.setRequestProperty("accept-charset", "utf-8, iso_8859-1");
   &conn.setRequestProperty("userid", "????");
   &conn.setRequestProperty("pwd", "?????");
   &conn.setDoOutput( True);

   &output = "";
   &r = CreateJavaObject("java.io.BufferedReader", CreateJavaObject("java.io.InputStreamReader", &conn.getInputStream()));
   &line = &r.readLine();
   While &line <> Null
      &output = &output | Char(10) | Char(13) | &output;
      &line = &r.readLine();
   End-While;
   &r.close();

   MessageBox(0, "", 0, 0, &output);

Please make sure to adjust the URLs and hostnames to what you need.

Resources

Step By Step Install: Installing JRockit

This post is a continuation of my installation of PeopleSoft on a Windows 8 Beta installation.  Previously, I installed Tuxedo.  This post is about the JRockit JVM.  In PeopleTools 8.52, you might be able to get away with using the Regular Oracle Sun JVM, but WebLogic seems designed to work with the JRockit version.

As a caveat, I have taken so long to proofread my notes that now PeopleTools 8.52 and PeopleSoft 9.2 are out.  From what I can tell so far, you don’t to install JRockit with PeopleTools 8.53.

Read More

PeopleCode: Unzipping

I come upon a requirement to unzip a file in a platform independent way.  Jim Marion got me most of the way, but his code didn’t write it to file.  Here’s my adjustment to make a function that wrote it to file:

Function unzip(&inputZipFile, &targetDir)
  Local JavaObject &zipFileInputStream = CreateJavaObject("java.io.FileInputStream", &inputZipFile);
  Local JavaObject &zipInputStream = CreateJavaObject("java.util.zip.ZipInputStream", &zipFileInputStream);
  Local JavaObject &zipEntry = &zipInputStream.getNextEntry();
  Local JavaObject &buf = CreateJavaArray("byte[]", 1024);
  Local number &byteCount;

  While &zipEntry <> Null

    If (&zipEntry.isDirectory()) Then
      REM ** do nothing;
    Else
      Local JavaObject &outFile = CreateJavaObject("java.io.File", &targetDir | &zipEntry.getName());
      &outFile.getParentFile().mkdirs();
      Local JavaObject &out = CreateJavaObject("java.io.FileOutputStream", &outFile);
      &byteCount = &zipInputStream.read(&buf);

      While &byteCount > 0
        &out.write(&buf, 0, &byteCount);
        &byteCount = &zipInputStream.read(&buf);
      End-While;

      &zipInputStream.closeEntry();
    End-If;

    &zipEntry = &zipInputStream.getNextEntry();
  End-While;

  &zipInputStream.close();
  &zipFileInputStream.close();
End-Function;

unzip("/tmp/myzipfile.zip", "/tmp/out");

Resources

Running Jasper Reports from Java

As a follow-up to my previous post about using iReport, I wanted to write some code that would run the report.  My goal is something that I can launch from PeopleTools.

Below is some Java that will execute the report and build a PDF output.  This class takes the XML data file and the report designed by iReport and produces a PDF out of it.

package net.digitaleagle.psst0101;

import java.io.File;
import java.util.HashMap;
import java.util.Locale;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.query.JRXPathQueryExecuterFactory;
import net.sf.jasperreports.engine.util.FileResolver;
import net.sf.jasperreports.engine.util.JRXmlUtils;

import org.w3c.dom.Document;

public class JasperInterface {
	private String dataPath;
	private String basePath;
	private String reportName;
	private String reportOutput;

	public JasperInterface(String dataPath, String basePath, String reportName, String reportOutput) {
		this.dataPath = dataPath;
		this.basePath = basePath;
		this.reportName = reportName;
		this.reportOutput = reportOutput;
	}

	public void run() throws JRException {
		Document data = JRXmlUtils.parse(dataPath);

		HashMap parms = new HashMap();
		parms.put(JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT, data);
		parms.put(JRXPathQueryExecuterFactory.XML_DATE_PATTERN, "yyyy-MM-dd");
		parms.put(JRXPathQueryExecuterFactory.XML_LOCALE, Locale.ENGLISH);
		parms.put(JRParameter.REPORT_LOCALE, Locale.US);

		FileResolver fileResolver = new FileResolver() {
			 @Override
			 public File resolveFile(String fileName) {
			  return new File(basePath, fileName);
			 }
			};
		parms.put(JRParameter.REPORT_FILE_RESOLVER, fileResolver);

		JasperReport jr = JasperCompileManager.compileReport(basePath + reportName);
		JasperPrint pr = JasperFillManager.fillReport(jr, parms);
		JasperExportManager.exportReportToPdfFile(pr, reportOutput);
	}
}

Here’s some code that can launch the report without needing the JasperReports classes in the classpath.  I originally thought about just putting the jar files into the class directory in the PeopleSoft Home, but Jasper Reports has a number of Jar files.  So, I created a class that had no dependencies on JasperReports.  I tell it the location of the JasperReports installation, and it builds the necessary class path.

package net.digitaleagle.psst0101;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

public class JasperReportRunner {
	private String jasperPath;
	private String dataPath;
	private String basePath;
	private String reportName;
	private String reportOutput;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String jasperPath = args[0];
		String dataPath = args[1];
		String basePath = args[2];
		String reportName = args[3];
		String reportOutput = args[4];

		JasperReportRunner jrr = new JasperReportRunner(jasperPath, dataPath, basePath, reportName, reportOutput);
		jrr.run();
	}

	public JasperReportRunner(String jasperPath, String dataPath, String basePath, String reportName, String reportOutput) {
		this.jasperPath = jasperPath;
		this.dataPath = dataPath;
		this.basePath = basePath;
		this.reportName = reportName;
		this.reportOutput = reportOutput;
	}

	public void run() {
		ArrayList urls = new ArrayList();
		File jasperDir = new File(jasperPath);
		addJars(urls, new File(jasperDir, "dist"));
		addJars(urls, new File(jasperDir, "lib"));
		URLClassLoader ucl = new URLClassLoader(urls.toArray(new URL[0]));
		Class jic;
		try {
			jic = ucl.loadClass(this.getClass().getPackage().getName() + ".JasperInterface");
		} catch (ClassNotFoundException e) {
			System.err.println("Could not access JasperInterface class");
			e.printStackTrace();
			return;
		}
		Constructor c = jic.getConstructors()[0];
		Object ji;
		try {
			ji = c.newInstance(dataPath, basePath, reportName, reportOutput);
		} catch (Exception e) {
			System.err.println("Error creating new instance of JasperInterface");
			e.printStackTrace();
			return;
		}
		Method method;
		try {
			method = jic.getMethod("run");
		} catch (Exception e) {
			System.err.println("Could not get run method");
			e.printStackTrace();
			return;
		}
		try {
			method.invoke(ji);
		} catch (Exception e) {
			System.err.println("Could not get execute run method");
			e.printStackTrace();
			return;
		}
	}

	private void addJars(ArrayList urls, File jarDir) {
		if(!jarDir.exists()) {
			System.err.println("Could not find Jasper Jar files in directory: " + jarDir.getAbsolutePath());
			System.err.println("Check installation directory");
			return;
		}
		for(File jarFile : jarDir.listFiles()) {
			if(jarFile.isFile() && jarFile.getName().toLowerCase().endsWith(".jar")) {
				try {
					urls.add(jarFile.toURI().toURL());
				} catch (MalformedURLException e) {
					System.err.println("Error loading jar for class path: " + jarFile.getAbsolutePath());
					e.printStackTrace();
				}
			}
		}
	}

}

Resources

Using iReport with Query Output

Because Oracle has stopped delivering Crystal Reports with PeopleSoft, I heard a few discussions about whether or not to license it for a new installation.  So, it’s an perfect timing to explorer an alternative tool.

Let me introduce JasperReports.  It is open-source, Java-based report generation tool.  The reports are XML files, but they have a tool called iReport that, in my opinion, is very similar to Crystal Reports.

Here’s the descriptions from their website:

iReport:

iReport is the free, open source report designer for JasperReports. Create very sophisticated layouts containing charts, images, subreports, crosstabs and much more. Access your data through JDBC, TableModels, JavaBeans, XML, Hibernate, CSV, and custom sources. Then publish your reports as PDF, RTF, XML, XLS, CSV, HTML, XHTML, text, DOCX, or OpenOffice.

Jasper Reports:

JasperReports is the world’s most popular open source reporting engine. It is entirely written in Java and it is able to use data coming from any kind of data source and produce pixel-perfect documents that can be viewed, printed or exported in a variety of document formats including HTML, PDF, Excel, OpenOffice and Word.

So, as an introduction, let me give you a walk through introduction of using iReport to design a report based on a Query.

Read More

Step By Step: PeopleTools 8.51 Upgrade (Part 3)

This is a continuation of my PeopleTools 8.51 posts.  In this part, we are looking at installing WebLogic and the PIA.

Sorry it has taken a while to get this post proofread — I was sick this weekend and had family visiting as well.  I will try to keep the others coming soon.

Read More

JDBC and SQL Server

Well, I have explored JDBC connections to Access in the past, but here is a connection to SQL Server via ODBC.

A driver for SQL Server exists, but using that driver requires adding a Jar file to the server.  Assuming the App Server or Batch Server is running on Windows, you have to have an ODBC connection setup already.

Here is the code; hope it helps:

Local SQL &sql;
 Local string &loadCommand;

/* Using JDBC */

/* Load the driver */
GetJavaClass("java.lang.Class").forName("sun.jdbc.odbc.JdbcOdbcDriver");
Local string &connectionUrl = "jdbc:odbc:" | %DbName | ";
user="MY_ADMIN";
password="MY_PASSWORD";
Local JavaObject &conn = GetJavaClass("java.sql.DriverManager").getConnection(&connectionUrl);
Local JavaObject &connSource = GetJavaClass("java.sql.DriverManager").getConnection(&connectionUrl);
try
   &conn.setCatalog("MY_DB");
catch Exception &changeCatalogWarning
end-try;
Local JavaObject &stTarget = &conn.createStatement(GetJavaClass("java.sql.ResultSet").TYPE_SCROLL_INSENSITIVE, GetJavaClass("java.sql.ResultSet").CONCUR_UPDATABLE);
Local JavaObject &stSource = &connSource.createStatement(GetJavaClass("java.sql.ResultSet").TYPE_FORWARD_ONLY, GetJavaClass("java.sql.ResultSet").CONCUR_READ_ONLY);
Local JavaObject &rsTarget;
Local JavaObject &rsSource;
Local number &rowsLoaded;
Local number &rowsUntilCommit;
Local JavaObject &metaData;
Local number &columnIndex;

&loadCommand = "";
&loadCommand = &loadCommand | "SELECT top 50 * ";
&loadCommand = &loadCommand | "FROM OPENQUERY([MY_LINKED_SERVER], ";
&loadCommand = &loadCommand | "'SELECT * FROM MY_REMOTE_TABLE')";
&rsSource = &stSource.executeQuery(&loadCommand);
&loadCommand = "";
&loadCommand = &loadCommand | "SELECT * ";
&loadCommand = &loadCommand | "FROM [TARGET_TABLE]";
&rsTarget = &stTarget.executeQuery(&loadCommand);
&rowsLoaded = 0;
&rowsUntilCommit = 50;
&metaData = &rsSource.getMetaData();
While &rsSource.next()
   GetJavaClass("java.lang.Thread").yield();
   &rsTarget.moveToInsertRow();
   For &columnIndex = 1 To &metaData.getColumnCount();
      Evaluate &metaData.getColumnType(&columnIndex)
         When = - 6
            rem &rsTarget.updateInt(&columnIndex, &rsSource.getInt(&columnIndex)); 
            &rsTarget.updateInt(&columnIndex, CreateJavaObject("java.lang.Integer", 0).intValue());
         When = 4
            rem &rsTarget.updateInt(&columnIndex, &rsSource.getInt(&columnIndex));
            &rsTarget.updateInt(&columnIndex, CreateJavaObject("java.lang.Integer", 0).intValue());
         When = 6
            rem &rsTarget.updateFloat(&columnIndex, &rsSource.getFloat(&columnIndex));
            &rsTarget.updateFloat(&columnIndex, CreateJavaObject("java.lang.Float", " ").floatValue());
         When = 12
            rem &rsTarget.updateString(&columnIndex, &rsSource.getString(&columnIndex));
            &rsTarget.updateString(&columnIndex, CreateJavaObject("java.lang.String"));
         When = 93
            rem &rsTarget.updateTimestamp(&columnIndex, &rsSource.getTimestamp(&columnIndex));
            &rsTarget.updateTimestamp(&columnIndex, CreateJavaObject("java.sql.Timestamp", CreateJavaObject("java.util.Date").getTime()));
         When-Other
            rem &rsTarget.updateObject(&columnIndex, &rsSource.getObject(&columnIndex));
            Error ("Unknown column type: " | &metaData.getColumnType(&columnIndex) | " -- " | &metaData.getColumnTypeName(&columnIndex) | " for field " | &metaData.getColumnName(&columnIndex));
      End-Evaluate;
   End-For;
   &rsTarget.insertRow();
   &rowsLoaded = &rowsLoaded + 1;
   &rowsUntilCommit = &rowsUntilCommit - 1;
   If &rowsUntilCommit <= 0 Then;
      &conn.commit();
      CommitWork();
      &rowsUntilCommit = 50;
   End-If;
End-While;
&rsSource.close();
&rsTarget.close();
&conn.commit();
CommitWork();
End-While;

Resources

JSON

Here is another one of those technologies that I would love to play with but have to wait for a client that actually needs it: JSON.  I found Jim’s post on JSON very interesting and would love to have the need to come back to it.

One other solution that might be worth considering is this library for Java.  You would have to compile it and place it on the class path, but you could access it from PeopleCode.  Or, I wonder if it would be worth implementing the library in a PeopleCode Application Package?

And in conjunction, you can’t mention JSON, without mentioning jQuery.

JDBC From PeopleCode — Disadvantage/Advantage

Jim Marion’s post on JDBC made me think a little more.  (By the way, thanks, Jim, for linking me.)  The one disadvantage about accessing the PeopleSoft database via JDBC is that you have to supply the password to make the connection.

I have thought about trying to read the password from the application server or batch server configuration file, but if I remember right it only has the connect id and the connect password.  With the connect password, I might be able to use it to read the Access id and password from the database, but I have would have to be able to unencrypt it.

One advantage that SQL Server might have is that you can use Window’s security.  Assuming that the account running the application server or batch server has access to the database, you could just use the integrated security instead of an actual user name or password.

The advantage that JDBC has is that you don’t have to know the number of fields/columns that you want until run time.  With both the SQL object and SQLExec, you have to have a variable for each field you return or a return that contains all of those fields.

For example, I am trying to loop through a group of tables in a linked server and copy all of their fields to a table in the current database.  I have a problem using INSERT … SELECT, and I have to read the values in and then write them out.  I can’t figure another way to do it other than use JDBC.

Please correct me if I am wrong on any of this.  Maybe these thoughts will give someone else an idea that I overlooked.

Deleting Files from PeopleCode

We have an interface file that we want to delete for security reasons once we have processed the file.  But, deleting it from the Application  Engine was not as straight-forward as I would have thought.

This does not work:

RemoveDirectory("c:\temp\mytextfile.txt", %FilePath_Absolute);

So, Java to the rescue — this does:

Local JavaObject &javaFile;
&javaFile = CreateJavaObject("java.io.File", "c:\temp\mytextfile.txt");
&javaFile.delete();

Update (8/20/2014):

Back when I wrote this post, I missed seeing the .Delete() method of the File API object.  That would be the better way to make this work.  Here’s an example:

Local File &file;
&file = GetFile("c:\temp\mytextfile.txt", "W", "A", %FilePath_Absolute);
&file.Delete();

(Thanks Tim and Andrew for pointing this out.)

Resources