Example Java Code for a Report Plug-in

The simplest way to create a new report is to extend the abstract class, AbstractReport. AbstractReport is located in the sas.dbuilder.util.jar at com.sas.wadmin.reports. AbstractReport provides the default implementation of the majority of the methods required by the report plug-in interface, ReportingInterface. In this example, all of the logic to generate the report is handled by SAS code, which is embedded in the Java code. The SAS Code is submitted to the application server by the reporting framework when the Run and view a report button is pressed in the Reports window.
Specific JAR files are needed to use the import statements in the sample code that is provided in this section. The JAR files for your reports plug-in code are located in the folder named SASVersionedJarRepository. This folder is usually located in the same directory as the SASDataIntegrationStudio folder. Make sure your path includes the following JAR files:
sas.dbuilder.util.jar 
sas.framework.workspace.jar 
sas.oma.joma.rmt.jar
The following example creates a summary report of all of the tables in the metadata server. This example generates the Tables Report, which you can find in the table in the Reports window.
CAUTION:
The following code sample was formatted so that each line fits within the page margins even if that string was continued on another line. Newline characters within a string generate compile errors, so do not put strings on a separate line as shown in this example.
import com.sas.metadata.remote.MdException;
import com.sas.wadmin.plugins.ReportingInterface;
import com.sas.wadmin.reports.AbstractReport;
import com.sas.wadmin.reports.ReportingController;
import com.sas.workspace.MessageUtil;
import com.sas.workspace.SASCodeGeneration;
import com.sas.workspace.WAdminResource;
import com.sas.workspace.WsAppServer;
import com.sas.workspace.WsServerRequest;


/**
 * TableListingReport generates a summary report all of the tables in 
 * a repository. 
 */
public class TableListingReport extends AbstractReport
{   
   /**
    * Default constructor
    */
   public TableListingReport()
   {
   }
   
   /**
    * Gets the report name
    * @return the name of the report
    * @see com.sas.plugins.PluginInterface#getName()
    */
   public String getName()
   {
      return "Tables Report";
   }//end method
   
   /**
    * Gets the report description
    * @return the description of the report
    * @see com.sas.plugins.PluginInterface#getDescription()
    */
   public String getDescription()
   {
      return "Shows a list of all the tables in the repository";
   }//end method
     
   /**
    * Gets the category that the report will be using.  Cannot have
    * multiple levels, only a single level can be used
    * @return the category name
    * @see com.sas.wadmin.plugins.ReportingInterface#getCategory()
    */
   public String getCategory()
   {
     return "Table";
   }//end method

   /**
    * Should return the fully qualified class name of this class.  This is 
    * used to tie the report to the report visual. 
    * Example: com.sas.reports.TableReport
    * @return the report plug-in class name
    * @see com.sas.wadmin.plugins.ReportingInterface#getReportingClass()
    */
   public String getReportingClass()
   {
      return "com.sas.reports.TableListingReport";
   }//end method
   
   /**
    * This method is called after the user selects a report and exits out
    * of the reporting framework.  This method executes on the UI thread
    * and is called prior to when getSourceCode() is sent to the application server. 
    * @see com.sas.wadmin.plugins.ReportingInterface#onSelected()
    */
   public void onSelected()
   {
      //This report doesn't have any extra UI elements
   }//end method

   /** 
    * Gets the report's generated code.  This code will then be executed on the 
    * application server on a background thread.
    * @return string buffer containing the code to send to the application server
    * @see com.sas.wadmin.plugins.ReportingInterface#getSourceCode()
    */
   public StringBuffer getSourceCode()
   {
      SASCodeGeneration codeGen = new SASCodeGeneration();
      
      codeGen.addCommentLine( "Creates an overview or summary report of 
                               all tables in the server." );
      WsServerRequest svrRequest = ReportingController.getInstance().
                                   getServerRequest();
      WsAppServer appServer = svrRequest.getAppServer();
      
      if (appServer == null)
         return new StringBuffer();
      
      try
      {
          codeGen.genMetadataMacrosAndOptions( appServer.getServerContext(), 
                                               appServer.getServerContext(), 
                                               true );
      }
      catch (MdException me)
      {
         MessageUtil.displayMetadataExceptionMessage( me, MessageUtil.
                                                      ACCESSING );
      }
      catch ( java.rmi.RemoteException re )
      {
         com.sas.workspace.Workspace.handleRemoteException( re );
      }
      
      codeGen.addSourceCode( "filename request temp;\n\n" );
      codeGen.addSourceCode( "data _null_;\n" );
      codeGen.indent( 3 );
      codeGen.addSourceCode( "file request;\n" );
      codeGen.addSourceCode( "infile cards4;\n" );
      codeGen.addSourceCode( "length long $256;\n" );
      codeGen.addSourceCode( "input;\n" );
      codeGen.addSourceCode( "long=_infile_;\n" );
      codeGen.addSourceCode( "put long \' \';\n" );
      codeGen.unIndent( 3 );
      codeGen.addSourceCode( "cards4;\n" );
      codeGen.addSourceCode( "<GetMetadataObjects>\n" );
      codeGen.addSourceCode( "<ReposId>$METAREPOSITORY</ReposId>\n" );
      codeGen.addSourceCode( "<Type>PhysicalTable</Type>\n" );
      codeGen.addSourceCode( "<Objects/>\n" );
      codeGen.addSourceCode( "<ns>SAS</ns>\n" );
      codeGen.addSourceCode( "<Flags>260</Flags>\n" );
      codeGen.addSourceCode( "<Options>\n" );
      codeGen.addSourceCode( "<Templates>\n" );
      codeGen.addSourceCode( "<PhysicalTable Name=\"\" Desc=\"\" 
                               ChangeState=\ "\" MetadataCreated=\"\" 
                               MetadataUpdated=\"\">\n" );
      codeGen.addSourceCode( "<Trees/> <ResponsibleParties/><TablePackage/>
                              </PhysicalTable>\n" );
      codeGen.addSourceCode( "<ResponsibleParty Name=\"\"/>\n" );
      codeGen.addSourceCode( "<SASLibrary Name=\"\"/>\n" );
      codeGen.addSourceCode( "<Tree Name=\"\"/>\n" );
      codeGen.addSourceCode( "<DatabaseSchema Name=\"\"/>\n" );
      codeGen.addSourceCode( "</Templates>\n" );
      codeGen.addSourceCode( "</Options>\n" );
      codeGen.addSourceCode( "</GetMetadataObjects>\n" );
      codeGen.addSourceCode( ";;;;\n" );
      codeGen.addSourceCode( "run;\n\n" );
      codeGen.addCommentLine( "Issue the request." );
      codeGen.addSourceCode( "filename response temp lrecl=1024;\n\n" );
      codeGen.addSourceCode( "proc metadata in=request out=response;\n" );
      codeGen.addSourceCode( "run;\n\n" );
      codeGen.addCommentLine( "Build the XML Map file to parse the 
                               response." );
      codeGen.addSourceCode( "filename map temp;\n\n" );
      codeGen.addSourceCode( "data _null_;\n" );
      codeGen.indent( 3 );
      codeGen.addSourceCode( "file map;\n" );
      codeGen.addSourceCode( "put \'<?xml version=\"1.0\" ?>\';\n" );
      codeGen.addSourceCode( "put \'<SXLEMAP version=\"1.2\">\';\n" );
      codeGen.addSourceCode( "put \'<TABLE name=\"Tables\">\';\n" );
      codeGen.addSourceCode( "put \'<TABLE-PATH syntax=\"xpath\">/
                              GetMetadataObjects/Objects/PhysicalTable
                              </TABLE-PATH>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"table\" retain=\"YES\">
                              \';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                                    PhysicalTable@Name</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>character</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>STRING</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>60</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"description\" retain=\
                                     "YES\">\';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable@Desc</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>character</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>STRING</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>200</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"created\"   
                              retain=\"YES\">\';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable@MetadataCreated</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>date</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>TIME</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>20</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"modified\" 
                                     retain=\"YES\">\';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable@MetadataUpdated</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>date</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>TIME</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>20</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"owner\" retain=\"YES\">
                              \';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable/ResponsibleParties/
                              ResponsibleParty@Name</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>character</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>STRING</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>60</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"schema\" 
                                     retain=\"YES\">\';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable/TablePackage/
                              DatabaseSchema@Name</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>character</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>STRING</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>60</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"group\" 
                              retain=\"YES\">\';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable/Trees/Tree@Name</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>character</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>STRING</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>60</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'<COLUMN name=\"checkout\" 
                              retain=\"YES\">\';\n" );
      codeGen.addSourceCode( "put \"<PATH>/GetMetadataObjects/Objects/
                              PhysicalTable@ChangeState</PATH>\";\n" );
      codeGen.addSourceCode( "put \'<TYPE>character</TYPE>\';\n" );
      codeGen.addSourceCode( "put \'<DATATYPE>STRING</DATATYPE>\';\n" );
      codeGen.addSourceCode( "put \'<LENGTH>60</LENGTH>\';\n" );
      codeGen.addSourceCode( "put \'</COLUMN>\';\n" );
      codeGen.addSourceCode( "put \'</TABLE>\';\n" );
      codeGen.addSourceCode( "put \'</SXLEMAP>\';\n" );
      codeGen.unIndent( 3 );
      codeGen.addSourceCode( "run;\n\n" );
      codeGen.addCommentLine( "Parse the response with the XML library 
                               engine and PROC SQL." );
      codeGen.addSourceCode( "libname response xml xmlmap=map;\n\n" );
      codeGen.addCommentLine( "Create a HTML report for viewing 
                               the table." );        
      codeGen.addSourceCode( "filename myReport \"")
             .addSourceCode( getURL() )
             .addSourceCode("\";\n" );
      String sformat = getODSFormatType();
      codeGen.addSourceCode( "ods ")
             .addSourceCode( sformat )
             .addSourceCode( " file=myReport \n" );
      //Check to see if style sheet is being used
      String sStyleSheet = getODSStyleSheet();
      //This options only works with HTML...
      if ( sformat.equals( ReportingInterface.ODS_HTML )) 
         if (sStyleSheet != null && sStyleSheet.length() > 0)
         {
            codeGen.addSourceCode( "stylesheet=(URL=\"file:" )
                   .addSourceCode(sStyleSheet.trim())
                   .addSourceCode( "\") \n" );
         }
      String sAdditionalOptions = getODSAdditionalOptions();
      if (sAdditionalOptions != null && sAdditionalOptions.length() > 0)
      {
         codeGen.addSourceCode( sAdditionalOptions )
                .addSourceCode( "\n");
      }
      codeGen.addSourceCode(";\n");
      
      //Set up the Table column name display
      codeGen.addSourceCode("%let etls_table = %str(\"" + 
      codeGen.escapeMacroValue("Table Name") + "\");\n" )
         .addSourceCode("%let etls_descr = %str(\"" + 
      codeGen.escapeMacroValue("Description") + "\");\n" )
         .addSourceCode("%let etls_create = %str(\"" + 
      codeGen.escapeMacroValue("Created") + "\");\n")
         .addSourceCode("%let etls_modified = %str(\"" + 
      codeGen.escapeMacroValue("Last Modified") + "\");\n")
         .addSourceCode("%let etls_owner = %str(\"" + 
      codeGen.escapeMacroValue("Owner") + "\");\n")
         .addSourceCode("%let etls_schema = %str(\"" + 
      codeGen.escapeMacroValue("Schema") + "\");\n")
         .addSourceCode("%let etls_group = %str(\"" + 
      codeGen.escapeMacroValue("Folder") + "\");\n")
         .addSourceCode("%let etls_checkout = %str(\"" + 
      codeGen.escapeMacroValue("Checked Out") + "\");\n");
      
      codeGen.addSourceCode( "title \"")
             .addSourceCode( getName() )
             .addSourceCode( "\";\n\n" );
      codeGen.addSourceCode( "proc print data=response.tables label;\n" )
             .addSourceCode( "var table description created modified owner 
                              schema group checkout;\n")
             .addSourceCode( "label table = &etls_table\n" )
             .addSourceCode( "      description = &etls_descr\n" )
             .addSourceCode( "      created = &etls_create\n" )
             .addSourceCode( "      modified = &etls_modified\n" )
             .addSourceCode( "      owner = &etls_owner\n" )
             .addSourceCode( "      schema = &etls_schema\n" )
             .addSourceCode( "      group  = &etls_group\n" )
             .addSourceCode( "      checkout = &etls_checkout\n" );
      codeGen.addSourceCode( "run;\n\n" );
      codeGen.addSourceCode( "ods ")
             .addSourceCode( getODSFormatType() )
             .addSourceCode( " close;\n\n" );
      codeGen.addCommentLine( "Cleanup" );
      codeGen.addSourceCode( "filename request;\n" );
      codeGen.addSourceCode( "filename response;\n" );
      codeGen.addSourceCode( "filename map;\n" );
      
      return codeGen.getSourceBuffer();
   }//end method
 
}//end class

Last updated: January 16, 2018