Package hirondelle.web4j.database

Source Code of hirondelle.web4j.database.Report

package hirondelle.web4j.database;

import java.util.*;

import hirondelle.web4j.request.Formats;
import hirondelle.web4j.security.SafeText;
import hirondelle.web4j.util.Util;

/**
Utility for producing reports quickly from a <tt>ResultSet</tt>.
<P>Most web applications need to produce reports of summary or transaction information.
If a Model Object already exists for the given data, then it may be used to fetch and render the data, likely
with {@link Db}.
<P>If a Model Object does <em>not</em> already exist for the given report data, then this class may
be used to quickly implement the report, without the need to create a full Model Object.
<P>This class translates each <tt>ResultSet</tt> row into a <tt>Map</tt> of some form. This <tt>Map</tt> is meant not as a
robust Model Object, but rather as a rather dumb data carrier, built only for the purpose of reporting.
The <tt>Map</tt> key is always the column name, and the <tt>Map</tt> value takes various forms, according
to how the <tt>ResultSet</tt> is processed :
<ul>
<li>{@link #formatted(Class[], Locale, TimeZone, SqlId, DynamicCriteria, Object[])} - column values are parsed using
{@link ConvertColumn} into <tt>Integer</tt>, <tt>Date</tt>, and so on, and then standard formatting is applied
using {@link Formats#objectToText(Object)}.  (This is the recommended style.)
<li>{@link #raw(SqlId, DynamicCriteria, Object[] )} - column values are all treated as simple text. To allow for various escaping styles in the view,
the text is actually returned as {@link SafeText}. By default, the text will be properly escaped for presentation
in HTML. If desired, some formatting can be applied directly in the underlying SQL statement itself, using database
formatting functions.
<li>{@link #unformatted(Class[], SqlId, DynamicCriteria, Object[])} - column values are parsed using {@link ConvertColumn} into 
<tt>Integer</tt>, <tt>Date</tt>, and so on, but formatting is deferred to the JSP.
</ul>
<P>Example of using the <tt>Map</tt> in a JSP. Here, column values are assumed to be already formatted, using
either {@link #raw(SqlId, DynamicCriteria, Object[])} or {@link #formatted(Class[], Locale, TimeZone, SqlId, DynamicCriteria, Object[])}:
<PRE>
{@code
<c:forEach var="row" items="${reportMap}" >
<tr>
  <td>${row['Name']}</td> 
  <td>${row['Visits']}</td> 
</tr>
</c:forEach>
  }
</PRE>

<P>If {@link #unformatted(Class[], SqlId, DynamicCriteria, Object[])} is used to build the <tt>Map</tt>, then formatting
of the resulting objects must be applied in the JSP.
<h3>Recommended Style</h3>
The recommended style is to use {@link #formatted(Class[], Locale, TimeZone, SqlId, DynamicCriteria, Object[])}.
 
<P>If {@link #raw(SqlId, DynamicCriteria, Object[])} or {@link #unformatted(Class[], SqlId, DynamicCriteria, Object[])} is used, then
the question usually arises of where to apply formatting :
<ul>
<li>format with database formatting functions - then there will often be much repetition of formatting function calls
across different <tt>SELECT</tt>s.
<li>format in the JSP (usually with JSTL) - be aware that there is often 
significant work involved. Not one but three operations can be necessary : a parse operation,
a format operation, and possibly a check-for-null.
</ul>
<h3><a name="emptyContent"></a>Empty Values</h3>
When the <tt>Map</tt> returned by this class has values as text, then any <tt>Strings</tt> which do not satisfy
{@link Util#textHasContent(String)} are replaced with the
return value of {@link hirondelle.web4j.request.Formats#getEmptyOrNullText} (which is in
turn configured in <tt>web.xml</tt>). This is a workaround for the fact that most browsers do
not render empty <tt>TD</tt> tags very well when the cell has a border. An alternate
(and likely superior) workaround is to set the
<tt><a href="http://www.w3.org/TR/REC-CSS2/tables.html#empty-cells">empty-cells</a></tt>
property of Cascading Style Sheets to <tt>'show'</tt>.
*/
public final class Report {
 
  /**
   Return column values without any processing.
  
   <P>For the returned {@code Map<String, SafeText>} objects,
   <ul>
   <li>key is the column name
   <li>value is the unprocessed column value, passed to a {@link SafeText}. <tt>SafeText</tt> is
   used instead of <tt>String</tt> to allow easy escaping of special characters in the view.
   </ul>
  
   @param aSqlId identifies the underlying <tt>SELECT</tt> statement
   @param aParams parameters for the <tt>SELECT</tt> statement, in the same order as in the underlying <tt>SELECT</tt> statement
  */
  public static List<Map<String, SafeText>> raw(SqlId aSqlId, DynamicCriteria aCriteria, Object... aParams) throws DAOException {
    List<Map<String,SafeText>> result = new ArrayList<Map<String, SafeText>>();
    ModelBuilder<Map<String, SafeText>> builder = new ReportBuilder();
    SqlFetcher fetcher = getFetcher(aSqlId, aCriteria, aParams);
    fetcher.fetchObjects(builder, result);
    return result;
  }

  /**
   Return column values after processing into formatted building block objects.
  
   <P>For the returned {@code Map<String, SafeText>} objects,
   <ul>
   <li>key is the column name
   <li>value is the processed column value, as <tt>SafeText</tt>. Column values are first parsed into
   building block objects using {@link ConvertColumn}. Then the objects are formatted in a 'standard'
   way using the configured {@link Formats}.
   </ul>
 
   @param aTargetClasses defines the target class for each column.
   The order of the classes in the array corresponds one-to-one with the column order of the underlying <tt>ResultSet</tt>.
   The size of the array matches the number of columns.
   Each class in the array must be supported by the configured {@link ConvertColumn}.
   @param aLocale <tt>Locale</tt> returned by {@link hirondelle.web4j.request.LocaleSource}
   @param aTimeZone <tt>TimeZone</tt> returned by {@link hirondelle.web4j.request.TimeZoneSource}
   @param aSqlId identifies the underlying <tt>SELECT</tt> statement
   @param aCriteria possible <em>dynamic</em> <tt>WHERE</tt> or <tt>ORDER BY</tt> clause. If no dynamic criteria, then
   just pass {@link DynamicCriteria#NONE}.
   @param aParams parameters for the <tt>SELECT</tt> statement, in the same order as in the underlying <tt>SELECT</tt> statement
  */
  public static List<Map<String, SafeText>> formatted(Class<?>[] aTargetClasses, Locale aLocale, TimeZone aTimeZone, SqlId aSqlId, DynamicCriteria aCriteria, Object... aParams) throws DAOException {
    List<Map<String, SafeText>> result = new ArrayList<Map<String, SafeText>>();
    //any date columns must be formatted in a Locale-sensitive manner
    Formats formats = new Formats(aLocale, aTimeZone);
    ModelBuilder<Map<String, SafeText>> builder = new ReportBuilder(aTargetClasses, formats);
    SqlFetcher fetcher = getFetcher(aSqlId, aCriteria, aParams);
    fetcher.fetchObjects(builder, result);
    return result;
  }
 
  /**
   Return column values as unformatted building block objects.
  
   <P>For the returned {@code Map<String, Object>} objects,
   <ul>
   <li>key is the column name
   <li>value is the processed column value, parsed into a building block Object using {@link ConvertColumn}.
   </ul>
 
   @param aTargetClasses defines the target class for each column.
   The order of the classes in the array corresponds one-to-one with the column order of the underlying <tt>ResultSet</tt>.
   The size of the array matches the number of columns.
   Each class in the array must be supported by the configured {@link ConvertColumn}.
   @param aSqlId identifies the underlying <tt>SELECT</tt> statement
   @param aCriteria possible <em>dynamic</em> <tt>WHERE</tt> or <tt>ORDER BY</tt> clause. If no dynamic criteria, then
   just pass {@link DynamicCriteria#NONE}.
   @param aParams parameters for the <tt>SELECT</tt> statement, in the same order as in the underlying <tt>SELECT</tt> statement
  */
  public static List<Map<String, Object>> unformatted(Class<?>[] aTargetClasses, SqlId aSqlId, DynamicCriteria aCriteria, Object... aParams) throws DAOException {
    List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
    ModelBuilder<Map<String, Object>> builder = new ReportBuilderUnformatted(aTargetClasses);
    SqlFetcher fetcher = getFetcher(aSqlId, aCriteria, aParams);
    fetcher.fetchObjects(builder, result);
    return result;
  }
 
  // PRIVATE //
 
  private Report(){
    //empty - prevent construction by caller
  }
 
  private static SqlFetcher getFetcher(SqlId aSqlId, DynamicCriteria aCriteria, Object[] aParams) throws DAOException {
    SqlFetcher result = null;
    if( DynamicCriteria.NONE == aCriteria ) {
      result = SqlFetcher.forSingleOp(aSqlId, aParams);
    }
    else {
      result = SqlFetcher.forSearch(aSqlId, aCriteria, aParams);
    }
    return result;
  }
}
TOP

Related Classes of hirondelle.web4j.database.Report

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.