Difference between revisions of "Tabulation Script"

From Catglobe Wiki
Jump to: navigation, search
(Moving script location)
(Create first version)
Line 21: Line 21:
 
Due to the fact that tabulation script belongs to REPORT DOMAIN rather RUNTIME DOMAIN, it MUST be in the same assembly with REPORT. And to not change so much at the same time, the file ''CGScript_System_Report'' is '<u>''copied'''</u> to ''CatGlobe.Report'' assembly under folder ''Script''. The namespace was also changed to '''CatGlobe.Framework.Report.Script'''.
 
Due to the fact that tabulation script belongs to REPORT DOMAIN rather RUNTIME DOMAIN, it MUST be in the same assembly with REPORT. And to not change so much at the same time, the file ''CGScript_System_Report'' is '<u>''copied'''</u> to ''CatGlobe.Report'' assembly under folder ''Script''. The namespace was also changed to '''CatGlobe.Framework.Report.Script'''.
  
Due to the fact that CGScript engine was designed to hide all unnecessary information from the outside (good point). But we need some references to some internal classes in order to implement a ''CGScriptLibrary''. Thus, the CatGlobe assembly must be internal visible to ''CatGlobe.Report''.
+
CGScript engine is designed to hide all unnecessary information from the outside (good point). But we need references to some internal classes in order to implement a ''CGScriptLibrary''. Thus, the CatGlobe assembly must be internal visible to ''CatGlobe.Report''.
  
=== Custom static Instance ===
+
And, there must be a factory method for getting ''Interpreter'' that can support for report:
* HashTable
+
<source lang="csharp">
* static string
+
  public static class ScriptLibraryHelper
 +
  {
 +
      public static Interpreter GetReportInterpreter(this DataCacheSpecification dataCache)
 +
      {
 +
        return new Interpreter(new[] { CGScript_System_Report.Instance })
 +
        {
 +
            DataCacheSpecification = dataCache,
 +
        };
 +
      }
 +
  }
 +
</source>
 +
 
 +
That's mean, with a appropriate ''using'' statement, we can create report's interpreter as below:
 +
<source lang="csharp">
 +
    DataCacheSpecification dcs = DataCacheSpecification.GetBy(1);
 +
    Interpreter cgsEngine = dcs.GetReportInterpreter();
 +
</source>
  
 
=== Point of injections ===
 
=== Point of injections ===
  
 
==== ''TabulationDiagram'' ====
 
==== ''TabulationDiagram'' ====
As shown in processing of tabulation script section above, we need to HACK the ''TabulationDiagram'' o create the REAL report diagram because it wraps the REAL report inside. The original code looks as below:
+
As shown in processing of tabulation script section above, the main idea of ''TabulationDiagram'' is that it is created with enough information for generating a domain's diagram instance, but that instance is created whenever needed only.  
  
 +
So, to inject our processing with least painful, I decided to create a diagram creating delegate. The delegate type is declared in ''DiagramUtility'' class (''CatGlobe'' assembly) but the implementation is inside ''CatGlobe.Report'' assembly. After all, the instance of the delegate will be passed to ''CatGlobe'' from ''CatGlobe.Report'' during execution of a tabulation script. And the ''TabulationDiabram'' is changed as below:
 
<source lang="csharp">
 
<source lang="csharp">
 +
      public Diagram InternalDiagram
 +
      {
 +
        get
 +
        {
 +
            if (this.internalDiagram == null)
 +
              this.CreateInternalDiagram();
 +
            return this.internalDiagram;
 +
        }
 +
        set { this.internalDiagram = value; }
 +
      }
 +
 
       private void CreateInternalDiagram()
 
       private void CreateInternalDiagram()
 
       {
 
       {
 
         ...
 
         ...
 
+
         InternalDiagram = DiagramFactoryMethod != null
        // Provide outside
+
                              ? DiagramFactoryMethod(this.ReportTemplate, this.ChartName, DiagramType.CrossDiagram, this.ChartType, string.Empty, this.Parameter)
         InternalDiagram = DiagramUtilities.CreateDiagram(this.ReportTemplate
+
                              : DiagramUtilities.CreateDiagram(this.ReportTemplate
                                                          , this.CrossStruct
+
                                                              , this.CrossStruct
                                                          , this.Parameter.InternalStyle
+
                                                              , this.ChartName
                                                          , this.ChartName
+
                                                              , this.Generator.Header
                                                          , this.Generator.Header
+
                                                              , this.Generator.Title
                                                          , this.Generator.Title
+
                                                              , this.Generator.Parameter.ChartType
                                                          , this.Generator.Parameter.ChartType
+
                                                              , DiagramType.CrossDiagram
                                                          , DiagramType.CrossDiagram
+
                                                              , subtitle1, string.Empty, string.Empty);
                                                          , subtitle1, string.Empty, string.Empty);
 
                                                          , subtitle1, string.Empty, string.Empty);
 
 
         ...
 
         ...
 
       }
 
       }
 
</source>
 
</source>
  
To inject our processing
+
It can be understood as if there is a custom diagram generating delegate, use that. Otherwise, use the default method.
  
 +
==== ''CatGlobe.Report'''s code ====
 +
First of all, we need an implementation of the diagram generating delegate:
  
After checking the current code, I come to the final place that all the processing of tabulation script must go through to create a diagram. And that is the perfect candidate for injecting new report processing. It is method ''CreateDiagram'' of ''CGScript_System_Report'', the code is as below:
 
 
<source lang="csharp">
 
<source lang="csharp">
 +
// CatGlobe.Report assembly
 +
  public static class DomainDiagramFactory
 +
  {
 +
      public static Domain.Reports.Diagram CreateDiagram(
 +
        ReportTemplate template, string chartName, DiagramType diagramType,
 +
        ChartType chartType, string weight, Parameter parameter)
 +
  }
 +
</source>
 +
 +
Then, we need to transfer above delegate instance to ''CatGlobe'' assembly;
 +
<source lang="csharp">
 +
  internal sealed class CGScript_System_Report : CGScriptLibrary
 +
  {
 
       private static int CreateDiagram(List<Axis> columns, List<Axis> rows, FunctionIdentifier function)
 
       private static int CreateDiagram(List<Axis> columns, List<Axis> rows, FunctionIdentifier function)
 
       {
 
       {
         if (columns.Count > 2 || rows.Count > 2)
+
         ...
            throw new RuntimeException(string.Format("Crossing too many rows and columns may crash the server. A limit of 2 rows and 2 columns is set at the moment. Function '{0}' failed.", function.Name));
+
         TabulationDiagram diagram = TabulationModuleUtilities.CreateDiagramObject(crossStruct, config, DomainDiagramFactory.CreateDiagram);
 
+
         ...  
        Interpreter interpreter = function.Interpreter;
 
        TabulationConfiguration config = interpreter.TabulationConfig;
 
 
 
        Parameter p = config.DiagramParameter;
 
        p.Weight = interpreter.WeightColumnName;
 
        p.Filters = interpreter.FilterExpressionList.ToArray();
 
        p.DataCache = interpreter.DataCacheSpecification;
 
        p.ColumnList = columns;
 
        p.RowList = rows;
 
        p.SourceTable = function.Interpreter.SourceTable;
 
 
 
        ValidateConfiguration(function);
 
 
 
        config.DiagramGenerator = new CrossDiagramGenerater { Parameter = p };
 
 
 
        //generate the expression table and result table
 
        CrossDiagramGenerater.CrossStructure crossStruct = config.DiagramGenerator.BuildCrossEx();
 
        DataTableFunctions.FormatDataTableValue(crossStruct.DataTable, TabulationModuleConstants.DEFAULT_DECIMAL_POSITION, TabulationModuleConstants.DEFAULT_CULTURE, config.ShowErrorInResult);
 
 
 
        //generate the xml string based on the configuration
 
         TabulationDiagram diagram = TabulationModuleUtilities.CreateDiagramObject(crossStruct, config);
 
 
 
        if (diagram == null)
 
            throw new RuntimeException(string.Format("Cannot generate this type of chart: '{0}'. Function '{1}' failed.", config.DiagramParameter.ChartType, function.Name));
 
 
 
         config.DiagramCharts.Add(diagram);
 
 
 
        return config.DiagramCharts.Count;
 
 
       }
 
       }
 +
  }
 
</source>
 
</source>
 +
 +
== Document revisions ==
 +
{|
 +
|-
 +
| '''Version No.'''
 +
| '''Date'''
 +
| '''Changed By'''
 +
| '''Description'''
 +
|-
 +
| 0.1
 +
| 23.07.2009
 +
| Nguyen Trung Chinh
 +
| Create the first version
 +
|}

Revision as of 09:14, 23 July 2009

Tabulation Script

Tabulation Script is a CGScript library allowing user to create diagram/report. It's also capable of setting stylesheet (both external and internal).

Some classes

  • CGScript_System_Report: CGScript library implementation, contains all entry points to diagram/report generation process
  • TabulationModuleUtilities: contains utility methods
  • DiagramUtilities: also contains utility methods
  • TabulationDiagram: wrapper class for the REAL report diagram
  • TabulationConfiguration: contains all result of tabulation diagram (the name ??!!!!)

Understanding tabulation script processing

The processing of tabulation script can be understand as below:

  1. Create new Interpreter (which create also an instance of TabulationConfiguration as properties named TabulationConfig )
  2. Run the tabulation script => the result diagrams (if any) is stored inside DiagramCharts variable of TabulationConfiguration
  3. If has to show result, get the result diagram objects from DiagramCharts and set to session
  4. Show a SPECIFIC viewer that takes diagram objects from session and draw on screen (why do we need a SPECIFIC viewer?)

Injecting new processing with least impact

Moving script location

Due to the fact that tabulation script belongs to REPORT DOMAIN rather RUNTIME DOMAIN, it MUST be in the same assembly with REPORT. And to not change so much at the same time, the file CGScript_System_Report is 'copied' to CatGlobe.Report assembly under folder Script. The namespace was also changed to CatGlobe.Framework.Report.Script.

CGScript engine is designed to hide all unnecessary information from the outside (good point). But we need references to some internal classes in order to implement a CGScriptLibrary. Thus, the CatGlobe assembly must be internal visible to CatGlobe.Report.

And, there must be a factory method for getting Interpreter that can support for report:

   public static class ScriptLibraryHelper
   {
      public static Interpreter GetReportInterpreter(this DataCacheSpecification dataCache)
      {
         return new Interpreter(new[] { CGScript_System_Report.Instance })
         {
            DataCacheSpecification = dataCache,
         };
      }
   }

That's mean, with a appropriate using statement, we can create report's interpreter as below:

    DataCacheSpecification dcs = DataCacheSpecification.GetBy(1);
    Interpreter cgsEngine = dcs.GetReportInterpreter();

Point of injections

TabulationDiagram

As shown in processing of tabulation script section above, the main idea of TabulationDiagram is that it is created with enough information for generating a domain's diagram instance, but that instance is created whenever needed only.

So, to inject our processing with least painful, I decided to create a diagram creating delegate. The delegate type is declared in DiagramUtility class (CatGlobe assembly) but the implementation is inside CatGlobe.Report assembly. After all, the instance of the delegate will be passed to CatGlobe from CatGlobe.Report during execution of a tabulation script. And the TabulationDiabram is changed as below:

      public Diagram InternalDiagram
      {
         get
         {
            if (this.internalDiagram == null)
               this.CreateInternalDiagram();
            return this.internalDiagram;
         }
         set { this.internalDiagram = value; }
      }

      private void CreateInternalDiagram()
      {
         ...
         InternalDiagram = DiagramFactoryMethod != null
                              ? DiagramFactoryMethod(this.ReportTemplate, this.ChartName, DiagramType.CrossDiagram, this.ChartType, string.Empty, this.Parameter)
                              : DiagramUtilities.CreateDiagram(this.ReportTemplate
                                                               , this.CrossStruct
                                                               , this.ChartName
                                                               , this.Generator.Header
                                                               , this.Generator.Title
                                                               , this.Generator.Parameter.ChartType
                                                               , DiagramType.CrossDiagram
                                                               , subtitle1, string.Empty, string.Empty);
         ...
      }

It can be understood as if there is a custom diagram generating delegate, use that. Otherwise, use the default method.

CatGlobe.Report's code

First of all, we need an implementation of the diagram generating delegate:

// CatGlobe.Report assembly
   public static class DomainDiagramFactory
   {
      public static Domain.Reports.Diagram CreateDiagram(
         ReportTemplate template, string chartName, DiagramType diagramType,
         ChartType chartType, string weight, Parameter parameter)
   }

Then, we need to transfer above delegate instance to CatGlobe assembly;

   internal sealed class CGScript_System_Report : CGScriptLibrary
   {
      private static int CreateDiagram(List<Axis> columns, List<Axis> rows, FunctionIdentifier function)
      {
         ...
         TabulationDiagram diagram = TabulationModuleUtilities.CreateDiagramObject(crossStruct, config, DomainDiagramFactory.CreateDiagram);
         ... 
      }
   }

Document revisions

Version No. Date Changed By Description
0.1 23.07.2009 Nguyen Trung Chinh Create the first version