Package hirondelle.web4j.database

Source Code of hirondelle.web4j.database.ReportBuilder

package hirondelle.web4j.database;

import java.util.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.ResultSetMetaData;

import hirondelle.web4j.BuildImpl;
import hirondelle.web4j.request.Formats;
import hirondelle.web4j.security.SafeText;
import hirondelle.web4j.util.Args;

/**
Translates a <tt>ResultSet</tt> row into a <tt>Map</tt>.
 
<P>The returned {@code Map<String, SafeText>} has :
<ul>
<li>key - column name.
<li>value - column value as {@link SafeText}. The column values may be formatted
using  {@link Formats#objectToTextForReport(Object)}, according to which constructor
is called.
</ul>
<P><tt>SafeText</tt> is used to protect the caller against unescaped special characters,
and Cross Site Scripting attacks.
*/
final class ReportBuilder extends ModelBuilder<Map<String, SafeText>> {
 
  /**
   Builds a <tt>Map</tt> whose values are simply the <em>raw, unprocessed text</em> of the
   underlying <tt>ResultSet</tt>. These values are placed into {@link SafeText}
   objects, to allow for various styles of escaping special characters when presenting
   the data in the view.
 
   <P>Database formatting functions can be used in the underlying SELECT statement
   to format values to the desired form.
  */
  ReportBuilder(){
    /*
     Implementation Note
     This is a relatively rare instance where is it makes sense to
     declare an empty constructor.
    */
  }

  /**
   Constructor for applying some processing to column values, instead of using the raw text.
 
   <P><tt>aColumnTypes</tt> is used to convert each column into an <tt>Object</tt>.
   The supported types are the same as for {@link ConvertColumn}.
  
   <P>After conversion into the desired class,
   {@link hirondelle.web4j.request.Formats#objectToTextForReport(Object)} is used to apply
   formats to the various objects.
   
   @param aColumnTypes defines the type of each column, in order from left to right, as
   they appear in the <tt>ResultSet</tt>; contains <tt>N</tt> class literals,
   where <tt>N</tt> is the number of columns in the <tt>ResultSet</tt>; contains only
   the classes supported by {@link ConvertColumn}; this constructor will create a defensive
   copy of this parameter.
   @param aFormats used to apply the
   formats specified in <tt>web.xml</tt> and
   {@link hirondelle.web4j.request.Formats#objectToTextForReport(Object)},
   localized using {@link hirondelle.web4j.request.LocaleSource}.
  */
  ReportBuilder(Class<?>[] aColumnTypes, Formats aFormats){
    Args.checkForPositive(aColumnTypes.length);
    fColumnTypes = defensiveCopy(aColumnTypes);
    fFormats = aFormats;
    fColumnToObject = BuildImpl.forConvertColumn();
  }
 
  /**
   Returns an unmodifiable <tt>Map</tt>.
  
   <P>See class description.
  */
  Map<String, SafeText> build(ResultSet aRow) throws SQLException {
    LinkedHashMap<String, SafeText> result = new LinkedHashMap<String, SafeText>();
    SafeText value = null;
    ResultSetMetaData metaData = aRow.getMetaData();
    for (int columnIdx = 1; columnIdx <= metaData.getColumnCount(); ++columnIdx) {
      if ( doNotTranslateToObjects() ) {
        value = getSafeText(aRow, columnIdx);
        //fLogger.finest("Raw unformatted text value: " + value.getRawString());
      }
      else {
        if ( fColumnTypes.length != metaData.getColumnCount() ) {
          throw new IllegalArgumentException(
            "Class[] has different number of elements than ResultSet: " + fColumnTypes.length +
            " versus " + metaData.getColumnCount () + ", respectively."
          );
        }
        value = getFormattedObject(aRow, columnIdx);
        //security risk to log data: fLogger.fine("Formatted object: " + value);
      }
      result.put(metaData.getColumnName(columnIdx), value);
    }
    return Collections.unmodifiableMap(result);
  }
 
  // PRIVATE //

  /** The types to which ResultSet columns will be converted.  */
  private Class<?>[] fColumnTypes;
 
  /** Applies formatting to objects created from ResultSet columns.  */
  private Formats fFormats;
 
  /** Translates ResultSet columns into desired Objects. */
  private ConvertColumn fColumnToObject;
 
  private Class[] defensiveCopy(Class[] aClassArray){
    Class[] result = new Class[aClassArray.length];
    System.arraycopy(aClassArray, 0, result, 0, aClassArray.length);
    return result;
  }
 
  private boolean doNotTranslateToObjects() {
    return fColumnTypes == null;
  }

  private SafeText getSafeText(ResultSet aRow, int aColumn) throws SQLException {
    SafeText result = null;
    String text = aRow.getString(aColumn);
    if ( text == null ) {
      result = new SafeText(Formats.getEmptyOrNullText());
    }
    else {
      result = new SafeText(text);
    }
    return result;
  }

  private SafeText getFormattedObject(ResultSet aRow, int aColumnIdx) throws SQLException {
    Object translatedObject = getUnformattedObject(aRow, aColumnIdx);
    return fFormats.objectToTextForReport(translatedObject);
  }

  private Object getUnformattedObject(ResultSet aRow, int aColumnIdx) throws SQLException {
    return fColumnToObject.convert(aRow, aColumnIdx, fColumnTypes[aColumnIdx-1]);
  }
}
TOP

Related Classes of hirondelle.web4j.database.ReportBuilder

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.