Dynamic Column generation in scripted dataset ,BIRT

Hi All,


I have a requirement to create a table dynamically in BIRT. In this scenario, the columns of the scripted data set is dynamic.Is it possible to dynamically populate the scripted data set with dynamic column generation and to create a table based on that dynamically generated data set? 
 

Please me know is it feasible to do this way.If so , please provide me an example code snippet or rptdesign file.

 




Thanks in advance.  





 


Comments

  • Yes. you can use designer API to create the design file from scratch.


  • This can be accomplished in a few different ways depending on your requirements.


     


    However as an example, I've attached an example that dynamically changes the query of a data set (Classic Models Data Set) to simulate your dynamic scripted data set.


     


    The dynamic table is build in the beforeFactory code.


    First, I query the data set (Classic Models Data Set) to get the result set.


    Then in the DataSetLogic function we start building the table by iterating through the data columns and dynamically adding columns, rows, and labels to a base table.


     


    Hopefully this example is helpful for you.


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • edited November 10, 2014

    Hi Matthew,


    Thanks for the reply and the example.


    I found that the example was using the JDBC data source.I saw few list of columns added to the output columns field of "Data Set to populate parameter list" dataset. Was it defined statically or is it added  dynamically from the "before Factory" code?


     


    I wanted to know how the dynamic column generation in the scripted data set which is using scripted Data source works?


     


    Can you please help me with the scenario?


     


     


    Hi dsoon,


    Can you please give me an example ?


  • Attached is a new design that adds columns to an existing Scripted Data Set and creates a dynamic table to display the output.


    As the columns are created via the API, they will not be visible to the GUI builder.


     


    However an example of the logic for adding columns to an existing Scripted Data Set is the following:


     



    dataSetHandle = reportContext.getDesignHandle().findDataSet("Data Set");  //Find Existing Data Set

    computedSet = dataSetHandle.getPropertyHandle(ScriptDataSetHandle.RESULT_SET_PROP);  //Get PropertyHandle

     

    //Create a Column

    resultColumn = StructureFactory.createResultSetColumn();  //ResultSetColumn

    resultColumn.setPosition(1);  //Set column position (Starting with 1)

    resultColumn.setColumnName("ColumnName");  //Set the column name

    resultColumn.setDataType("String");  //Set the data type of this column: Integer, String, Date Time, Decimal, Float, Boolean, Date, Time, Blob, Java Object 

    computedSet.addItem(resultColumn);  //Add column to Data set


     


     


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • Hi Matthew,


    Thanks a lot for the reply.I would like to use my own array which i fetched from other datasets via "onfetch" event in the scripted dataset and give as input to the column name method resultColumn.setColumnName();  //Set the column name


     


    i see all the code is being in the before factory event and the Onfetch gets called after the before factory which will not work.


    I tried to implement that  via "describe" event in the scripted dataset.


    http://developer.actuate.com/community/forum/index.php?/topic/20417-scripted-data-source-describe-event/


     


    i could not find an api to add the column name to the dataset. 


     


    Can you please provide me an example for this?.

  • Hello Sri,


     


    Because of the order of operations, I'm not sure if using the "describe" event is possible for what you are wanting to accomplish, as it seems that you have determined this due to the onFetch is called after the beforeFactory method.


     


    Dynamically creating elements based on the result set of a data set can get complex.


    In the attached example, I tried to simplify the design to demonstrate how to accomplish this.


    In the new example there is a function you can call to query a data set when needed.


    This example pulls column names from a Scripted Data Set, then provides examples to assign the data both hard coded and dynamically from another data set to the column either based on the Column Name or Column Position.


     


    The code in the initialize method is used to query a data set.  The logic in the ResultLogic function pulls data from the first column, assigns it to an array, then returns it back to the original call.


     


    The code in the beforeFactory creates a New Scripted Data Source and New Scripted Data Set, then calls the code in the initialize method to query one of the data sets for the column names and creates the columns.


    Then I set the Open and Fetch methods of the New Scripted Data Set in code with a few examples on how to assign the data, including how to pull data from another data set.


     


    The table is built dynamically based on the number of columns in the New Scripted Data Set.


     


    Let me know if you have any questions about this new example.


     


     


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • Hi Matthew,


    i tried to modify your example by replacing the jdbc datasource with my required datasource and tried running it. i am facing  few issues in running it.


     


    i modified in intialize and before factory methos.Please let me know the way i understood is right?


  • The example was only setup for a simple scenario.


    What issues are you running into?


    Or do you have any specific questions on how the example works?


    Also what modifications did you make to the initialize and beforeFactory methods?


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • edited November 27, 2014

    Hi Matthew,


    when i run the code as such i am getting an error as "Parameter label must be a string"


     


    Change i made for dataset is in before factory method


    //Or query another data set

    + "if( columnNameArray.indexOf(\"temp\") > -1 ){"

    +   "row[\"temp\"] =  QueryDataSet(\"Data Set\")[4];}"

    + "if(columnNameArray[5]){row[columnNameArray[5]] = QueryDataSet(\"Data Set\")[5];}"

    + "if(columnNameArray[6]){row[columnNameArray[6]] = QueryDataSet(\"Data Set\")[6];}"

    + "i++;"

    + "return true;"

    + "}"

    + "else return false;");

     


    Even after changing the dataset iam getting the same error. I tried to use the capabilities of cross tab for my requirement which had positive results.


     


    So i am proceeding with  the same.


     


    Thanks for the help.Please let me know where i did wrong in the modification

  • My apologies for the late reply.


    I'm not sure why your receiving the "Parameter label must be a string".


    The code snippet you posted looks correct.


    If possible, can you post your report example to look over?


    Please remove any sensitive data source information before posting.


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • Hi,


     


    I am using the same piece of code in data design scripted code. But getting the below error. 


     

    Any help would be really appreciated...

     


    A BIRT exception occurred. See next exception for more information.

    Wrapped java.lang.ClassCastException: com.actuate.birt.report.model.api.DataMartHandle cannot be cast to org.eclipse.birt.report.model.api.ReportDesignHandle (/datamart/data-sets/script-data-set[@id="3"]/method[@name="afterOpen"]#6)

     

    at org.eclipse.birt.data.engine.script.JSMethodRunner.runScript(JSMethodRunner.java:147)

     

    at org.eclipse.birt.report.engine.script.internal.DtEScriptExecutor.handleJS(DtEScriptExecutor.java:90)

     

    at org.eclipse.birt.report.engine.script.internal.DataSetScriptExecutor.handleJS(DataSetScriptExecutor.java:256)

     

    at org.eclipse.birt.report.engine.script.internal.DataSetScriptExecutor.handleAfterOpen(DataSetScriptExecutor.java:160)

     

    at org.eclipse.birt.data.engine.impl.DataSetRuntime.afterOpen(DataSetRuntime.java:603)

     

    at org.eclipse.birt.data.engine.impl.QueryExecutor.dataSetAfterOpen(QueryExecutor.java:229)

     

    at org.eclipse.birt.data.engine.impl.PreparedScriptDSQuery$ScriptDSQueryExecutor.executeOdiQuery(PreparedScriptDSQuery.java:224)

     

    at org.eclipse.birt.data.engine.impl.QueryExecutor.execute(QueryExecutor.java:1237)

     

    at org.eclipse.birt.data.engine.impl.ServiceForQueryResults.executeQuery(ServiceForQueryResults.java:233)

     

    at org.eclipse.birt.data.engine.impl.QueryResults.getResultIterator(QueryResults.java:178)

     

    at org.eclipse.birt.report.engine.api.impl.ExtractionResults.nextResultIterator(ExtractionResults.java:157)

     

    at org.eclipse.birt.report.designer.data.ui.dataset.DataSetPreviewer.preview(DataSetPreviewer.java:69)

     

    at org.eclipse.birt.report.designer.data.ui.dataset.ResultSetPreviewPage$5.run(ResultSetPreviewPage.java:372)

     

    at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:121)

     

    Caused by: org.eclipse.birt.data.engine.core.DataException: A BIRT exception occurred. See next exception for more information.

    Wrapped java.lang.ClassCastException: com.actuate.birt.report.model.api.DataMartHandle cannot be cast to org.eclipse.birt.report.model.api.ReportDesignHandle (/datamart/data-sets/script-data-set[@id="3"]/method[@name="afterOpen"]#6)

     

    at org.eclipse.birt.data.engine.core.DataException.wrap(DataException.java:123)

     

    at org.eclipse.birt.data.engine.script.ScriptEvalUtil.evaluateJSAsExpr(ScriptEvalUtil.java:1003)

     

    at org.eclipse.birt.data.engine.script.JSMethodRunner.runScript(JSMethodRunner.java:138)

     

    ... 13 more
  • It looks like there is a DataMartHandle vs ReportDesignHandle issue.


    Can you post a data design example so that I can look it over?


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • I am trying to create 3 data set output columns in afterOpen or beforeOpen methods of data set with the below code but getting the ClassCastException: com.actuate.birt.report.model.api.DataMartHandle cannot be cast to org.eclipse.birt.report.model.api.ReportDesignHandle 


     


    code snippet:


     


    importPackage(Packages.org.eclipse.birt.report.model.api);

    importPackage(Packages.org.eclipse.birt.report.model.api.elements);

    importPackage(Packages.org.eclipse.birt.report.model.elements.interfaces);

     

    //dataDesignHandle = reportContext.getDesignHandle().getDesignHandle();

    dataSetHandle = reportContext.getDesignHandle().findDataSet("Data Set");

    computedSet = dataSetHandle.getPropertyHandle(ScriptDataSetHandle.RESULT_SET_PROP);  

     

    ch = StructureFactory.createColumnHint();

    ch.setProperty("columnName", "Month");

     

    columnHint = dataSetHandle.getPropertyHandle(ScriptDataSetHandle.COLUMN_HINTS_PROP);

    columnHint.addItem(ch);

     

     

    resultColumn = StructureFactory.createResultSetColumn();  

    resultColumn.setPosition(1); 

    resultColumn.setColumnName("Month");  

    resultColumn.setDataType("String"); 

    computedSet.addItem(resultColumn);  

     

    //Create a Column

    resultColumn = StructureFactory.createResultSetColumn();  //ResultSetColumn

    resultColumn.setPosition(2);  //Set column position (Starting with 1)

    resultColumn.setColumnName("Product");  //Set the column name

    resultColumn.setDataType("String");  //Set the data type of this column: Integer, String, Date Time, Decimal, Float, Boolean, Date, Time, Blob, Java Object 

    computedSet.addItem(resultColumn);  //Add column to Data set

     

    //Create a Column

    resultColumn = StructureFactory.createResultSetColumn();  //ResultSetColumn

    resultColumn.setPosition(3);  //Set column position (Starting with 1)

    resultColumn.setColumnName("Amount");  //Set the column name

    resultColumn.setDataType("Integer");  //Set the data type of this column: Integer, String, Date Time, Decimal, Float, Boolean, Date, Time, Blob, Java Object 

    computedSet.addItem(resultColumn);  //Add column to Data set
  • Looking over this in more depth, I am unsure if this method will work in a data design due to how data designs fall in the order of operations.


     


    However since you are trying to create the columns in the data set and not in the reports beforeFactory method, you could dynamically create columns in the data set using the describe method.


    So for example, in your data set's describe method you would enter the following lines of code to create the 3 columns as in the example code posted.



    this.addDataSetColumn("Month","STRING"); //JSDataSetImpl (String name, String type("INTEGER","DOUBLE","DECIMAL","DATE","STRING","ANY"))
    this.addDataSetColumn("Product","STRING"); //JSDataSetImpl (String name, String type("INTEGER","DOUBLE","DECIMAL","DATE","STRING","ANY"))
    this.addDataSetColumn("Amount","INTEGER"); //JSDataSetImpl (String name, String type("INTEGER","DOUBLE","DECIMAL","DATE","STRING","ANY"))
    return true; //Return true

    Attached is an example that demonstrates this alternative method.


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • Thanks for your reply..


    Could you pls help me with above code on how to set the locale specific column names. If my resource file is already linked with data design file.


  • Localization is typically set in the rptdesign file.  For column names in a table, you can set th localization of the label in the header row under the label's Property Editor -> Localization.


     


    Or are you referring to something else?


    Matthew L.
    Actuate is now OpenText
    http://www.actuate.com

  • In data sets we can set the display name of columns, i am referring to that requirement.


    Basically, I want to create columns dynamically at runtime & want to set the display name of those columns as well (By mapping display key with some resource file property)


  • @Matthew L. said:
    This can be accomplished in a few different ways depending on your requirements.

     

    However as an example, I've attached an example that dynamically changes the query of a data set (Classic Models Data Set) to simulate your dynamic scripted data set.

     

    The dynamic table is build in the beforeFactory code.

    First, I query the data set (Classic Models Data Set) to get the result set.

    Then in the DataSetLogic function we start building the table by iterating through the data columns and dynamically adding columns, rows, and labels to a base table.

     

    Hopefully this example is helpful for you.

    Hi Matthew,

    I also want to do the same thing. Will it be possible for you to attach an example again? I am not able to see any attached example here.

    Thank you in advance,
    Tanvi.

  • Hi,
    I have the same pb than tanvi : I can't get any attached samples :(
    Too bad...it seems so fine !!! :)

    Thanks in advance, ;)
    Laurent

  • Hi

    Did anyone solve this problem? Please send me the example.
    Thank you

Sign In or Register to comment.