Package com.cosmo.reports

Source Code of com.cosmo.reports.ReportsEngine

package com.cosmo.reports;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;

import org.apache.log4j.Logger;

import com.cosmo.Workspace;
import com.cosmo.data.DataAgent;
import com.cosmo.data.DataException;
import com.cosmo.data.DataQuery;
import com.cosmo.logging.LogFactory;
import com.cosmo.util.XmlUtils;

/**
* Implementa el generador de informes de Cosmo Framework.
*
* @author Gerard Llort
*/
public abstract class ReportsEngine
{
   /**
    * Enumera los tipos de TAG que pueden contener los informes para indicar valores.
    */
   public enum ReporTagType
   {
      /** Valor de la primera fila de una consulta. */
      FIRSTROWVALUE,
      /** Valor de la fila actual (en un grupo de detalle) de una consulta. */
      ROWVALUE,
      /** Valor est�tico. */
      STATICVALUE,
      /** Valor del workspace. */
      WORKSPACE
   }
  
   /**
    * Enumera los tipos de secci�n de un informe.
    */
   public enum ReportSection
   {
      /** Cabecera del informe. */
      HEADER,
      /** Cabecera de grupo de detalle. */
      DETAILGROUPHEADER,
      /** Fila de grupo de detalle. */
      DETAILGROUPROW,
      /** Pie de grupo de detalle. */
      DETAILGROUPFOOTER,
      /** Pie del informe. */
      FOOTER
   }

   // Variables internas
   private Workspace workspace;
   private Report report;

   Logger log = LogFactory.getLogger("Reporting Services");


   //==============================================
   // Constructors
   //==============================================

   /**
    * Constructor de la clase {@link ReportsEngine}.
    *
    * @param workspace Una instancia de {@link Workspace} que representa el workspace actual.
    */
   public ReportsEngine(Workspace workspace)
   {
      initialize();

      this.workspace = workspace;
   }

   public ReportsEngine(Workspace workspace, String reportId) throws ReportException
   {
      initialize();

      this.workspace = workspace;

      // Carga la plantilla de informe
      loadReport(reportId);
   }


   //==============================================
   // Properties
   //==============================================

   /**
    * Devuelve la instancia de {@link Workspace} usada internamente.
    */
   public Workspace getWorkspace()
   {
      return workspace;
   }

   /**
    * Devuelve la instancia de {@link Report} que representa el informe cargado actualmente.
    */
   public Report getReport()
   {
      return report;
   }

   /**
    * Indica si hay un informe cargado en el generador de informes.
    */
   public boolean isReportLoaded()
   {
      return (this.report != null);
   }


   //==============================================
   // Methods
   //==============================================

   /**
    * Genera el informe cargado actualmente y devuelve la URL de acceso.
    *
    * @return Una cadena que contiene la URL de acceso al informe generado y transformado por la implementaci�n.
    *
    * @throws ReportException
    */
   public abstract String generateReport() throws ReportException ;

   /**
    * Carga una plantilla de informe.
    *
    * @param reportId Una cadena que contiene el identificador del informe.
    *
    * @throws ReportException
    */
   public void loadReport(String reportId) throws ReportException
   {
      this.report = new Report(this.workspace, reportId);
   }

   /**
    * Renderiza el informe cargado en el motor de informes.<br />
    * Una vez renderizado el informe este se encuentra accesible en la URL asociada al informe.
    *
    * @throws DataException
    * @throws ReportException
    */
   public void render() throws DataException, ReportException
   {
      HashMap<String, ResultSet> data;
      StringBuilder xhtml;

      // Inicializaciones
      xhtml = new StringBuilder();
      data = new HashMap<String, ResultSet>();

      log.debug("Start rendering report '" + getReport().getId() + "'...");

      try
      {
         // Ejecuta todas las consultas necesarias para el informe
         for (DataQuery dq : getReport().getDataQueries())
         {
            data.put(dq.getId(), dq.execute(getWorkspace()));
         }

         // Genera el HEADER
         xhtml.append(renderSection(getReport().getHeader(), ReportSection.HEADER, null));

         // Genera los GRUPOS DE DETALLE
         for (ReportDetailGroup group : getReport().getDetailGroups())
         {
            xhtml.append(renderDetailGroup(group));
         }

         // Genera el FOOTER
         xhtml.append(renderSection(getReport().getFooter(), ReportSection.FOOTER, null));

         // Almacena el c�digo XHTML resultante
         getReport().setRenderedXhtml(XmlUtils.trimXml(xhtml.toString()));
      }
      catch (Exception ex)
      {
         log.error("Error rendering report '" + getReport().getId() + "': " + ex.getMessage(), ex);
         throw new ReportException(ex.getMessage(), ex);
      }

      log.debug("Report '" + getReport().getId() + "' renderized");
   }


   //==============================================
   // Private Members
   //==============================================

   /**
    * Renderiza una determinada secci�n del informe cargado actualmente.
    *
    * @param text Texto que corresponde a la secci�n dentro de la plantilla del informe.
    * @param section Un valor de {@link ReportSection} que indica que tipo de secci�n se debe renderizar.
    * @param rs Una instancia de {@link ResultSet} que contiene los datos del grupo de detalle actual o {@code null}
    *   si la secci�n no corresponde a un grupo de detalle.
    *  
    * @return Una cadena que contiene el c�digo XHTML correspondiente a la representaci�n gr�fica de la secci�n.
    *
    * @throws ReportException
    * @throws DataException
    */
   private String renderSection(String text, ReportSection section, ResultSet rs) throws ReportException, DataException
   {
      int curPos = 0;
      String xhtml = text;
      ReportTag tag = null;

      do
      {
         tag = getNextTag(xhtml, curPos);

         if (tag != null)
         {
            curPos = tag.getStartPosition() + 1;

            if (tag.getTagType() == ReporTagType.STATICVALUE)
            {
               xhtml = replaceTag(xhtml, tag, this.report.getStaticValue(tag.getValueName()));
            }
            else if (tag.getTagType() == ReporTagType.FIRSTROWVALUE)
            {
               xhtml = replaceTag(xhtml, tag, getFirstRowValue(tag));
            }
            else if (tag.getTagType() == ReporTagType.WORKSPACE)
            {
               xhtml = replaceTag(xhtml, tag, getWorkspaceValue(tag));
            }
            else if (section == ReportSection.DETAILGROUPROW && tag.getTagType() == ReporTagType.ROWVALUE)
            {
               xhtml = replaceTag(xhtml, tag, getRowValue(rs, tag));
            }
            else
            {
               throw new ReportException("Malformed report template (character " + curPos + "): Can't use ROWVALUE TAG outside a detail group");
            }
         }
      }
      while (tag != null);

      return xhtml;
   }

   /**
    * Renderiza un determinado grupo de detalle del informe.
    *
    * @param group Una instancia de {@link ReportDetailGroup} que representa el grupo de detalle a renderizar.
    *
    * @return Una cadena que contiene el c�digo XHTML que representa el grupo de detalle renderizado.
    *
    * @throws ReportException
    * @throws DataException
    */
   private String renderDetailGroup(ReportDetailGroup group) throws ReportException, DataException
   {
      StringBuilder xhtml = new StringBuilder();
      ResultSet rs = null;

      xhtml.append(renderSection(group.getHeader(), ReportSection.DETAILGROUPHEADER, null));

      try
      {
         // Genera los GRUPOS DE DETALLE
         DataQuery query = this.report.getDataQuery(group.getDataQueryId());
         rs = query.execute(this.workspace);
         while (rs.next())
         {
            xhtml.append(renderSection(group.getDetail(), ReportSection.DETAILGROUPROW, rs));
         }
      }
      catch (SQLException ex)
      {
         throw new DataException(ex.getMessage(), ex);
      }
      finally
      {
         DataAgent.closeResultSet(rs);
      }

      xhtml.append(renderSection(group.getFooter(), ReportSection.DETAILGROUPFOOTER, null));

      return xhtml.toString();
   }

   /**
    * Obtiene un valor de base de datos que se encuentra en la primera fila de una consulta.
    *
    * @param tag Una instancia de {@link ReportTag} que representa el TAG a rellenar.
    *
    * @return El valor a representar.
    *
    * @throws DataException
    */
   private String getFirstRowValue(ReportTag tag) throws DataException
   {
      String value = null;
     
      try
      {
         ResultSet rs = this.report.getDataQuery(tag.getConnectionId()).getResultSet();
         if (!rs.next())
         {
            throw new DataException("The query has no results.");
         }

         value = rs.getString(tag.getValueName());
      }
      catch (SQLException ex)
      {
         value = null;
         // throw new DataException(ex.getMessage(), ex);
      }

      return (value == null ? "[unknown value]" : value);
   }

   /**
    * Obtiene un valor dependiente a una fila de un grupo de detalle.
    *
    * @param rs Una instancia de {@link ResultSet} que contiene los datos. Debe estar correctamente posicionado en la fila adecuada.
    * @param tag Una instancia de {@link ReportTag} que representa el TAG a rellenar.
    *
    * @return El valor a representar.
    *
    * @throws DataException
    */
   private String getRowValue(ResultSet rs, ReportTag tag) throws DataException
   {
      String value = null;
     
      try
      {
         value = rs.getString(tag.getValueName());
      }
      catch (SQLException ex)
      {
         value = null;
         // throw new DataException(ex.getMessage(), ex);
      }

      return (value == null ? "[unknown value]" : value);
   }

   /**
    * Obtiene el valor de una TAG de workspace.
    *
    * @param tag Una instancia de {@link ReportTag} que representa el TAG para el que se desea obtener el valor.
    *
    * @return Una cadena de texto que contiene el valor a mostrar.
    *
    * @throws DataException
    */
   private String getWorkspaceValue(ReportTag tag) throws DataException
   {
      if (tag.getValueName().equals("name"))
      {
         return this.workspace.getName();
      }
      else if (tag.getValueName().equals("mail"))
      {
         return this.workspace.getMail();
      }
      else if (tag.getValueName().equals("url"))
      {
         return this.workspace.getUrl();
      }
      else if (tag.getValueName().equals("property"))
      {
         return this.workspace.getProperties().getString(tag.getPropertyName());
      }

      return null;
   }

   private String replaceTag(String text, ReportTag tag, String value)
   {
      return text.replace(tag.getOriginalTag(), value);
   }

   /**
    * Obtiene el siguiente TAG a partir de una determinada posici�n.
    *
    * @param text Texto que contiene los TAGs.
    * @param startPos �ndice del primer car�cter a partir del que se debe buscar.
    *
    * @return Una instancia de {@link ReportTag} que describe el TAG encontrado.
    *
    * @throws ReportException
    */
   private ReportTag getNextTag(String text, int startPos) throws ReportException
   {
      String chr;
      String tag;

      int idxStart = text.indexOf("[@", startPos);

      // Si no encuentra ning�n TAG termina
      if (idxStart < 0)
      {
         return null;
      }

      // Busca el cierre del TAG
      tag = "";
      for (int i = idxStart; i < text.length(); i++)
      {
         chr = "" + text.charAt(i);
         tag += chr;
         if (chr.equals("]"))
         {
            return new ReportTag(tag, idxStart);
         }
      }

      // Detectado un TAG no cerrado
      throw new ReportException("Malformed report template: unclosed TAG.");
   }

   /**
    * Inicializa la instancia.
    */
   private void initialize()
   {
      this.workspace = null;
      this.report = null;
   }


   //==============================================
   // Internal Classes
   //==============================================

   /**
    * Representa un TAG encontrado en un informe.<br />
    * Los TAGs admitidos son los siguientes:
    * <ul>
    * <li>{@code ROWVALUE rsColumnName}</li>
    * <li>{@code WORKSPACE [ name | mail | url | property PropertyName ]}</li>
    * </ul>
    */
   private class ReportTag
   {
      private static final String CMD_ROWVALUE = "ROWVALUE";
      private static final String CMD_FIRSTROWVALUE = "FIRSTROWVALUE";
      private static final String CMD_STATICVALUE = "STATICVALUE";
      private static final String CMD_WORKSPACE = "WORKSPACE";

      private int startPosition;
      private String valueName;
      private String propertyName;
      private String originalTag;
      private String connectionId;
      private ReporTagType tagType;
     
      /**
       * Constructor de la clase {@link ReportTag}.
       *
       * @param tag Una cadena que contiene el TAG leido desde el informe.
       * @param position �ndice del primer car�cter del TAG.
       *
       * @throws ReportException
       */
      public ReportTag(String tag, int position) throws ReportException
      {
         setStartPosition(position);
         this.originalTag = tag;
         this.connectionId = "";
         this.valueName = "";
         this.propertyName= "";

         getTagProperties();
      }

      public String getValueName()
      {
         return valueName;
      }

      public void setValueName(String valueName)
      {
         this.valueName = valueName;
      }

      public String getPropertyName()
      {
         return propertyName;
      }

      public void setPropertyName(String propertyName)
      {
         this.propertyName = propertyName;
      }

      public String getConnectionId()
      {
         return connectionId;
      }

      public void setConnectionId(String connectionId)
      {
         this.connectionId = connectionId;
      }

      public String getOriginalTag()
      {
         return originalTag;
      }

      public int getStartPosition()
      {
         return startPosition;
      }

      public void setStartPosition(int startPosition)
      {
         this.startPosition = startPosition;
      }

      public ReporTagType getTagType()
      {
         return tagType;
      }

      public void setTagType(ReporTagType tagType)
      {
         this.tagType = tagType;
      }

      /**
       * Analiza el TAG y obtiene sus propiedades.
       */
      private void getTagProperties() throws ReportException
      {
         String[] params = this.originalTag.replace("[@", "").replace("]", "") .split(" ");

         if (params[0].equals(ReportTag.CMD_STATICVALUE))
         {
            this.setTagType(ReporTagType.STATICVALUE);
            this.setConnectionId("");
            this.setValueName(params[1]);
         }
         else if (params[0].equals(ReportTag.CMD_FIRSTROWVALUE))
         {
            this.setTagType(ReporTagType.FIRSTROWVALUE);
            this.setConnectionId(params[1]);
            this.setValueName(params[2]);
         }
         else if (params[0].equals(ReportTag.CMD_ROWVALUE))
         {
            this.setTagType(ReporTagType.ROWVALUE);
            this.setValueName(params[1]);
         }
         else if (params[0].equals(ReportTag.CMD_WORKSPACE))
         {
            this.setTagType(ReporTagType.WORKSPACE);
            this.setConnectionId("");
            this.setValueName(params[1].toLowerCase().trim());

            // Si se trata de una propiedad de configuraci�n, a�ade el par�metro
            if (this.getValueName().trim().toLowerCase().endsWith("property"))
            {
               this.setPropertyName(params[2].toLowerCase().trim());
            }
         }
         else
         {
            throw new ReportException("Malformed report template: Unknown TAG '" + params[0] + "'");
         }
      }
   }
}
TOP

Related Classes of com.cosmo.reports.ReportsEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.