Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)
B25947-01
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

31.11 Contents of Supporting Files

This section shows the contents of the following files:

31.11.1 sampleDC.xsd

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

Example 31-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>

31.11.2 CSVHandler Class

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

Example 31-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;
  }
   
}

31.11.3 CSVParser

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

Example 31-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;
    }
  }
 
}