Daniel Ng
Email Me Contact Me

You're welcome to email me at dng11@sympatico.ca.

While I do like hearing from you, I am not interested in SEO services nor offshoring my business, so please don't offer me any.

Follow me on Twitter Subscribe to my RSS feed

How To Create A Custom Dialog Box In Maximo Allowing User To Email BIRT Report
Originally posted by Daniel Ng on May 27, 2012. Last revised on June 8, 2012.

This is a comprehensive tutorial on how to create a custom dialog box in Maximo allowing user to email BIRT report as attachment. While this tutorial is about a specific function, the overall aim is to use this example as a segue to introduce a few useful and common concepts to those who are new to Maximo/MBO customization, such as:

  • How to create a custom dialog box in Maximo.
  • How to associate a custom dialog box to a custom toolbar button.
  • How to add functionality to the dialog box via custom AppBean class.
  • How to programmatically assign default value to dialog box controls.
  • How to programmatically retrieve data from the current MBO record and also from the dialog box.
  • How to generate a report programmatically.
  • How to work with logger.
  • How to display custom message to user via message box.
  • and etc.

As mentioned, this is a comprehensive tutorial. Meaning it will be lengthy as I walk you through the entire process from start to finish. Since it is impossible for me to cover every single detail, I expect you to know some basics. Please check out the Pre-requisites section before reading any further.

The Java source code and the custom dialog box in XML referred to in this tutorial can be downloaded from the File Download section.


Finished Product

Before we continue, let's take a sneak peek at the finished product (see both figure 1 and 2 below) so that you are mindful of what we are trying to accomplish here.

Figure 1: What the custom dialog box looks like. Custom dialog box
Figure 2: How it works. Finished product
Tip: In this tutorial, I am adding the custom dialog box to the Purchase Orders application and attaching the PO details report to the email. Theoretically, you can add the custom dialog box to one or more Maximo applications and have each dialog box calling a different report.

So, Let's Get Started!

Just a heads up, we will first create and set up the dialog box and then we will implement the functionality via custom AppBean class. Here are the detailed steps we are going to take:

  1. Create a custom XML dialog box.
  2. Attach the custom dialog box to the PO application.
  3. Enable security for the custom dialog box.
  4. Associate the custom dialog box to a custom toolbar button.
  5. Create a custom AppBean class.
  6. Create a custom message box.
  7. Turn on debugging mode for the logger.
  8. Deployment and testing.

Depending on your experience, you can either follow the entire tutorial step by step, or you can skip to the section that requires your attention.


Step 1: Create a custom XML dialog box.

Maximo, at this point of writing, does not provide us a GUI to create a custom dialog box. Since the dialog box is XML-based, you can create one using any text or XML editor you have. Once you have added a custom dialog box to a Maximo application, you can actually modify the dialog box via Application Designer. For those who prefers a GUI, you can always create a skeleton of your dialog box, import it into Maximo and then leverage Application Designer to design your form that way. Personally, I am comfortable designing my form with text editor and I always find Application Designer buggy in Firefox browser.

In figure 1 above, you can see what the dialog box looks like graphically. The following figure shows the XML code behind, which you may download from the File Download section.

Figure 3: The XML code behind the custom dialog box. XML dialog box

Color Codes Explained:
Blue text = XML element; Red text = XML attribute; Gray text = String;
Yellow highlight = Safe to change as you see fit; Green highlight = Should be changed to reflect your needs; Purple highlight = Be cautious when changing.

Before I dwell deeper into the XML, let me first mention that each XML element must have a unique id. If not, you will experience problem importing your XML code into Maximo. Now, let's examine the XML line-by-line:

Line # Comment
1 The "beanclass" attribute is how you associate a bean class (i.e., the AppBean class which we will write later) to this dialog box. If you compile your AppBean class under a different class path, be sure to specify your value here.

The "id" attribute here is the dialog box id. Typically, an element id has no length restriction, but there is one here so beware! Later on, you will need to create a signature option for this dialog box and the name of the signature option should match this dialog box id. Maximo only allows a maximum of 25 characters for the name. Furthermore, when you try to associate a signature option to a custom toolbar control (which we will also do), Maximo will throw an error if your signature option is more than 10 characters long. In short, keep your dialog box id to no more than 10 characters long to save yourself a ton of headache!

The "mboname" attribute is the name of the MBO which we want to associate our dialog box to. Since our example is about emailing PO details report, the logical MBO to use is "PO". If you want to add this tool to the Work Order Tracking application and allow user to email WO details report, you should change the MBO to "WORKORDER".
2 The "helpgrid" element is entirely optional. It is an excellent way for displaying long static message on the dialog screen.
3 This line will require a bit of an explanation, so please bear with me.

Some background information first. Any XML element that is used to store/capture/display data must be bound to an existing MBO attribute. An MBO attribute can be of persistent or non-persistent type. If you want to store the data in the database, you have to use an attribute that is of persistent type. In our example, we have 4 visible textbox controls on the dialog box to capture email to, email cc, email subject and email message respectively. Since it doesn't make sense for us to store these data in the database (we only need to store them temporary somewhere, access them and dispose them thereafter), we need to use attributes that are of non-persistent type. With that in mind, we now have a choice to make. We need an MBO with non-persistent attributes which we can bound our controls to. So, we can either create a custom MBO object or modify an existing one. It turns out that there is a third hidden option. There is already an MBO object named "REPORTPARAMETER" in the system that can fulfill all our needs just out-of-the-box. If you look up the object via Database Configuration application, you can see that it has all the necessary attributes we need for emailing purposes.

If you refer back to line #1, you can see that we'd already bound an MBO to the dialog box. To introduce another MBO into the mix, we need to use a datasource element. As a matter of fact, you can add as many datasource elements as you want or none at all if you only need to work with one MBO.

Here, I am adding a datasource element with "REPORTPARAMETER" as the MBO. You will see that all my textbox and defaultvalue controls referenced this datasource element (via the "datasrc" attribute) and its attributes (via the "dataattribute" attribute). Needless to say, this is important.
4, 5, 6 As the name implies, defaultvalue element is hidden element and is traditionally used for setting default value for an MBO attribute. For instance, if you like to provide a default email message, you can simply add the following line to the XML. Notice the value for "dataattribute" attribute is the same as the multilinetextbox element's "dataattribute" value which is "EMAILCOMMENTS".
<defaultvalue id="rptemail_emailmessage" dataattribute="EMAILCOMMENTS" datasrc="RPTEMAIL_ds1"
defaulttype="insert" value="Type your message here."/>

Here, I am actually using these defaultvalue elements to store system variables. I want to expose them here (instead of hardcoding them in the Java class) so that they can be easily changed (by you) and not having to go through the lengthy deployment process. Later I will show you how we can programmatically access these values from the AppBean class.

About these system variables:
  1. Report Name
    Use this variable to specify which report to run. You can look up a list of report names from the Report Administration application. The only caveat is that the report must be able to accept a simple where clause that matches records by record id. If your report expects other report parameter(s) to run, you may need to adjust the AppBean class yourself.
  2. Report Output Directory
    Specify a report output directory on the server. The custom AppBean class, which we will discuss later, will need to write out a temporarily PDF document on the server and then it will delete the document after sending the email. Occasionally, it may fail to delete for whatever reason. I am exposing this variable just so that we can control the ouput and know where to clean up. The custom AppBean class will create the directory structure if does not exist.
  3. Default Email Subject Line
    Specify a default email subject line. The is entirely optional of course. This particular default value also supports substitution variables. If, for instance, you would like to show the current record id on the subject line, find out what the proper MBO attribute name is and then surround it with curly brackets, e.g., {ponum}, {wonum}, etc. These variables will be replaced by actual values on run-time. In the example here, I want to display the PO number and PO description on the subject line.
7 The section element is mainly a layout element. My example here doesn't really illustrate its purpose because I am employing a single column layout. If you want to create a multi-column layout, be sure to read up more on this.
8 This textbox element is for user to enter email to addresses. Email addresses must be comma separated. This control is bound to the REPORTPARAMETER.EMAILTO attribute.
9 This textbox element is for user to enter email cc addresses. Addresses must be comma separated. The current user's email will be added here by default. If you don't want this, you need to remove the line from the AppBean class. This control is bound to the REPORTPARAMETER.EMAILCC attribute.
10 This textbox element is for user to enter email subject line. This control is bound to the REPORTPARAMETER.EMAILSUBJECT attribute.
11 This multilinetextbox element is for user to enter email message. This control is bound to the REPORTPARAMETER.EMAILCOMMENTS attribute.
14 When this button is clicked, it will fire the sendEmail() method, as stipulated by the "mxevent" attribute, in the custom AppBean class. Needless to say, this method name must exist in the bean class. If you want to change the method name, beware that you must change it in both places.
15 When this button is clicked, it will cancel out the operation and close the dialog box. The "dialogcancel" event is actually a common method inherited from the base class. We don't need to write any custom code to handle this event.

Step 2: Attach the custom dialog box to the PO application.

Tip: Always have a backup of your original Application Definition file. If you happened to corrupt the file you are working on, you then have the original copy to fall back on.
Tip: When importing an Application Definition file, do not have the application record opened in the Application Designer application. In fact, make sure the List tab is empty of any record before you do the import.
Tip: If you are developing a general purpose dialog box to be accessed by numerous applications and the dialog box is bound to fixed MBO(s), you can add your dialog box to the system Library XML file (instead of individual applications). The upside is less work for you, but the downside is that you may not be able to modify the dialog box via the Application Designer application.

This tutorial focuses on the PO application. If you want to use other applications, by all means go ahead. The steps are the same.

  1. Launch the Application Designer application.
  2. Retrieve the application of your choice, e.g., PO.
  3. Export the Application Definition (an XML file) of your application and save the file to a local location.
  4. Open the exported file with any text or XML editor of your choice.
  5. Scroll all the way down to the bottom of the page.
  6. Just before the </presentation> end tag, insert your XML code block (from step 1) here. Make sure your code is within the <presentation> tag and it doesn't break other existing tags.
  7. Save your changes.
  8. Go back to the Application Designer application.
  9. On the List tab, click on the Import Application Definition toolbar button to import your modified file.
  10. Done.

Step 3: Enable security for the custom dialog box.

Figure 4: Adding new signature option. New Signature Option

Figure 5: Grant access to signature option in PO application. Grant Access to Signature Option

Follow these steps to enable security for the dialog box:

  1. Launch the Application Designer application.
  2. Retrieve the application which you modified on step 2.
  3. On the Select Action menu, click on Add/Modify Signature Options.
  4. Click on New Row to add a new row.
  5. At a minimum, you need to provide a name for the option and a description (see figure 4). Others you can do as you see fit. The only key thing to watch out for is that the option name must be the same as your dialog box id. This is how the system associates this signature option to your dialog box.
  6. Exit out the Application Designer application.
  7. Launch the Security Groups application and retrieve a security group named "EVERYONE".
  8. Go to the Applications tab.
  9. Look up the application of your choice and you should be able to see the new signature option (see figure 5). Grant access to it and save your changes.
  10. Done.
Note: I am using the "EVERYONE" security group because it is the quickest approach for me to grant wide access. You should really only give access to group(s) that needs it.

Step 4: Associate the custom dialog box to a custom toolbar button.

Figure 6: Adding new toolbar control. Adding New Toolbar Control

Follow these steps to create a custom toolbar button to launch your dialog box:

  1. Launch the Application Designer application.
  2. Retrieve the application which you modified on step 2.
  3. On the Select Action menu, click on Add/Modify Toolbar Menu.
  4. Click on New Row to add a new row. Use the following values (also shown in figure 6):
    • Element Type = OPTION
    • Key Value = <Select your new signature option created in step 3 from the pick list.>
    • Image = nav_icon_statusSent.gif
    • Position = <Use any value as you see fit.>
    • Subposition = <Use any value as you see fit.>
    • Visible = Yes
    • Tabs = MAIN
  5. Exit out the Application Designer application.
  6. Launch the application which you modified on step 2.
  7. Go to any tab other than the List tab. You should be able to see your new custom toolbar control. Click on it to open the dialog box. At this point, you can only view your dialog box. It will not work because no functionality has been implemented yet.
  8. Done.
Tip: You may use any images found in this "<maximo>\applications\maximo\maximouiweb\webmodule\webclient\images\" directory on your Maximo server. To use any image from this directory, simply type in the image file name without the file path like I did here.

Step 5: Create a custom AppBean class.

You can download the entire AppBean source code from the File Download section. This code is complete and requires no further modification. All you need to do is compile it into a Java class file. Since the code is lengthy, I will not go over it line-by-line. Rather, I will point out some of the key features for you. Please refer to the source code as I go over the following:

First, let's take a look at the overall class structure:

  • The class extends the psdi.webclient.system.beans.AppBean class, which is a requirement.
  • The package name is custom.webclient.system.beans. If you are to modify this name, you need to update the XML code for the dialog box accordingly. It is referenced there.
  • The initialize() is a method from the base class. We are simply overriding it here. This method is automatically called when the dialog box first load. We will be setting default value for some form controls here. Do not change the method name.
  • The sendEmail() is a custom method that will perform the core task, i.e., generate report and email report. This method name is explicitly referenced in the XML code for the dialog box. You are free to change the method name, but you must also update the XML code accordingly.
  • The log() is a custom method for writing out custom message to the log file. This method explicitly uses the mail logger and it will only output message if the logger is in debug mode. Otherwise, nothing will be written to the log file. Keep this method handy and use it on your other Java classes. You might want to consider using other logger as well. The mail logger is appropriate in this tutorial but may not be so in other situations. Check out the Logging application in Maximo for other types of loggers.
  • The msgbox() is a custom method for displaying custom message on screen via a pop up window. This method explicitly uses a custom message object created in Maximo (see step 6 for details). The hardcoded strings "messagebox" and "CustomMessage" are used to identify that particular message object. You may use other if you wish. Keep this method handy and use it on your other Java classes.

Now, let's examine some specific functions:

  • How to get the dialog box underlying MBOs?

    Recall from step 1 we have bound 2 different MBOs (i.e., PO and REPORTPARAMETER) to our dialog box. One is assigned on the dialog element and the other through a datasource element. Both will require different method to access them:

    • For dialog element, use the getAppBean(), e.g.,
      MboRemote mbo = this.app.getAppBean().getMbo();
    • For datasource element, use the getDataBean() and pass in the datasource element id, e.g.,
      MboRemote mbo = this.app.getDataBean("RPTEMAIL_ds1").getMbo();
  • How to find a dialog box control by id and get its value?

    You may use the findControl() and getProperty() respectively, e.g.,

    ControlInstance ctr1 = this.clientSession.findControl("rptemail_emailsubject");
    String uservalue = ctr1.getProperty("value");
  • How to set default value for dialog box control?

    The key is to get the correct MBO (recall we have 2 different MBOs) first and then use the setValue(). The following example will display the current user's email on the Email Cc text field:

    MboRemote mbo = this.app.getDataBean("RPTEMAIL_ds1").getMbo();
    mbo.setValue("emailcc", this.clientSession.getMXSession().getUserInfo().getEmail());
  • How to generate a dynamic where clause for the current record?

    When running a report programmatically, we need to pass in a record filter for the current record. Otherwise, the report will show all records. The following example will show you how to generate a dynamic where clause based upon the unique id for the current display record:

    MboRemote mbo = this.app.getAppBean().getMbo();
    String whereclause = mbo.getUniqueIDName() + " = " + mbo.getUniqueIDValue();

    The value for the whereclause string will look something like this: "POID = 18704"

  • How to properly concatenate file paths in Java?

    Java is finicky about the character slash in file path because back-slash has special meaning in Java. To avoid headache when concatenating paths, I suggest you use the java.io.File class to combine paths for you, e.g.,

    import java.io.File;
    String path1 = "C:/temp";
    String path2 = "subfolder\\testfile.txt";
    File outputFile = new File(path1, path2);
    System.out.println(">>>> Full File Path = '" + outputFile.getAbsolutePath() + "'");
    System.out.println(">>>> File Name Only = '" + outputFile.getName() + "'");

    Output:
    >>>> Full File Path = 'C:\temp\subfolder\testfile.txt'
    >>>> File Name Only = 'testfile.txt'
  • How to generate a report programmatically?

    The com.ibm.tivoli.maximo.report.birt.admin.ReportAdminServiceRemote class provides a runReport() method to generate report into byte array, e.g.,

    UserInfo ui = this.clientSession.getMXSession().getUserInfo();
    ReportParameterData para = new ReportParameterData();
    para.addParameter("where", "POID = 1234");
    ReportAdminServiceRemote reportservice = (ReportAdminServiceRemote)MXServer.getMXServer().lookup("BIRTREPORT");
    byte[] reportOutput = reportservice.runReport(ui, "poprint.rptdesign", "PO", para, "newreport.pdf", "pdf");
  • How to close the dialog box?

    You need to instantiate a new instance of psdi.webclient.system.controller.WebClientEvent object and pass in the "dialogclose" type, e.g.,

    WebClientEvent newEvent = new WebClientEvent("dialogclose", this.app.getCurrentPageId(), null, this.clientSession);
    this.clientSession.queueEvent(newEvent);

Step 6: Create a custom message box.

To create a generic message box that can be used to display all kind of custom messages, follow these steps:

  1. Launch the Database Configuration application.
  2. On the Select Action menu, click on Messages.
  3. Click on New Row to add a new row. Use the same settings as shown in figure 7 below. Both the Message Group value and the Message Key value are referenced in the AppBean class, so they must match.
    Figure 7: Creating a new message object. Creating New Message Object

    Figure 8: What the message box looks like at run-time. Message Box
  4. Done.
Note: The "Display ID?" property doesn't seem to work in my current version of Maximo. Perhaps IBM will fix this in future version. Supposeably, this property will allow us to hide the message ID on the message box but it doesn't (as shown in figure 8).
Tip: Once you have a generic message box created, you can keep re-using it in your other Java classes. You don't really need to create a new one each time.

Step 7: Turn on debugging mode for the logger.

Java development for Maximo can be a daunting task for those who lack patience. Often time, you will be writing code in blind because you cannot test what you just wrote until you deployed your code which can take 10 or more minutes. Ability to write out data to a log file can ease the development and debugging effort. There are many different types of logger in Maximo which you can tap into. Some are application specific, some are task specific, and so on. The output location of log file should be <maximo>\logs.

In this tutorial, I used the "mail" logger because it seems to make the most sense. Having said that, you are welcome to use other as you see fit. In the custom AppBean class, we specifically stated that only show logging info when the "mail" logger is in debug mode. Simply follow these steps to turn on the debugging mode for the "mail" logger. This is completely optional by the way.

  1. Launch the Logging application.
  2. Look up a root logger named "mail".
  3. Change the Log Level to "DEBUG" as shown below:
    Figure 9: Changing logger to debug mode. Changing logger to debug mode
  4. Click on Save and then make sure to click on Select Action > Apply Settings after.
  5. Done.
Once you begin testing the email tool, make sure to check the output log file for logging information, which should look something like this:
28 May 2012 09:11:37:381 [DEBUG] >>>> Entering custom.webclient.system.beans.EmailReportAppBean:sendEmail()
28 May 2012 09:11:37:381 [DEBUG] >>>> Report Name = poprint.rptdesign
28 May 2012 09:11:37:381 [DEBUG] >>>> Where POID = 18704
28 May 2012 09:11:37:381 [DEBUG] >>>> Output File Path = 'E:\temp\PO_20120528091137AM.pdf'
28 May 2012 09:11:38:991 [DEBUG] --------------------------------------------
28 May 2012 09:11:38:991 [DEBUG] To: johndoe@hotmail.com
28 May 2012 09:11:38:991 [DEBUG] From: maximo.administrator@company.com
28 May 2012 09:11:38:991 [DEBUG] Subject: Purchase Order #5992
28 May 2012 09:11:38:991 [DEBUG] Message: testing
28 May 2012 09:11:38:991 [DEBUG] File Attachment:E:\temp\PO_20120528091137AM.pdf
28 May 2012 09:11:38:991 [DEBUG] --------------------------------------------
28 May 2012 09:12:03:802 [DEBUG] >>>> Exiting custom.webclient.system.beans.EmailReportAppBean:sendEmail()
Tip: Change the log level back to "ERROR" when not testing or troubleshooting. Otherwise, you will end up with huge log files taken up precious server disk space. "ERROR" log level means only error will be written to the log file.

Figure 10: Class file deployment location. Class file deployment location

Step 8: Deployment and testing.

Follow these final steps:

  1. Copy your custom AppBean class to the following location on your Maximo server:
    <maximo>\applications\maximo\maximouiweb\webmodule\WEB-INF\classes\
  2. Re-build and deploy Maximo EAR file.
  3. Done.

At this point, you are ready for testing. Simply launch your application of choice and test out the email tool.

Tip: Custom bean class must be deployed to a different location on the server than other types of classes (e.g., field class, MBO class, etc.). For other types of classes, you have to copy your file to <maximo>\applications\maximo\businessobjects\classes\. Whereas, for bean class the path is <maximo>\applications\maximo\maximouiweb\webmodule\WEB-INF\classes\.The system will not inform you if you have your class file at the wrong location. But you will be left wondering why your code doesn't work.

Final Notes

If you do find this tool useful, you may also want to consider these additional enhancements:

  1. On the AppBean class, add a validation check to make sure email addresses entered are comma delimited. The current code will throw an error if email addresses are delimited by semi-colon for instance. I have amended the Java source code to replace all semi-colons with commas.
  2. On the AppBean class, add a check to see whether the current user has the necessary rights to run a particular report before generating one. The psdi.app.report.ReportService object has a method called "canRunThisReport()" which can do just that.

If you have any questions or comments, feel free to contact me. You can find my contact information on my home page.

Tip: If you have problem sending email from Maximo (via SMTP) to hotmail, yahoo or google account for instance, contact your network guys and ask them to configure your SMTP server allowing your Maximo server to relay email.
Copyright © 2013 www.xcentricway.ca. All rights reserved.