|
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3) B25386-01 |
|
![]() Previous |
![]() Next |
This section shows the contents of the following files:
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>
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;
}
}
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;
}
}
}