The Company
Products
Solutions
Services and Support
Customers
Partners
News
Events
Home >> News >> WebFOCUS Newsletter >> Fall 2004 >> Simultaneous Distribution: A ReportCaster Technique

Simultaneous Distribution: A ReportCaster Technique

By Joe Trelin

A frequent request we get from customers is for simultaneous distribution of a single report via multiple distribution types. For example, send the results of a single schedule to the library and via e-mail.

Unfortunately, ReportCaster doesn’t allow this within a single schedule. In addition, faced with the prospect of creating two schedules, customers balk at the resource demands and the potential discrepancies in data that might occur because the reports are not being run at exactly the same time.

Using the ReportCaster JavaBean™ API, there is a technique that allows customers to do this, and even ensure the data is the same when being run against volatile transactional systems.

In essence, what needs to be done is a three-step process:

1. Create a schedule that handles one of the two distribution types in the normal way. For example, distribution via e-mail.
2. Write a Java API program that creates a schedule that handles the other distribution type. For example, distribution to the library.
3. Enhance the FEX in the first schedule to call the Java program.

For example, Figure 1 shows a sample Java API application that writes a report to the library and then writes the scheduleID of the job that was created to the logs.

As a Java application, this code is called via the command line and subsequently can be called from a FEX. The example below shows one way to call a Java application from a FEX. In this example, the application is called with a batch file.

-DOS CALL D:\IBI\WEBFOCUS52\WEBAPPS\RCASTER52
\SAMPLES\JAVAAPP2.BAT
-RUN
SET PAGE-NUM = OFF
TABLE FILE CAR
HEADING
"PROGRAM RAN SUCCESSFULLY"
PRINT CAR NOPRINT
END

Now, when schedule A runs, its FEX will call the Java program that schedules the exact same report, but distributes it via library. If properly designed, perhaps via a self-service GUI, or with cleverly designed FEXes, users will be able to schedule a single report and choose multiple distributions, without realizing there is a technique calling two schedules behind the scenes.

But what about ensuring that the data is the same for both reports? For customers whose data lives in a warehouse, or is updated periodically, that shouldn’t be an issue. But for busy transactional systems we’ll need a solution. For the latter you’ll need to create a HOLD file within the first FEX and pass the location and name of that HOLD file to the Java application to use when it creates its report. In order to avoid contention issues, this HOLD file should be named dynamically with a time stamp appended. This way, when the Java application runs, it will always have a unique file to access.

In order to do this, in the FEX that is referenced by the schedule created by the Java application, create an ‘& variable’ that expects the name and location of the HOLD file. Modify the Java application’s Main() to accept an argument. This argument will be the location of the HOLD file. So when schedule A calls the Java application, it passes the path of the HOLD file it created. The Java application passes this location as a parameter into the library schedule it is dynamically creating, so that this value gets substituted into ‘& variable’ in the FEX associated with its schedule.

When run, the report associated with the schedule created by the Java application will reference the same HOLD file created in the first schedule. Hence, it will have the same data and will save resources by not requiring additional calls to the database.

As you become more familiar with this technique, there are other things you can do. One enhancement is to broaden the scope of this to include multiple schedules and multiple reports, rather than do this as a one-off. For example, rather than just write this for a particular report or a particular FEX, if you write a skeleton FEX that accepts -includes, and a skeleton Java application, you can distribute via multiple distribution types for any FEX that is available to a user.

In order to do this, consider the following: Change the Java application to accept two arguments. The first will be the location of the HOLD file, the second will be the scheduleID or job description of the first schedule. By passing this second value to the Java application, it can automatically query the properties of the first schedule and clone it so that the schedule it creates is exactly the same, including whatever report you are running. Then it simply changes the distribution type and schedules the new job.

Another enhancement is to create a third argument in the Java application that accepts the distribution type. This will allow the user to choose any distribution type rather than just having the option of also sending to the library. For example, rather than send the report to the library, you send it to the printer.

As for scheduling alternate FEXes, if you use a skeleton FEX that contains the basic components of this technique, the users can pass the actual report into the skeleton via an ‘& variable’ embedded within an -include. The actual name of the FEX can be accepted as a parameter during scheduling and then resolved within the skeleton FEX, placing the name of the FEX that is to generate the report after the -include.

In general, this branching technique is very powerful and flexible, and, once familiar, limited only by the imagination. For example, another possibility to consider is the ability to run a report once and have it delivered in multiple formats, perhaps both PDF and HTML.

The diagram shown in Figure 2 provides a general overview of this technique.

import java.util.Vector;
import ibi.broker.beans.DSTAPIStatus;
import ibi.broker.beans.DSTAuthenticate;
import ibi.broker.beans.DSTBeanHandler;
import ibi.broker.beans.DSTBeanResult;
import ibi.broker.beans.DSTSchedFactory;


/**
 * @author pgmyxc
 *
 */
public class DSTTest1 {

	/**
	 * 
	 */
	public DSTTest1() {}
public void createSchedule() {
		DSTAuthenticate auth = new 
		DSTAuthenticate();
		auth.setAgentProperty("localhost:8200");
		auth.setUser("admin");
		auth.setPass(""); 
		DSTSchedFactory schedFact = new 
		DSTSchedFactory();
		schedFact.setAuthenticate(auth);
		
		schedFact.setIBIB_casteruser("admin");
		schedFact.setIBIB_jobdesc("Insert report to library from 
		WFServer procedure");
		//schedFact.setIBIB_active("Y");
		//schedFact.setIBIB_priority("3");

		schedFact.setIBIB_frequency("1"); 
		schedFact.setIBIB_interval
		(DSTSchedFactory.INTERVAL_DAY); //Daily
		schedFact.setIBIB_weekdays("1111111"); // every day
		schedFact.setIBIB_dates
		("00000000000000000000000000000000");
		schedFact.setIBIB_startdate("20031009");
		schedFact.setIBIB_starttime("1039");
		schedFact.setIBIB_enddate("20991231");
		schedFact.setIBIB_endtime("2359");
		schedFact.setIBIB_listtype(DSTSched
		Factory.ADDRESSTYPE_ADDRESSBOOK);
		schedFact.setIBIB_distlist
		("MyAccessList1"); // access list name
		schedFact.setIBIB_method(DSTSchedFactory.
		METHOD_LIBRARY);
		
		// notification
		schedFact.setIBIB_notifyflag(DSTSched
		Factory.NOTIFYFLAG_INACTIVE);
		//schedFact.setIBIB_notifyaddress("");
		//schedFact.setIBIB_notifybrief("");
		//schedFact.setIBIB_notifyreply("");
		//schedFact.setIBIB_notifysubject("");
		
		//exptype M--monthly W--weekly D--daily 
		Y--yearly, 'V' 
		--version 'N' 			never

		schedFact.setIBIB_libexpiretype("V");
		schedFact.setIBIB_libexpireinterval("5");
		
		String[] parNames = {"MYFIELD", "MYCOUNTRY"};
		String[] parValues = {"BODYTYPE", "W GERMANY"};
		schedFact.setIBIB_paramname(parNames);
		schedFact.setIBIB_paramvalue(parValues);
		schedFact.setIBIB_tasktype(DSTSchedFactory.
		TASKTYPE_EDA_FOCEXEC);
		schedFact.setIBIB_taskobj("myfex");  // 
		focexec name
		//schedFact.setIBIB_burst("N"); // default 
		"Y" for burst report
		schedFact.setIBIB_asvalue("myReport1.pdf");
		schedFact.setIBIB_servername("EDASERVE");
		schedFact.setIBIB_sendformat(DSTSchedFactory.
		SENDFORMAT_PDF);
		schedFact.setIBIB_execid("guest");
		schedFact.setIBIB_execpass("guest");
		schedFact.setIBIB_category("My Report from 
		WFServer Procedure");	
		
		DSTBeanHandler h = schedFact.getCreate
		ScheduleHandler();
		h.processRequest();
		DSTAPIStatus status = h.getAPIStatus();
		int code = status.getErrorCode();
		if(code != DSTAPIStatus.NO_ERROR) {
			 System.out.println("Code = " + 
			 code + "; Message = " +
			 status.getErrorMessage());
			 return;
		}
		DSTBeanResult result = h.getBeanResult();
		Vector xml = result.getXML();		
		String sid = null;
		String stag = "<IBIB_scheduleid>";
		String etag = "</IBIB_scheduleid>";
		for(int i = 0; i < xml.size(); i++) {
			String temp = (String)xml.elementAt(i);
			int index = temp.indexOf(stag);
			if(index != -1) {
				int end = temp.indexOf(etag);
				sid = temp.substring(index + 
				stag.length(), end);
				break;
			}
		}
		System.out.println("Schedule ID = " + sid);
	}


	public static void main(String[] args) {
		DSTTest1 test1 = new DSTTest1();
		test1.createSchedule();
	}
}

Figure 1

Figure 2

Java and all Java-based marks are trademarks of Sun Microsystems, Inc. in the U.S. and other countries.