Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3)
B25386-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

20.11 Contents of Supporting Files

This section shows the contents of the following files:

20.11.1 sampleDC.xsd

Example 20-37 shows the contents of the sampleDC.xsd file.

Example 20-37 sampleDC.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://xmlns.oracle.com/adfm/adapter/test"
            xmlns="http://xmlns.oracle.com/adfm/adapter/test"
            elementFormDefault="qualified">
   <xsd:element name="Definition">
      <xsd:complexType>
         <xsd:attribute name="SourceLocation" type="xsd:string"/>    
      </xsd:complexType>
   </xsd:element>
</xsd:schema>

20.11.2 CSVHandler Class

Example 20-38 shows the contents of the CSVHandler class.

Example 20-38 CSVHandler

package oracle.adfinternal.model.adapter.sample;

import java.io.InputStream;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import oracle.binding.meta.DefinitionContext;
import oracle.binding.meta.StructureDefinition;

import oracle.adf.model.utils.SimpleStringBuffer;

import oracle.adf.model.adapter.AdapterException;
import oracle.adf.model.adapter.dataformat.AttributeDef;
import oracle.adf.model.adapter.dataformat.StructureDef;
import oracle.adfinternal.model.adapter.sample.CSVParser;
import oracle.adf.model.adapter.utils.Utility;

/**
 * Format handler for character separated values.
 * <p>
 * This class generates structures according to the JSR 227 specification from
 * a CSV data stream by parsing the data. The data types are guessed from the 
 * value of the first data line. It can extract values from a CSV data stream 
 * as well.
 * <p>
 * Data controls that deals with CSV data can use this class to generate data 
 * and structure.
 *
 * @version 1.0
 * @since 10.1.3
 */
public class CSVHandler
{
  // stream containing the data.
  private InputStream mDataStream;
 
  // if the first row contains the names
  private boolean mIsFirstRowNames = false;
 
  // Encoding styles
  private String mEncStyle;
 
  // Character value separator 
  private String mDelimiter;
 
  // Character used to quote a multi-word string
  private String mQuoteChar;
 
  // Column names
  private List mColNames = null; 
  
  ////////////////////////////// Constructors //////////////////////////////////
 
  /**
   * Creats a CSV format handler object.
   *
   * @param is input stream that contains the CSV data.
   * @param isFirstRowNames flag to indicate if the first row of the CSV data 
   *        can be treated as column names.
   * @param encodingStyle encoding style of the data.
   * @param delim character value separators.
   * @param quoteChar value that can be treated as quote.
   */
  public CSVHandler(
    InputStream is,
    boolean isFirstRowNames, 
    String encodingStyle,
    String delim, 
    String quoteChar)
  {
    mDataStream = is;
    mIsFirstRowNames = isFirstRowNames;
    mEncStyle = encodingStyle;
    mDelimiter = delim;
    mQuoteChar = quoteChar;
} 
 
 
  ///////////////////// Impl of FormatHandler //////////////////////////////////
 
  /**
   * Returns the structure definition extracted for the data format.
   * <p>
   *
   * @param name name of the root structure.
   * @param ctx definition context information.
   * @return the structure information extracted.
   */
  public StructureDefinition getStructure(String name, DefinitionContext ctx)
  {
    StructureDef attrParent = null;
    try
    {
      CSVParser parser;
        
      if (mEncStyle == null)
      {
        parser = new CSVParser(mDataStream);
      }
      else
      {
        parser = new CSVParser(mDataStream, mEncStyle);
      }
 
      parser.setSeparators(mDelimiter.toCharArray());
      if (mQuoteChar != null && mQuoteChar.length() != 0)
      {
        parser.setQuoteChar(mQuoteChar.charAt(0));
      }
 
      // Get the column names
      Iterator colNames = getColNames(parser).iterator();
 
      // Create the structure definition
      attrParent = new StructureDef(name);
 
      // Parse the data to get the attributes
      if (mIsFirstRowNames)
      {
        parser.nextLine();
      }
 
      String[] vals = parser.getLineValues();
      if (vals != null)
      {
        int i = 0;
        while (colNames.hasNext())
        {
          String type = "java.lang.String";
          if (i < vals.length)
          {
            type = checkType(vals[i]);
            ++i;
          }
          AttributeDef attr = 
            new AttributeDef((String) colNames.next(), attrParent, type);
          attrParent.addAttribute(attr);
        }
      }
      else
      {
        while (colNames.hasNext())
        {
          AttributeDef attr = 
            new AttributeDef((String) colNames.next(), 
                             attrParent, "java.lang.String");
          attrParent.addAttribute(attr);
        }
      }
    }
    catch (Exception e)
    {
      throw new AdapterException(e);
    }  
    return attrParent;
 
  }
 
 
  /**
   * Returns the resulting data extracted from the input.
   * @param params parameters passed containig the context information.
   * @return <code>Iterator</code> of <code>Map</code> objects for the result.
   *         If no data found it can return null. The <code>Map</code>
   *         contains the value of attributes as defined in the data structure.
   *         For complex data, <code>Map</code>s can contain other iterator of
   *         <code>Map</code>s as well.
   */
  public Iterator getResult(Map params)
  {
    try
    {
      final CSVParser parser;
      if (mEncStyle == null)
      {
        parser = new CSVParser(mDataStream);
      }
      else
      {
        parser = new CSVParser(mDataStream, mEncStyle);
      }
 
      parser.setSeparators(mDelimiter.toCharArray());
      if (mQuoteChar != null && mQuoteChar.length() != 0)
      {
        parser.setQuoteChar(mQuoteChar.charAt(0));
      }
 
      final List cols = getColNames(parser);
      final boolean bEndOfData = (mIsFirstRowNames) ? !parser.nextLine() : false;
      //return the data iterator
      return new Iterator()
      {
        CSVParser _parser = parser;
        Iterator _colNames = cols.iterator();
        boolean _eof = bEndOfData;
 
        public void remove()
        {
        }
        
        public boolean hasNext()
        {
          return !_eof;
        }
        
        public Object next()
        {
            try
                {
                  if (_eof)
                  {
                    return null;
                  }
 
                  java.util.HashMap map = new java.util.HashMap(5);
 
                  // Create the current row as Map
                  String[] data = _parser.getLineValues();
                  int i = 0;
                  while (_colNames.hasNext())
                  {
                    String val = null;
                    if (i < data.length)
                    {
                      val = data[i];
                    }
 
                    map.put(_colNames.next(), val);
                    i++;
                  }
 
                  // get the next data line.
                  _eof = !_parser.nextLine();
 
                  return map;
            }
              catch (Exception e)
              {
                throw new AdapterException(e);
              }
            }
        
      };
        
    }
    catch (AdapterException ae)
    {
      throw ae;
    }
    catch (Exception e)
    {
      throw new AdapterException(e);
    }
  }
 
 
  //============================================================================
  // Class Helper Methods 
  //============================================================================
 
   /**
    * Attempts to obtain the Java type from the string value.
    * @param data String value whose datatype has to be guessed.
    * @return Java type name.
    */
   private String checkType(String data)
   {
     try
     {
       // We first try to convert the value into a long number.
       // If successful, we will use long; if it throws NumberFormatException,
       // we will attempt to convert it to float. If this too fails, we return
       // string.
       if (data != null)
       {
         try
         {
           // Try to conver the value into an integer number.
           long numTest = Long.parseLong(data);
           return "java.lang.Long"; //NOTRANS
         }
         catch (NumberFormatException nfe)
         {
           // Try to convert the value into float number.
           float numTest = Float.parseFloat(data);
           return "java.lang.Float"; //NOTRANS
         }
       }
       else
       {
         return "java.lang.String"; //NOTRANS
       }
     }
     catch (NumberFormatException nfe)
     {
       // If conversion failed, we assume this is a string.
       return "java.lang.String";
     }
   }
 
 
  /**
   * Gets the column names.
   */
  /**
   * Gets the column names.
   */
  private List getColNames(CSVParser parser)
  {
    try
    {
      if (mColNames == null)
      {
        // Get the first row. If the first row is NOT the column names, we need
        // to generate column names for them.
  
        if (!parser.nextLine())
        {
          // No data found.
          // ToDo: resource
          new Exception("No data");
        }
  
        mColNames = new java.util.ArrayList(10);
  
        String[] cols = parser.getLineValues();
        if (mIsFirstRowNames)
        {
          makeValidColumnNames(cols);
          for (int i = 0; i < cols.length; i++)
          {
            mColNames.add(cols[i]);
          }
        }
        else
        {
          for (int i = 0; i < cols.length; i++)
          {
            String colName = 
              new SimpleStringBuffer(20).append("Column").append(i).toString();
            mColNames.add(colName);
          }
        }
      }
 
      return mColNames;
    }
    catch (Exception e)
    {
      throw new AdapterException(e);
    }
  }
 
  
  /**
    * Make valid column names for all columns in CSV data source.
    *
    * This method applies the following rules to translate the given string
    * to a valid column name which can be accepted by EL:
    * 
    * 1. If the first character of the string is digit,  
    *    prefix the string with '_'.
    * 2. Translate any characters other than letter, digit, or '_'  to '_'. 
    * 
    *
    */
  private String[] makeValidColumnNames(String[] cols) 
  {
    for (int i = 0; i <cols.length; i++)
    { 
       // Trim out leading or ending white spaces
      if (cols[i] != null && cols[i].length() > 0)
      {
        cols[i] = cols[i].trim();
      }
       
      if (cols[i] == null || cols[i].length() == 0)
      {
         // Default as "column1", "column2", ... if column name null 
        cols[i] = new SimpleStringBuffer("column").append(i+1).toString();
      }
      else
      {
        // Check special characters
        try 
        {
          cols[i] = Utility.normalizeString(cols[i]);
        }
        catch (Exception e)
        {
           // On error, simply default to "columnX". 
          cols[i] = new SimpleStringBuffer("column").append(i+1).toString();  
        }
      }
    }
    return cols;
  }
   
}

20.11.3 CSVParser

Example 20-39 shows the contents of the CSVParser class.

Example 20-39 CSVParser

package oracle.adfinternal.model.adapter.sample;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;

import oracle.adf.model.utils.SimpleStringBuffer;

public final class CSVParser 
{
  /////////////////////////////// Constants ////////////////////////////////////
 
  /** UTF8 encoding, used for hadling data in different languages. */
  public static final String UTF8_ENCODING = "UTF8";
 
  /** Quote character */
  private static char CHAR_QUOTE = '"';
 
  /** Comma (seperator) character */
  private static char CHAR_COMMA = ',';
 
 
  /////////////////////////////// Class Variables //////////////////////////////
 
  /**
   * CSV stream reader
   */
  private LineNumberReader mReader;
 
  /** Buffer to store one line of values.  */
  private ArrayList mValueArrayList = new ArrayList(); 
 
  /** Buffer to store one string value.  */
  private SimpleStringBuffer mValueBuffer = new SimpleStringBuffer(256);
 
  /** Current processed line.  */
  private String mLine = null;
 
  /** Current character position in the current line.  */
  private int mLinePosition = -1;
 
  /** Length of current line. */
  private int mLineLength = 0;
 
  /** If last character is comma. */
  private boolean mLastCharIsComma = false;
  
  /** Value separator character set. The separator can be one of these values.*/
  private char[] mSepCharSet = {CHAR_COMMA};
  
  /** Quote character. */
  private char mQuoteChar = CHAR_QUOTE;
 
 
  ////////////////////////////// Constructors //////////////////////////////////
 
  /**
   * Constructor
   *
   * @param pInputStream CSV input stream
   * @throws Exception any error occurred
   */
  public CSVParser(InputStream pInputStream) throws Exception
  {
    // If no encoding is passed in, use "UTF-8" encoding
    this(pInputStream, UTF8_ENCODING);
  }
 
  /**
   * Constructor
   *
   * @param pInputStream CSV input stream
   * @param pEnc character encoding
   * @throws Exception any error occurred
   */
  public CSVParser(InputStream pInputStream, String pEnc) throws Exception
  {
    if (pInputStream == null)
    {
      throw new Exception("Null Input Stream."); //TODO: Resource
    }
    
    mReader = new LineNumberReader(new InputStreamReader(pInputStream, pEnc));
  }
 
  ///////////////////////////// Public Methods /////////////////////////////////
 
  /**
   * Sets the separator characters as a list of possible separators for the 
   * data. CSV data may have more than one separators. By default this parser
   * considers comma (,) as the data separator.
   * @param seps  Array of separator charactors.
   */
  public void setSeparators(char[] seps)
  {
    if ((seps != null) && (seps.length > 0))
    {
      mSepCharSet = seps;
    }
  }
  
  /**
   * Sets the quote character.
   * @param ch Quote character.
   */
  public void setQuoteChar(char ch)
  {
    mQuoteChar = ch;
  }
 
  /**
   * Moves to the next line of the data.
   * @return returns false if the end of data reached.
   * @throws Exception any error occurred
   */
  public boolean nextLine() throws Exception 
  {
    setLine(mReader.readLine());
    if (mLine == null)
    {
      // End of file
      mValueArrayList.clear();
      return false;
    }
 
    parseLine();
 
    return true;
  }
 
  /**
   * Gets values of next line.
   * @return next line elements from input stream. If end of data reached, 
   *         it returns null.
   * @throws Exception any error occurred
   */
  public String[] getLineValues() throws Exception 
  {
    if (mValueArrayList.size() > 0) 
    {
      String[] ret = new String[mValueArrayList.size()];
      return (String[]) mValueArrayList.toArray(ret);
    }
    
    return null;
  }
 
 
 
  //////////////////////////// Class Helpers ///////////////////////////////////
 
  /**
   * Checks if the character is a valid separator.
   */
  private boolean isSeparator(char ch)
  {
    for (int i = 0; i < mSepCharSet.length; i++)
    {
      if (ch == mSepCharSet[i]) 
      {
        return true;
      }
    }
    
    return false;
  }
 
  /**
   * Tests if end of line has reached.
   * @return true if end of line.
   */
  public boolean isEndOfLine() 
  {
    // If last char is comma, must return at least one more value
    return (mLinePosition >= mLineLength) && (!mLastCharIsComma);
  }
 
 
  /**
   * Sets current line to be processed
   *
   * @param line the line to be processed
   */
  private void setLine(String line) 
  {
    mLine = line;
   
    if (line != null)
    {
      mLineLength = line.length();
      mLinePosition = 0;
    }
 
  }
 
  /**
   * If next character is quote character
   *
   * @return true if next character is quote
   */
  private boolean isNextCharQuote() 
  {    
    if ((mLinePosition + 1) >= mLineLength) 
    {
      // no more char in the line
      return false; 
    } 
    else 
    {
      char ch = mLine.charAt(mLinePosition + 1);
      if (ch == mQuoteChar) 
      {
        return true;
      } 
      else 
      {
        return false;
      }
    }
  }
 
  /**
   * Parse one line.
   *
   * @return values of the line
   * @throws Exception any error occurred
   */
  private void parseLine() throws Exception 
  {
    mValueArrayList.clear();
        
    String[] values = null;
    String value = null;
 
    while (!isEndOfLine())
    {
      value = getNextValue();
      mValueArrayList.add(value);
    }    
  }
 
  /**
   * Gets next value from current line.
   * @return next data value.
   */
  private String getNextValue() throws Exception 
  {  
    mLastCharIsComma = false;
 
    // Clean up value buffer first 
    if (mValueBuffer.length() > 0) 
    {
      mValueBuffer.setLength(0);
    }
 
    boolean insideQuote = false;
    boolean firstChar = true;    
    boolean endValue = false;
 
    // Scan char by char
    while ((mLinePosition < mLineLength) && !endValue) 
    {
      boolean copyChar = true;    
      char ch = mLine.charAt(mLinePosition);
      
      // If first char
      if (firstChar) 
      {
        // Only check quote at first char
        if (ch == mQuoteChar) 
        {
          insideQuote = true;
          copyChar = false;  
        }
        // Also need to check comma at first char
        else if (isSeparator(ch)) 
        {
          copyChar = false;
          endValue = true;
          mLastCharIsComma = true;
        }
        
        firstChar = false;
      } 
      // Not first char but inside quote
      else if (insideQuote) 
      {
        // Check end quote 
        if (ch == mQuoteChar) 
        {        
          copyChar = false;
          // Two sucesstive quote chars inside quote means quote char itself
          if (isNextCharQuote()) 
          {
            mLinePosition++;
          } 
          // Otherwise it is ending quote
          else 
          {
            insideQuote= false;
          }
        }
      }
      // Not first char and outside quote
      else 
      {
        // Check comma 
        if (isSeparator(ch)) 
        {
          copyChar = false;
          endValue = true;
          mLastCharIsComma = true;
        }        
      }
 
      if (copyChar) 
      {
        mValueBuffer.append(ch);
      }
 
      mLinePosition++;
    }
 
    if (mValueBuffer.length() > 0) 
    {
      return mValueBuffer.toString();
    } 
    else 
    {
      return null;
    }
  }
 
}