Main

E Business Suite Archives

June 16, 2006

How to install a font using XML Publisher Administrator?

Many of you will have seen the Administrator module on the Template manager in the E Business Suite ... the new properties UI is great and much easier to use but you can now also manage those troublesome MICR, Barcode and other fonts through the manager too.


Thanks to Kevin McDermott from Oracle Support for laying out the following very useful instructions:


XML Publisher 5.6 has a new tab: Administration. This replaces the xdo.cfg configuration file. Now fonts can be uploaded and stored in the database instead of stored on the file system.


Under the Administration tab are sub tabs: Configuration, Font Mappings and Font Files and Currencies.


To install a font requires only a few steps.


1. Log in as XML Publisher Administrator.


2. Navigate to Administration->Font Files->Create Font File.


3. Fields are Font Name and File.
       For Font Name choose any descriptive name.
       File will browse your PC to locate the font file.


4. Navigate to Font Mappings->Create Font Mapping Set.


5. Mapping name is the name you will give to a set of fonts.


6. Mapping code is the internal name you will give to this set.


7. Type: 'PDF Form' for PDF templates. 'FO to PDF' for all other template types.


8. Create Font Mapping (this allows you to add multiple fonts to a set).


9. Font Family is the exact same name you see in Word under Fonts.
If you don't use the same name the font will not be picked up at runtime.


10. Style and weight must also match how you use the font in windows.
Normal and Normal are good defaults.


12. Navigate to Configuration General-> FO Processing->Font Mapping Set.
Can also be done at data def and template level under Edit Configuration.
Hierarchy is Site-> Data Def -> Template.


13. Select your new mapping set.


14. Make sure the font is not referenced under File->Properties->Custom in the RTF template file.


15. Upload a template that uses your special font and test using preview.

July 19, 2006

Open World is coming to town ... with lots of XMLP

Its coming ... its even bigger I hear rumors of Oracle taking over a block of Howard Street in San Francisco to "extend" the Moscone Center for the week :o)
This year there will be two XMLP events for EBS and PeopleSoft customers at the Extreme Weekend - lots of hands on stuff to dip your proverbial toes in the XMLP water. Places are limited so book early.
There are also over 20 sessions related to XMLP and its use throughout the all of Oracle including EBS, JDE, PeopleSoft and Enterprise. The sessions are not just from development, we have customer and a partner sessions lined up. Last year they were turning folks away from the doors so get there early too.
Of course the demo pod will be swamped all week but drop by, hang out, have a chat and get a demo or three!













































































Session ID Session Title

S281400
Oracle XML Publisher - Enterprise Reporting and Delivery Platform

S281401
Customer Case Study: XML Publisher Live with all the Bells and Whistles

S281461
Implementing XML Publisher for PeopleSoft Enterprise

S281593
Oracle XML Publisher for E-Business Suite, with Customer (City of West Palm Beach) as a Case Study

S281725
Developing XML Applications using Oracle Fusion Middleware

S281740
Leverage Fusion Middleware Technologies Now with PeopleSoft Financial Management Release 9

S281765
Financial Reporting in Oracle E-Business Suite Financials

S281903
Oracle Enterprise Planning & Budgeting -- What's New

S282107
Understanding the EnterpriseOne Reporting tools and choosing the best tool for your needs

S282232
Oracle E-Business Public Sector Financials in Release 12

S282284
Better Enterprise Reporting through XML Publisher

S282444
Oracle Inventory & Warehouse Management: What's New in Release 12

S282562
Oracle E-Business Suite Release 12 CRM Overview

S282771
Technology Trends in Primary/Secondary/K-12 Education

S282878
E-Business Suite: Tools and Technology

S282881
PeopleSoft Enterprise: Tools and Technology

S282964
Enterprise HCM 9.0 Common Components

S283007
Fusion Technology in PeopleSoft SCM and SRM Products

S283117
Fax, Print and Email from Oracle E-Business Suite Using XML Publisher  

S283151
The Impact of Oracle Fusion Middleware on Implementation Project Strategies for Data Cleanup, Conversion, Integration, Business Intelligence, and Instance Management  

S283168
OAUG XML Publisher SIG  

S283183
JD Edwards EnterpriseOne Tools and Technology X-treme Weekend Program


The above sessions are of course subject to some change but you get the idea.

July 21, 2006

Correcting XML Date Formats from a VO object

Finally, an EBS posting!


For those of you using XMLP in your OA Framework pages you may have noticed (as did one of our EBS developers) that the VO method writeXML is great but the dates are pushed out in a non XMLP format i.e. 2006-06-05 07:01:12.0. XMLP needs to have the XSD date format,'YYYY-MM-DDTHH:MM:SS' to allow you to format the date correctly in the layout template.


To get this format Steve Meunch came to the rescue, thanks Steve.


Customizing the getter method of the view object's row class to return a Date with a custom implementation of the
getXMLContentNode() method, using whatever format you like for the date value. Will get you the correct date format.

For example, if you created an EmpView having Empno, Ename, and Hiredate attributes, your EmpViewRowImpl.java class could overide the getter method for the Hiredate attribute like this:

Change:

 public Date getHiredate() {
   return (Date)getAttributeInternal(HIREDATE);
}

To this:

 public Date getHiredate() {
   return new Date((Date)getAttributeInternal(HIREDATE)) {
     public Node getXMLContentNode(Document xmlDoc) {
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
       return xmlDoc.createTextNode(sdf.format(timestampValue()));
     }    
   };
}

Doing so would coax writeXML() to change its output from:

<EmpView>
  <EmpViewRow>
     <Empno>7369</Empno>
     <Ename>SMITH2</Ename>
     <Hiredate>2006-07-21 10:50:32.0</Hiredate>
  </EmpViewRow>
</EmpView>


To this:

<EmpView>
  <EmpViewRow>
     <Empno>7369</Empno>
     <Ename>SMITH2</Ename>
     <Hiredate>2006-07-21T10:50:32</Hiredate>
  </EmpViewRow>
</EmpView>

August 3, 2006

Document Delivery from EBS - Part 1

So many questions on the forum about the delivery manager and its integration into the concurrent manager in EBS, so over the next few postings Im going to try and clear the air and show you some of the options you have to get documents delivered from the concurrent manager, forms or OAFramework. 

Introductions
We need an introduction to the delivery manager before we start. Its a rich set of java APIs that can be used to send documents via:


  • Email - pretty obvious, supports multiple document attachments, embedded HTML, multiple recipients, etc
  • Fax - not up to communicating with a multifax board for high volume but definitely adequate
  • Print - again obvious, uses the IPP for communication to the printer, has tray handling, copies, duplex, orientation, etc
  • WebDAV - allows you to post documents to a repository such as Oracle Files Online, other 3rd party management solutions
  • HTTP/HTTPS - posting docs to a web server
  • FTP/SFTP - posting docs to an FTP
  • Custom - if you have your own channel or a third party delivery solution you (or they) can create a custom delivery channel interface and XMLP will direct documents down that channel.

It even has the AS2 protocol implemented for your EDI messages. The APIs can rely on a configuration file to define servers, printers, etc or you can hardcode the information directly in your API call. 

Clarifications
A very rich set of APIs that are being expanded with every release ... thats the good news. The bad news is that none of it is directly integrated into the concurrent manager, OA framework or forms ... if you want to use the functionality you are going to have to get into some java coding and customization.

OA Framework
As OAF is completely java anyway its not going to be a tough job to create some UI for folks to deliver docs.

Forms
As EBS11i uses Forms 6i, our options are a little limited to integrate the delivery APIs directly. We could create some plsql wrappers for the APIs ... thats been done by a couple of Apps teams already. Or we could just call a concurrent program from the form. 

Concurrent Manager
This is the most popular method of generating reports, lets just cover what is going on process wise in the concurrent manager today (11i.10.X) with an XMLP report.



  1. User selects an XMLP report to execute and enters the parameter values they want, the layout template, output format and language then submits
  2. Concurrent manager 'looks up' the concurrent program definition, finds the executable and calls it. This could be an XMLP Data Template, Oracle Report, pl/sql or any other extraction routine ... just so long as its getting XML data.
  3. Once the program has completed the Output Post Processor(OPP) comes into play. This is the new concurrent manager that handles the XMLP requests. It is passed a handle to the data file and calls the XMLP APIs to process the data to then generate the output based on the users choice of template, format, etc. The output document is then generated and the XML data is preserved.
  4. The user can then either view the document from the SRS forms and print locally or they might have asked that the document be printed directly to a printer. Hopefully the SysAdmin has set up PASTA to handle the document, pre-process it to a printer language and then pass it off to the printer.


Thats the current process in a nutshell. If we want to add delivery other than printing there are a couple of entry points for us to inject our own delivery options at:
Step 2: We can create a wrapper java concurrent program. This would be called by the concurrent manager instead of the current one. It would:


  • Call the extraction conurrent program and wait for it to finish
  • Call the XMLP formatting APIs to generate the output document i.e no OPP involvement
  • Call the delivery APIs to deliver the document.
This approach has some advantages, you have complete control over everything that is going on, you can add parameters to the program so the user can select the delivery destination for the document at runtime, etc ... but there is a big disadvantage ... you are going to need a wrapper for every program or create a request set for every report containing the base report and the delivery program as a second program that can accept the request id of the first ... thats a hurdle in itself ... the programs in the request set are not 'aware' of each other and at runtime the CM does not pass info about them to each other e.g. request IDs ... been there done that ... its a nasty piece of code that has to make too many assumptions to work.

Step 4: We can create a virtual print destination in EBS that does not have a printer at the end of it but rather a shell or perl script that can take the document and deliver it down a channel based on the user's choice at runtime.
This has the advantage that we do not need to create custom programs, mess with the definitions, etc. It's another moving part but its at least everything we create is sitting at the end of the reporting flow.  

The second option seems to be the most popular entry point for many third party delivery solutions. Im going to pursue this line of investigation over the next few postings.
Next ... getting into the delivery APIs!

August 4, 2006

Document Delivery from EBS - Part II

Carrying on from where we left off yesterday in ths series of articles on the XMLP delivery manager, today we'll take a look at the APIs themselves and how you can use ... we're not going to touch EBS yet, just get some basics around the APIs. Before we start, arm yourself with the following documents:

XML Publisher Users Guide incl Developers Guide
XML Publisher release 5.6.1 Core Components API (javadoc)

Overview
The basic flow to deliver documents is as follows:



  1. Create DeliveryManager instance
  2. Create DeliveryRequest instance by createRequest() method
  3. Add request properties such as where to send to the DeliveryRequest. Most of properties require a string value. Take a look at the supported properties of each delivery channel for more detail.
  4. Set your document to the DeliveryRequest
  5. Call submit() to submit the delivery request.

One delivery request can handle one document and one destination. This is because it makes simple and easy to track down each delivery status and re-submit the request if it failed to deliver.


The DeliveryRequest allows you to set the documents in two ways, these are;


  • Getting OutputStream from the DeliveryReqeust and writing the document to the OutputStream. You don't need to close the OutputStream, but you can just call submit() method right after you finish writing the document to the OutputStream.-->
  • Setting InputStream of the document to the DeliverRequest. The DeliveryRequest will read the InputStream when you call submit() for the first time. The DeliveryRequest doesn't close the InputStream so you need to take care of closing it.
  • Setting the file name of the document to the DeliveryRequest. The DeliveryRequest will pick up the document from the file system when you call submit().

Those are the basic steps you need to follow, how about in practice?


EMail
With all of the delivery channels its a case of setting the required properties and then calling the apprpriate API. 


create delivery manager instance
   DeliveryManager dm = new DeliveryManager();
   // create a delivery request
   DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_SMTP_EMAIL);
   // set email subject
   req.addProperty(DeliveryPropertyDefinitions.SMTP_SUBJECT, "Invoice");
   // set SMTP server host
   req.addProperty(
     DeliveryPropertyDefinitions.SMTP_HOST, "mysmtphost");
   // set the sender email address
   req.addProperty(DeliveryPropertyDefinitions.SMTP_FROM, "myname@mydomain.com");
   // set the destination email address
   req.addProperty(
     DeliveryPropertyDefinitions.SMTP_TO_RECIPIENTS, "user1@mydomain.com, user2@mydomain.com" );
   // set the content type of the email body
   req.addProperty(DeliveryPropertyDefinitions.SMTP_CONTENT_TYPE, "application/pdf");
   // set the document file name appeared in the email
   req.addProperty(DeliveryPropertyDefinitions.SMTP_CONTENT_FILENAME, "invoice.pdf");
   // set the document to deliver
   req.setDocument("/document/invoice.pdf");
    // submit the request
   req.submit();
   // close the request
   req.close();



Simple stuff right?

This was just a simple example, you have complete control over the email and its attachments, there are more examples in the developer guide and the javadocs for the APIs.


FAX
The Delivery API supports the delivery of documents to fax modems configured on CUPS using the Internet Printing Protocol. XMLP uses a CUPS instance on Linux or UNIX to act as the delivery server. Its straightforward to set up, check the developers guide for instructions.
You can configure the fax modems on CUPS with efax and FAX4CUPS. By the default setting, CUPS can fax the document in Postscript and PDF document formats.  We have not done much research on Fax over a Windows Server, there are commercial software packages that can use the IPP. Another alternative is to use one of the many Fax over Email solutions out there, we have several customers using it very sucessfully.


Sample FAXing code 

// create delivery manager instance 
DeliveryManager dm = new DeliveryManager();
// create a delivery request
DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_IPP_FAX);
// set IPP fax host
req.addProperty(DeliveryPropertyDefinitions.IPP_HOST, "myhost");
// set IPP fax port
req.addProperty(DeliveryPropertyDefinitions.IPP_PORT, "631");
// set IPP fax name
req.addProperty(DeliveryPropertyDefinitions.IPP_PRINTER_NAME, "/printers/myfax");
// set the document format
req.addProperty(DeliveryPropertyDefinitions.IPP_DOCUMENT_FORMAT, "application/postscript");
// set the phone number to send
req.addProperty(DeliveryPropertyDefinitions.IPP_PHONE_NUMBER, "9999999");
// set the document
req.setDocument("/document/invoice.pdf");
// submit the request
req.submit();
// close the request
req.close();

WebDAV
This delivery channel can direct your documents to any repository that supports the WebDAV protocol, whether that be Oracle Files Online, XDB or a third party solution. The document can be pushed into a directory on the repository as an archive or into a personal folder for viewing later by the recipient.
Again, its a simple case of setting properties and then calling the APIs submit method:

   // create delivery manager instance
     DeliveryManager dm = new DeliveryManager();
     // create a delivery request
     DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_WEBDAV);
      // set document content type
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_CONTENT_TYPE, "application/pdf");
     // set the WebDAV server hostname
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_HOST, "mywebdavhost");
     // set the WebDAV server port number
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_PORT, "80");
     // set the target remote directory
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_REMOTE_DIRECTORY, "/content/");
     // set the remote filename
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_REMOTE_FILENAME, "xdotest.pdf");
     // set username and password to access WebDAV server
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_USERNAME, "xdo");
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_PASSWORD, "xdo");
     // set the document
     req.setDocument("/document/test.pdf");
     // submit the request
     req.submit();

     // close the request
     req.close();


FTP
Another protocol that is very widely used to move files to specific locations for a daemon to recognize and have picked up by another process.

     // create delivery manager instance
     DeliveryManager dm = new DeliveryManager();
     // create a delivery request
     DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_FTP);

     // set hostname of the FTP server
     req.addProperty(DeliveryPropertyDefinitions.FTP_HOST, "myftphost");
     // set port# of the FTP server
     req.addProperty(DeliveryPropertyDefinitions.FTP_PORT, "21");
     // set username and password to access WebDAV server
     req.addProperty(DeliveryPropertyDefinitions.FTP_USERNAME, "xdo");
     req.addProperty(DeliveryPropertyDefinitions.FTP_PASSWORD, "xdo");
     // set the remote directory that you want to send your document to
     req.addProperty(DeliveryPropertyDefinitions.FTP_REMOTE_DIRECTORY, "pub");
     // set the remote file name
     req.addProperty(DeliveryPropertyDefinitions.FTP_REMOTE_FILENAME, "test.pdf");
     // set the document
     req.setDocument("/document/test.pdf");

     // submit the request
     req.submit();
     // close the request
     req.close();

HTTP
Finally, HTTP ... The Delivery API supports to deliver documents to the HTTP servers. The following sample is sending a document through HTTP POST method. Technically, you can send not only documents, but also anything you want. But the servers should be capable to accept your custom HTTP requests in advance, such as your custom Servlet or CGI program.

 // create delivery manager instance 
DeliveryManager dm = new DeliveryManager();
// create a delivery request
DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_HTTP);
// set request method
req.addProperty(DeliveryPropertyDefinitions.HTTP_METHOD, DeliveryPropertyDefinitions.HTTP_METHOD_POST);
// set document content type
req.addProperty(DeliveryPropertyDefinitions.HTTP_CONTENT_TYPE, "application/pdf");
// set the HTTP server hostname
req.addProperty(DeliveryPropertyDefinitions.HTTP_HOST, "myhost");
// set the HTTP server port number
req.addProperty(DeliveryPropertyDefinitions.HTTP_PORT, "80");
// set the target remote directory
req.addProperty(DeliveryPropertyDefinitions.HTTP_REMOTE_DIRECTORY, "/servlet/");
// set the remote filename (servlet class)
req.addProperty(DeliveryPropertyDefinitions.HTTP_REMOTE_FILENAME, "uploadDocument");
// set the document
req.setDocument("/document/test.pdf");
// submit the request
req.submit();
// close the request
req.close();
So thats the APIs and brief introduction to their use, some of you will have noticed a glaring exception to the list ... where the printing APIs?

They are present and use the IPP much like the fax. They are in my opinion superior to the current concurrent manager printing abilities but, I suspect that many of you have already been through the fun and games (NOT!) that is printer setup in Apps and have got them working ... it might not be quitre what you users want in the age of tray switching and duplex printing but if it ain't broke dont fix it! For those that are interested I'll cover printing another time. The other delivery channel I'll cover later is the custom channel, many of you will have thrid parties delivery software that you would like to hook up to the XMLP flow (if they have not done it for you), the custom channel can help.

Next week ... how to get these APIs running in the EBS and delivering your docs for you.

August 16, 2006

Document Delivery from EBS - Part III

Apologies for the break, trying to wrap up on some template standards for the EBS division ...


We now have an idea of the Delivery Manager APIs and what they can do and the limitations within the EBS infrastructure for using them to deliver documents. Now we need to know how we can hook up the delivery APIs to the concurrent manager. As I have mentioned before the delivery manager is not integrated into the concurrent manager. We need to use another method to get the document generated by the concurrent manager to the delivery manager. The concurrent manager expects to direct a document to a printer, the setup of printers has some flexibility and we can take advantage of that, rather than have a printer at the end of the flow we can have a shell script that can then direct the output to another delivery stream. 


Setup XMLP as a virtual printer


Using the System Administrator responsibility we can create a new Printer Driver but rather than calling a print command such as 'lp' we can call our shell script.


CM1:


The most important field is the 'Arguments' field, this is where we specify the script to call and pass parameters:


$XX_TOP/delivery/xmlpmailer.sh $PROFILES$.CONC_REQUEST_ID $PROFILES$.FILENAME + others


where
$XX_TOP/delivery/xmlpmailer.sh - is the location and name of the script we want to call
$PROFILES$.CONC_REQUEST_ID  - is the request id of the report we are sending
$PROFILES$.FILENAME - is the name of the file we want to deliver
others - we can pass other parameters, either from the PROFILES object or hardcode values here. There is no definitive list of what those PROFILES are in the Oracle documentation but using a little trial and error you can chekc what can and can not be passed. To find the other PROFILES that might be supported have the forms interface open Help > Diagnostics > Examine. Find PROFILES in the popup windows Block field. Heres what I have found is supported so far, not an exhaustive list:


$PROFILES$.CONC_REQUEST_ID
$PROFILES$.PRINTER
$PROFILES$.CONC_COPIES
$PROFILES$.TITLE
$PROFILES$.FILENAME
$PROFILES$.RESP_ID
$PROFILES$.USER_ID


With this lot we can derive quite alot of information and with a trip back to the database to we can get even more information.


To test all this theory you will need to enter the murky world of printers, printer types, styles and drivers ... I still sometimes struggle getting the right combination ... reading the manual, some trial and error and above all patience helps.
I created a very simple shell script to simply write the PROFILE values to a file:

echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 > /apps/vis11510appl/xdo/11.5.0/delivery/1.log
exit 0

The exit command is important, without it the concurrent manager will leave your request id as still running. Before you can test the new driver you'll need to bounce the concurrent manager and again for any changes. The following script became my best friend very quickly while putting these articles together:

startmgr sysmgr="apps/pwd" mgrname="std" printer="hqseq1" mailto="jsmith"
restart="N" logfile="mgrlog" sleep="90" pmon="5" quesiz="10"

So, we can call a script, but what do we want it do ?
Well by now you will hopefully have managed to get the printers on your network working with Apps and a great saying comes to mind here ... if it ain't broke don't fix it. If we leave printing then we have email, fax, ftp, webdav, http or even a custom channel to deliver documents to. All we need do is create a java class that takes the arguments above and then delivers the document ...easy!


Next article we'll tackle emailing documents from the EBS

August 17, 2006

Email from EBS

Trying to write this article for the third time today ... first time I forgot to commit it and my browser crashed ... serves me right for playing with IE7. Second time, I dont know what happened ... anyway trying again.


Apologies for the longer and longer titles ... hopefully the usefullness of the article outweighs the silly titles, got myself into a hole here. This time we're discussing emailing documents from the EBS, we need to pull together the Delivery Manager APIs with the shell scripts techniques we looked at last time.


But you can email already !


Little known fact but you can already allow your users to get emails from the concurrent manager. When submitting a request they can open the 'Options' popup and specify users that should receive a notification upon completion of the request. Thats great but how do they get hold of the output without logging back in and searching through the massive list of requests? If you set the 'Concurrent:Attach URL' to Yes then users will get a mail with a link in it to the output file. However, there are a couple of caveats:
1. The email can only be sent to a user registered in the system (remember to enter their email id)
2. The user has to be connected to the system to retrieve the output file.


Gotta thank Mr Azzopardi for this tidbit!

So what can I do?


To get around these limitations and attach an output file to an email to any user we can use the script print driver and the Delivery Manager APIs. Remember we can pass several parameters to the java via the script:


$PROFILES$.CONC_REQUEST_ID
$PROFILES$.PRINTER
$PROFILES$.CONC_COPIES
$PROFILES$.TITLE
$PROFILES$.FILENAME
$PROFILES$.RESP_ID
$PROFILES$.USER_ID


We could just add the email address we want to send the report to :

$PROFILES$.CONC_REQUEST_ID $PROFILES$.FILENAME tim.dexter@oracle.com

But that would mean either one person is going to get every report output from the system that uses that driver or you'll need to create a personal driver for every user, not a bad idea for smaller user groups. It would be better to derive the email address so we can have one email driver to maintain.
Using a combination of the PROFILES we can make a trip to the database to retrieve pretty much anything we want. With the USER_ID we can fetch the email address for that user; with the RESP_ID we could fetch all the emails for the users that have that responsibility. Using the CONC_REQUEST_ID we can get a hold of the concurrent program and maybe store the emails for the report in the Options field of the program definition form. We could even use the derived program id to look up emails against a custom table where we have stored users and programs ... we now have a nice report subscription model for EBS ... cool!


OK, let's do it ...


For this example this just tackle looking up the email address of the user ... the other options are just a variation on the same theme, its just getting the sql right.
So I have built the following java class:

package oracle.apps.xdo.ebsdelivery;

import oracle.apps.xdo.delivery.DeliveryManager;
import oracle.apps.xdo.delivery.DeliveryRequest;
import oracle.apps.xdo.delivery.DeliveryPropertyDefinitions;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

 

public class EBSEmailDelivery
{
  public EBSEmailDelivery(String rRequestID, String rFile, String rUser)
  {
        int userid =  Integer.parseInt(rUser);
        int requestid = Integer.parseInt(rRequestID);
   
    try {
        //get the report title
        String repTitle = getReportTitle(requestid);
        // create delivery manager instance
         DeliveryManager delMgr = new DeliveryManager();
        // create a delivery request
         DeliveryRequest delReq = delMgr.createRequest

(DeliveryManager.TYPE_SMTP_EMAIL);
        // set email subject
         delReq.addProperty(DeliveryPropertyDefinitions.SMTP_SUBJECT,

"EBS Report:"+repTitle +" for request: "+ rRequestID);
        // set SMTP server host
         delReq.addProperty(
         DeliveryPropertyDefinitions.SMTP_HOST, "mail.yourcompany.com");
        // set the sender email address
         delReq.addProperty(DeliveryPropertyDefinitions.SMTP_FROM,

"ebsadmin@oracle.com");
        // set the destination email address
         delReq.addProperty(DeliveryPropertyDefinitions.SMTP_TO_RECIPIENTS,

getEmail(userid) );
        // set the content type of the email body
         delReq.addProperty(DeliveryPropertyDefinitions.SMTP_CONTENT_TYPE,

"application/pdf");
        // set the document file name appeared in the email
         delReq.addProperty(DeliveryPropertyDefinitions.SMTP_CONTENT_FILENAME,

repTitle+rRequestID+".pdf");
        // set the document to deliver
         delReq.setDocument(rFile);
        // submit the request
         delReq.submit();
        // close the request
         delReq.close();

    }
    catch (Exception e) {
    e.printStackTrace();

    }
  }

  static Connection getConnection() throws SQLException, Exception
  {
        String fDriverName = "oracle.jdbc.driver.OracleDriver";
        String fDbName = "vis11510";
        String fServer = "xdodemo.us.oracle.com";
        String fPort = "1521";
        String fUserName = "apps";
        String fPassword = "apps";

        Class.forName(fDriverName).newInstance();
        Connection dbconn = DriverManager.getConnection
            ("jdbc:oracle:thin:@"+fServer+":"+fPort+":"

+fDbName, fUserName, fPassword);
        return dbconn;
  }
 
  private String getReportTitle(int requestID)
  {
    String reportName = "";
    try
    {
      // Try and geta connection to the db
      Connection conn = getConnection();
      // fetch the report name based on the request id
      PreparedStatement getTitle = conn.prepareStatement(

"select user_concurrent_program_name \n" +
"from fnd_concurrent_requests fcr,\n" +
 "fnd_concurrent_programs_vl fcpv\n" +
 "where fcr.concurrent_program_id = fcpv.concurrent_program_id\n" +
 "and request_id = ?");

//get the title
      getTitle.setInt(1,requestID);
    
      // get the query result in to a result set and then assign the
      // value to a variable we can pass back to the calling method
      ResultSet titleRslt = getTitle.executeQuery();
      titleRslt.next();
      reportName = titleRslt.getString(1);
      System.out.println(reportName);
     
      //Clean up
      titleRslt.close();
      getTitle.close();
      conn.close();
     
     
    }
    catch (SQLException eSQL)
    {
      System.err.println("Could not create connection");
      eSQL.printStackTrace();
    }
    catch (Exception e)
    {
     System.err.println("Exception thrown");
     e.printStackTrace();
    }
    
    return reportName;
  }
 
 
  private String getEmail(int userID)
  {
    String eMailID = "";
    try
    {
      // Try and geta connection to the db
      Connection conn = getConnection();
      PreparedStatement getEmail = conn.prepareStatement(

"select email_address from fnd_user where user_id = ?");
      getEmail.setInt(1,userID);
    
      // get the query result in to a result set and then assign the
      // value to a variable we can pass back to the calling method
      ResultSet emailRslt = getEmail.executeQuery();
      emailRslt.next();
      eMailID = emailRslt.getString(1);
      System.out.println(eMailID);
     
      //Clean up
      emailRslt.close();
      getEmail.close();
      conn.close();
     
     
    }
    catch (SQLException eSQL)
    {
      System.err.println("Could not create connection");
      eSQL.printStackTrace();
    }
    catch (Exception e)
    {
     System.err.println("Exception thrown");
     e.printStackTrace();
    }
         
    return eMailID;
  }
  public static final void main(final String[] args)
  {
    // Arguments passed
    //1.$PROFILES$.CONC_REQUEST_ID
    //2.$PROFILES$.FILENAME
    //3.$PROFILES$.USER_ID

    EBSEmailDelivery ebsMail = new EBSEmailDelivery(args[0], args[1], args[2]);

  }

}


You can get the source here.
Just a note, to develop and compile your class you are going to need the following libraries:
xdocore.jar - grab it from the Template Builder install
versioninfo.jar - same place
xmlparserv2-904.jar - the Oracle XML parser
mail.jar - this is the java mail library get it from Sun
Activation.jar - a supporting library for the mail library get it from Sun 

if you want to test it on your cleint machine you'll need the Oracle JDBC driver libraries too ... these will be under your EBS JAVA_TOP, jdbc12.zip worked for me. Ar runtime all the libraries will be available for you so all you'll need to do is add the path to your class in the shell script.

Walking through the class we have several methods.



  • EBSEmailDelivery - at the top we have the delivery manager APIs for emailing. We have seen these already. You'll need to add your outgoing email server.
  • getConnection() - this method gets us a connection to the db
  • getReportTitle - this fetches the report title based on the concurrent request id. Check out the query we're executing.
  • getEmail - this fetches the email of the user that ran the report based on the user id


The class is not catching every possible situation but you get the idea.

Now we have the class we mount it into the APPL_TOP. You should have a custom area under JAVA_TOP. My class is going to sit under the xdo directory under JAVA_TOP. You should note that the package name in the top of the class i.e. oracle.apps.xdo.ebsdelivery is going to define where the class is going to sit. In this case $JAVA_TOP/oracle/apps/xdo/ebsdelivery.

The shell script now needs to call the class and pass the parameters, I have the following:

CLASSPATH=/apps/vis11510comn/java/oracle/apps/xdo/ebsdelivery:$CLASSPATH
export CLASSPATH

java oracle.apps.xdo.ebsdelivery.EBSEmailDelivery $1 $2 $3
RESULT=$?
if [ $RESULT -ne 0 ]
then
echo "`date` There was an error while delivering the document."
echo "`date` Please inform your System Administrator."
exit $RESULT
fi

# Return success code to Oracle concurrent manager
exit 0


So there you have it, your users can get emails from the EBS with their reports attached. Of course you can get very sophisticated and grab multiple email addresses or even multiple reports if you are using a request set ... just let your imagination run riot.

Next ... faxing documents

August 24, 2006

Email from EBS - Addendum

The fax article is on the way but since I came up with the email solution there has always been the niggling fact that I was putting the EBS user name/password openly into my java class ... there had to be a better a solution !


There is, and thanks to Ashish from the dev team and a little work I found it. The OA Framework UI uses a DBC file to define the connection and other information to the EBS database and we can use that to get a connection to the database instead of hard coding the connection.


The file resides under the $FND_TOP/secure directory, check it out you'll have one. It will look similar to this:

#DB Settings
#Sun Sep 04 13:02:20 PDT 2005
GUEST_USER_PWD=user/pwd
APPL_SERVER_ID=F936BF325610DB94E03023823E050DC825406294681422881503890572956133
FND_JDBC_BUFFER_DECAY_INTERVAL=300
APPS_JDBC_DRIVER_TYPE=THIN
FND_JDBC_BUFFER_MIN=1
GWYUID=user/pwd
FND_JDBC_BUFFER_MAX=5
APPS_JDBC_URL=jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=YES)
(FAILOVER=YES)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)
(HOST=your server)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=sid)))
FND_JDBC_STMT_CACHE_FREE_MEM=TRUE
FND_JDBC_STMT_CACHE_SIZE=200
TWO_TASK=yourdb
FND_MAX_JDBC_CONNECTIONS=500
FND_JDBC_USABLE_CHECK=false
FNDNAM=user
FND_JDBC_PLSQL_RESET=false
DB_PORT=1521
FND_JDBC_CONTEXT_CHECK=true
FND_JDBC_BUFFER_DECAY_SIZE=5
DB_HOST=your server

there is also an environment variable called $FND_SECURE which will point to the file location.
To take advantage of the file and its contents and make your java class a whole lot more secure you can pass the FND_SECURE value and the dbc file name to the class via the driver i.e. $FND_SECURE/file.dbc


Then in your class add the following:


import oracle.apps.fnd.common.AppsContext;
...

the getConnection method becomes very simple
  static Connection getConnection() throws SQLException, Exception
  {
       
        AppsContext aCont = new AppsContext(dbcLocation);
        Connection aConn  = aCont.getJDBCConnection();
        return (aConn);
       
  }


where dbcLocation is a string that holds the new parameter passed from the driver. The rest of the class remains the same.
So now you have a much more secure method to get the connection. Just be sure to close it after you have finished so the connection returns to the connection pool. Much cleaner, neater and faster :o)




 


 

August 25, 2006

Faxing from EBS

Fax integration is probably one of the most popular and tougher delivery destinations from the EBS, you need connections to the fax server from EBS, you need to be able to convert your documents to a tif format, you may need very high volumes of faxes, your users will want to be able to monitor the delivery and have automatic redial if the fax recipient's machine is busy. This has required third parties and Oracle Partners to provide functionality for faxing documents.
The XMLP faxing solution aleviates some of these issues but it is not a replacement for some of the fine solutions out there.


What can it do?


  • XMLP can send a fax via the IPP protocol, this requires a delivery server such as CUPS to handle the fax the request.
  • XMLP can be integrated into the concurrent manager or even a specific product
  • XMLP can be used for lightweight faxing requirements
  • You can build a complete faxing solution using the XMLP APIs
What can't it do?



  • It can not handle huge volumes of faxing, Im talking thousand of faxed an hour
  • No out of the box redial and monitoring EBS UI. CUPS has its own UI that could be used.

If you're still interested in building a fax delivery channel then you can use the java APIs and the shell script in conjunction with a dummy printer driver. Again, you can extend your implementation as much as you want so you can build feedback into the concurrent manager or even build your own fax monitoring UI interface.

For this demo we'll take a similar approachto that of the email solution. We'll need a CUPS server set up to communicate the fax content to. CUPS is only for UNIX or LINUX implementations, for those of you on a Windows there are commercial solutions available to have a FAX machine connected to your network via IPP. We will also use the database querying to grab the fax number.

Step1: Set up CUPS


The set up of CUPS for faxing is covered in the user guide (pg 11-36) you'll need some extra packages and install them. The good news is that they are all open source solutions and therefore inexpensive, the not so good news is that support is going to be patchy. Follow the instructions and test that the fax machine is sending output when called.

Step 2: Build the java class

We can reuse much of the email code we wrote last time. We of course need to use the fax APIs rather than the Email. We also need to fetch the fax number of course, you can use the techniques we used last. For this example I decided to try something different. Im assuming that the report that is to be delivered actually has the fax number embedded inside it. In this case we can fetch the XML data used to create the report, parse it and retrieve the fax number value.
I have been a little lazy with my class, it parses and sends the document, if you were going to use the parser functionality across multiple delivery classes then you would break it out on its own.
I use the SAXParser rather than the DOM, we're not sure how much data we are going to get and do not want to gobble up memory loading the whole document using the DOM parser.
In the class I have I just have a few methods to:


  1. Parse the document - the parser just moves through the document and event are fired that we can subscribe to.
  2. Look for the specific element that holds the fax number - once found its sets a flag for the next method to
  3. Fetch the fax number value into a variable and sets another 'found the element' flag for the next function
  4. Check the closing element that holds the fax number - if the flag is set then the parser stops working through the document.


Heres the code snippet for the parser, the startElement, endElement and characters methods are standard SAXParser methods we need to implement:


  public String parseFAXNum (String xmlFile)
  {
    try {
         
          SAXParser parser = new SAXParser();
//Because Im lazy my class is extending the DefaultHandler for SAX
// so I can just use 'this' for the following methods



          parser.setContentHandler(this);
          parser.setErrorHandler(this);
          // We parse the XML file fetched from the variables passed
// from the printer driver
          parser.parse(xmlFile);
         
    }
          catch (Exception ex) {
                System.out.println(ex);
          }
        return(xFaxNum);
  }
 
  public void startElement(String uri, String localName,
          String rawName, Attributes attributes) 
          // We're checking for the CUST_FAX_NUM element, this method
// looks for the opening tag. If found then we set a
// "found" flag to true for the "characters" method

       {
             if (localName.equals("CUST_FAX_NUM"))
             {
                getEleVal = true;
              }
       }
  public void endElement (String uri, String localName,
          String rawName) throws SAXException
          {
         // We're checking for the CUST_FAX_NUM element, this method looks
// for the closing tag.
         // If found then we throw an exception to stop the parser.
            if (localName.equals("CUST_FAX_NUM"))
            {
               getEleVal = false;
               throw new SAXException("Found element required");
             }
          }
    public void characters(char[] cbuf, int start, int len) 
      {
         if (getEleVal)
         {
           // We have the value we want so assign it to the fax variable
           xFaxNum = new String(cbuf,start,len);
           
         }
      }
If you wanted to break the parser out on its own and use it for multiple report output you could place the logic in the code to check the root of XML ie RAXINV for the Invoice report, POXRPOP for Purchase Orders and then find the appropriate element for the fax number.

Once we have the fax number we're pretty much set to call the appropriate APIs to deliver the document.
    try
    {
      // fetch the fax number from the XML data that is
      // fetched via the requestid from the driver
      String faxx  = parseFAXNum(getXMLFile(requestid));
      // create delivery manager instance
      DeliveryManager dm = new DeliveryManager();
      // create a delivery request
      DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_IPP_FAX);
      // set IPP fax host - this is our CUPS server
      req.addProperty(DeliveryPropertyDefinitions.IPP_HOST,
"xdodev2.us.oracle.com");
      // set IPP fax port - - this is our CUPS server port
      req.addProperty(DeliveryPropertyDefinitions.IPP_PORT, "631");
      // set IPP fax name - this is our CUPS fax name
      req.addProperty(DeliveryPropertyDefinitions.IPP_PRINTER_NAME,
"/printers/fax1");
      // set the document format
      // we can pass a pdf document and CUPS will convert it to tiff for us
      req.addProperty(DeliveryPropertyDefinitions.IPP_DOCUMENT_FORMAT,
"application/pdf");
      // set the phone number to send
      req.addProperty(DeliveryPropertyDefinitions.IPP_PHONE_NUMBER, faxx);
      // set the document
      req.setDocument(rFile);
      // submit the request
      req.submit();
      // close the request
      req.close();
    }

You might have noticed that we are  passing a pdf format to the CUPS server, CUPS will convert the pdf to tiff format for us. You can see the complete class definition here.


Now all you need do is create a new fax "printer" driver to call your class and you now have faxing from the EBS with some level of flexibility for your users.
If you are looking at handling a batch of documents, XMLP has a much better solution in its Bursting Engine and I'll cover that once I have completed the delivery articles.


Happy Faxing!

August 28, 2006

Document Storage and EBS

Couple more delivery channels to cover and we'll have exhausted the options for document delivery from EBS. For this article Im turning to document management. Many of you will have a document management system in your company this may be as simple as scanning invoice documents and storing them in some LOBS table in the EBS schema for later retrieval or you may have Oracle Files or maybe a third party solution.
To get the documents to the repository may involve some third party or custom code interfacing into the EBS stack. XML Publisher can help you get the documents to the repository directly from the concurrent manager. Whats more you can do this while you are delivering the document to the end user at the same time and even do some post processing to maybe add a watermark to the archived document with the word "COPY" striped across it.


Same again please ...


With all the work we have done with email and faxing we now know how the whole solution hangs together and how we can call APIs to get the documents delivered. All we need do is add the code to send the document(s) to the correct place in the repository. Just about all the document management solutions offer a webdav channel to push documents into the document repositiory. They may also have the ability to push in some metadata about the document. I have naturally picked on Oracle Files in the example below, but its still generic for all webdav servers.

    /*create delivery manager instance*/
     DeliveryManager dm = new DeliveryManager();
     // create a delivery request
     DeliveryRequest req = dm.createRequest(DeliveryManager.TYPE_WEBDAV);
      // set document content type
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_CONTENT_TYPE,
"application/pdf");
     // set the WebDAV server hostname
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_HOST, "mywebdavhost");
     // set the WebDAV server port number
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_PORT, "80");
     // set the target remote directory
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_REMOTE_DIRECTORY,
"/content/");
     // set the remote filename
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_REMOTE_FILENAME,
"xdotest.pdf");
     // set username and password to access WebDAV server
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_USERNAME, "xdo");
     req.addProperty(DeliveryPropertyDefinitions.WEBDAV_PASSWORD, "xdo");
     // set the document
     req.setDocument("/document/test.pdf");
     // submit the request
     req.submit();
 
     // close the request
     req.close();

I want to watermark ...

To add a watermark to the document its just a simple API call.

 // You already have the document locally so call the PDFDoc merger
// and create input and output streams for it
PDFDocMerger docMerger = new PDFDocMerger(inputStreams, outputStream);
// You can use setTextDefaultWatermark() without these detailed setting
docMerger.setTextWatermark("COPY", 200f, 200f); //set text and place
docMerger.setTextWatermarkAngle(80); //set angle
docMerger.setTextWatermarkColor(1.0f, 0.3f, 0.5f); // set RGB Color
// Merge PDF Documents and generates new PDF Document
docMerger.mergePDFDocs();

Pretty straightforward right?
There are a couple of points here:
1.There is a need to get the username/pwd for the repository. There are ways around this, putting documents into a public directory, passing the username/pwd from the EBS instance ... Im not going to cover this in this article thou.
2. Metadata - all of the repositories I have come across have a java interface to push meta data in. You could use the XML parsing techniques in the fax article to grab pertinent information about the document to join it in the repository.


Short but sweet ... next, custom channels

November 3, 2006

Let's Date ...

Date formatting in XML Publisher is very powerful, it can provide a variety of formats from simple 03/12/99 to 'Friday, December 31, 1999 6:15 PM GMT' ... notice the timestamp and the timezone components. All very neat but how do you get there?


Get the right format ...


Well the first hurdle is to get your dates in the XSD date-time format:
                  YYYY-MM-DDThh:mm:ss+HH:MM
Looks straightforward and you ought to be able to get the database 'to_char' function to serve it up no problem, but there is a wrinkle in there in the form of that 'T' character its used as a separator between date and time components. Try and use that format mask with the to_char and the database will choke ... the format is not recognised. There is hope, even for Oracle Reports under EBS users :)


1. If you are not interested in the time and zone info then just use the 'YYYY-MM-DD' format mask, no need for the 'T'. Oracle Reports and the db support this mask. XMLP will then format the date appropriately. any timestamp is going to be 12:00:00 AM and the timezone will default to GMT
2. Use the XMLP extraction engine - the engine will extract all dates using the XSD mask - simple
3. If you're using Oracle Reports or your own plsql/sql extraction routine and want the timestamp and zone then only way I have found to construct the mask is to use something like:

    to_char(sysdate,'YYYY-MM-DD')||'T'||to_char(sysdate,'hh:mm:ss+HH:MM')


this will at least get the date into the right format.





I stand corrected on this thanks to an anonymous comment, I was playing with masks in the 
db while writing and could not get the format to work, however our anonymous friend has:
to_char(sysdate, 'YYYY-MM-DD"T"hh:mm:ss+HH:MM') which works perfectly ... apologies!

Date formatting and calculations


Now you have date in the right format you can apply masks in the layout very easily. You can either use the MSWord formats or XMLP provides a format-date function ... there is a complete section devoted to the formatting in the user guide. Page 118 is the start and covers all XMLP flavors.
The other advantage of the mask is that calculations on dates become possible with XSLT 2.0, prior to this all dates were treated as strings not much use when it comes to calculating the number of days between two dates. Thats another article in itself ... there are plenty of resources out there now.

November 8, 2006

Introducing Data Templates

Another series of articles on the way ... this time concerning the relatively new data extraction engine from XML Publisher that is currently available in the Enterprise and E Business Suite flavors.


First a little history ... 


Why build another extraction tool, there are others that can generate XML, Oracle Reports, various solutions from the database folks, the list goes on. To answer why you have to understand the volumes of data we are trying to handle here and the furture of reporting for Oracle Applications. For EBS in particular we had multiple reporting solutions, the majority of which were based on Oracle Reports. The plan going forward is to remove Oracle Reports from the techstack in the fusion timeframe. Therefore we needed an extraction engine that offered all that Oracle Reports offers and was just as fast - Oracle Reports is danged fast at generating XML data. On top of that we are not talking about extracting data for a 2 page invoice, the engine needs to extract millions of rows to build tens of thousands of pages for some reports. 
We looked at what was out there, SQL XML provided fast extraction for large data sets but we needed among others, event triggers and flexfield user exits, plus users would need to learn the wrapper functions used to generate the hierarchies. After a lot of research we decided to build an engine ourselves with all the bells and whistles needed to cover the Oracle Reports replacement requirements.


Features ... features ... features


To dig in a little to the features the engine provides:


Fast, scalable extractions - its fast, faster than Oracle Reports. We worked closely with the Oracle Performance team and had to re-write it a couple of times to get their approval. It needs to be fast too, those of you that use Oracle Reports EBS know that out of the box we generate flat text character based output. With XMLP we're generating highfidelity output ... that requires more processing time so the more time we save on the extraction the more we have for formatting without slowing the report generation.


Oracle Reports Features - if its going to replace OR in EBS then it has to match OR on features:


  • Multiple Queries/Joins -  enabling master/detail extractions
  • Event Triggers - pre- and post- fetch for business rule processing. Currently plsql support but will add java
  • Flexfield Support - gotta get that natural account description with out the select statement - this is an EBS feature.
  • Formula/summary columns -  again similar to Oracle Report functionality allowing you to create aggregation values and pl/sql based formula columns in your extraction
  • Data Structure - this allows you to build a hierarchy into your XML data similar to the grouping abilities in Oracle Reports
  • Group filters - a la Oracle Reports
  • etc


on top of that its also has:




  • Rich Java API layer - call a data template from your jsp or java app
  • Distributed Queries - this is neat. You're not tied to a single db nor even to an Oracle db. You can construct a data template that, for example hits an MSSQL instance for customer data and an Oracle db for their invoices. the engine will generate a single result set of hierarchical XML i.e. Customer1
     Invoice1
     Invoice2
    Customer2
     Invoice1
     Invoice2

  • Static XML File support - query across a db and an XML file. Text and XLS support coming.
  • Pluggable Data Templates - not here yet but theidea here is that you can build a core data template and then allow a plugin DT to be applied over the top to get more data from other sources.

Some of you will have wondered what the heck a Data Template is? this is the name we give to the extraction definition, its an XML representation of the queries, joins, data structure, etc.

Thats the brief overview, next Im going to cover some sample Data templates over the next few articles from the most basic to an all singing all dancing EBS DT, I'll also post a jsp appyou can use to test DTs and some help on how to build them.

November 9, 2006

How about another date?

Im interrupting the Data Template flow with a really great question and answer from the forum that I wanted to share on time zone formatting. For those of you that want to include a timezone portion into your output dates XMLP can help but you might not find what you expect!


Let's assume we have the following date element in our data stream:


 2006-07-27T12:48:00.000+02:00

Notice the timezone offset from GMT i.e. Paris, France.
Using 
       <?format-date:DATE_TEST; 'LONG_TIME_TZ'?>
we  get
 Thursday, July 27, 2006 10:48 PM GMT

The GMT appears incorrect we were expecting 'Paris' ... hey thats a bug! Look closer and you'll notice that the time component has been adjusted back by 2 hrs. So it is actually correct for the GMT timezone.
So how do we stop the adjustment and see 'Paris' i.e. Thursday, July 27, 2006 12:48 PM Paris
This can be achieved using:
    <?format-date:DATE_TEST; 'LONG_TIME_TZ';'Europe/Paris'?>
that 'Europe/Paris' is a java time zone specification. The list can be gotten here, http://www.thescripts.com/forum/thread15954.html
This is in the user docs but  a little tough to grasp(;o). If you are in EBS then there is a profile option, more details in the user guide. If you are using APIs the java time zone can be passed into the template as a parameter.  Neat!
 

November 29, 2006

Data Templates by Example

Apologies for the delay ... I have lots of content and examples for you but I did not have a means for you to test your data templates. I have now rectified that and have taken one of our internal testbeds and packaged it up so you can test to your hearts content. The test bed is a web application that runs inside OC4J, I have not tested it with any other mid tier flavors but if you're game.


Before we start on the content lets install the app and test a sample data template.


  1. Download the EAR file here. Well you would be able to download it if I can find somewhere that can host it. for now drop me a mail and I'll get it to you. 

    Finally found a home for the file on my website, you can get the file here, http://www.banzel.com/download/DTTestBed.ear
     
  2. I have tested with OC4J 9.0.4, 10.1.2 and 10.1.3 so once you have the EAR its a simple case of deploying it. If you do not have OC4J installed, go for the latest 10.1.3 release and have a nice UI to help you deploy the app.
  3. Once installed you just need to point your browser to http://yourserver:port/DTTestBed/DT1.jsp
    4. The first page you'll see is:
    DTTB1:


    I have created a small data template that will run against the scott/tiger schema, so download it from here. Then use the browse button to find it and hit Upload.


  4. You'll then get a page like this:


    DTTB2:

    Heres where the fun starts, so in the page you have a parameter section, these are the parameters parsed out of the data template in this case we only have one, pDeptNo. You can fill in a value or leave it blank to get the complete data set.
    Then we have the runtime options:


    • Generate XML Schema  - fairly obvious but very useful if you are going to be doing some PDF template mapping
    • Generate Default Layout - this will generate an RTF template for you based on the data structure of the data template, again useful to get you started
    • Layout Template - if you have already developed an RTF template (no it does not support PDF templates yet) then you can load it to be applied to the resulting data. If you choose this option then a default template will not be generated.
    • Database - we need a connect string to the database, hostname:port:sid
    • User Name - obvious
    • Password - obvious if you have it
    • ORG ID - this is for EBS customers that want to test data templates running against the EBS db - its not required.


  5. So fill in some values so you have something like this:


    DTTB3:


    and hit Submit
    7. If all went well then you'll get a page of results similar to this:


    DTTB4:


    There will be links to the various objects that XMLP has generated. These are all created in a temp directory under the root of the web app in mycase

    D:Oc4j10.1.3j2eehomeapplicationsDTTestBedDTTestBedtemp
    . Be sure to clean that directory up regularly it will fill your disk all to quickly.


So thats the test bed we are going to use in the coming articles ... get it up and running and you'll be able to try your first data template.  

December 13, 2006

Hello Data Templates

Hopefully you have downloaded and installed the Data Template Test Bed I provided in my last post, you may have even loaded and run the sample I provided ... hopefully sucessfully. You may have even gone off and got started on your own. Well we are going to take a step back here and get back to basics and then move up to the more powerful stuff like filters, triggers and flexfields ... we're going to get there quickly so please be patient.


Being the consumate geek and not wanting to break tradition when it comes to starting out with a new technology we're going to build and test a Hello World data template ... now known as 'DTs' for brevity. First lets take a look at the anatomy of a DT, it'll help later.

<dataTemplate name="EMPLOYEES" defaultPackage="" description="Employee Data">
   <properties>
      <property name="include_parameters" value="true"/>
      <property name="include_null_Element" value="true"/>
      <property name="xml_tag_case" value="upper"/>
      <property name="db_fetch_size" value="500"/>
      <property name="scalable_mode" value="off"/>
      <property name="include_rowsettag" value="false"/>
      <property name="debug_mode" value="off"/>
   </properties>
   <parameters>
      <parameter name="pDeptNo" dataType="number" defaultValue=""/>
   </parameters>
   <lexicals/>
   <dataQuery>
  <sqlStatement name="Q1" dataSourceRef=""><![CDATA[SELECT DEPTNO,DNAME,LOC
from dept where deptno = nvl(:p_DeptNo,deptno)
order by deptno]]>
</sqlStatement>
  <sqlStatement name="Q2" dataSourceRef=""><![CDATA[SELECT  EMPNO,ENAME,JOB
,MGR,HIREDATE,SAL,nvl(COMM,0) COMM 
from EMP
WHERE DEPTNO = :DEPTNO]]>
</sqlStatement>
  </dataQuery>
   <dataStructure>
  <group name="G_DEPT" source="Q1" groupFilter="">
   <element name="DEPT_NUM" value="DEPTNO" function=""/>
   <element name="DEPT_NAME" value="DNAME" function=""/>
   <element name="LOCATION" value="LOC" function=""/>
   <group name="G_EMP" source="Q2" groupFilter="">
    <element name="EMPNO" value="EMP_NUM" function=""/>
    <element name="EMP_NAME" value="ENAME" function=""/>
    <element name="JOB_TITLE" value="JOB" function=""/>
    <element name="MANAGER" value="MGR" function=""/>
    <element name="HIRE_DATE" value="HIREDATE" function=""/>
    <element name="SALARY" value="SAL" function=""/>
    <element name="COMMISSION" value="COMM" function=""/>
   </group>
  </group>
 </dataStructure>
</dataTemplate> 

I have highlighted the main players in a DT:




  • dataTemplate - header element where you provide a name and description for your DT. The name will be used as the root name of the element.
  • properties - these are the runtime switches for the extraction engine:

    • include_parameters - should the parameter values be extracted to the XML or not
    • include_null_Element - if a value when extracted is null do you want an empty element in the xml
    • xml_tag_case - upper or lower case tag names
    • db_fetch_size - maximum number of records to fetch
    • scalable_mode - if you know this is going to be a large dataset or an intensive extract then set this to true
    • include_rowsettag - for simple XML with no hierarchy do you want ROWSET as the root element
    • debug_mode - generate a debug file while processing or not. The test bed I posted will always do this for you.
Moving into the main section:

  • parameters - these are the runtime parameters for the DT
  • lexicals - these are EBS specific and will allow you to fetch flexfield values ... more on these later
  • dataQuery - heres where we start to define the
    sqlStatement - this is where we define the query(s)
  • group - this section defines the structure of the data we want to see and contains
  • element - the reference to the column in a specific query. These also have a name for the resulting XML element and you can include functions here.

So thats a quick overview, lets do the HelloWorld ... its as simple as it gets when it comes to DTs.

<dataTemplate name="HELLOWORLD" defaultPackage="" description="Hello World DT">
   <properties>
      <property name="include_parameters" value="true"/>
      <property name="include_null_Element" value="true"/>
      <property name="xml_tag_case" value="upper"/>
      <property name="db_fetch_size" value="500"/>
      <property name="scalable_mode" value="off"/>
      <property name="in