com.ricebridge.csvman
Class CustomLineListener

java.lang.Object
  extended bycom.ricebridge.csvman.LineListenerSupportImpl
      extended bycom.ricebridge.csvman.CustomLineListener
All Implemented Interfaces:
LineListener
Direct Known Subclasses:
BadLineTest.NullLineListener, BasicCsvLoader.LoaderLineListener, BasicLineListener, BeanLineListener, CsvHandlerTest.TestLineListener, EdgeCasesTest.NumFieldLineListener, HeadersListenerSupport, LoadLineListenerTest.SimpleLineListener, MultiLineListener, ReallyBadLines.NullLineListener, Snippets.MyLineListener, StreamingTest.MeasureStreamLineListener

public abstract class CustomLineListener
extends LineListenerSupportImpl

Extend this class to create your own LineListener.

You can create custom data from CSV files by overriding and implementing the methods in this class. The basic idea is that you implement the handleLineImpl method which is called each time a line of CSV data is read from the CSV file. You can then use this data in whatever way you need.

Here's a very simple example. This LineListener just prints out any data that is loaded. You might use this for debugging or logging.


    import com.ricebridge.csvman.*;
 
    public class PrintingLineListener extends CustomLineListener {
      protected BadLine handleLineImpl( String[] pLine, int pNumFields, 
                                        long pLineNumber, String pOriginalLine ) 
      {
        for( int field = 0; field < pNumFields; field++ ) {
          System.out.print( pLine[field] + ", " );
        }
        System.out.println();
        return null;
      }
    }
  

You can see from this code that instead of implementing the public LineListener.handleLine method directly, you implement the protected handleLineImpl method. This insulates you from API changes and also provides an extra layer of error checking. And CustomLineListener provides default implementations for most of the methods of LineListener, so handleLineImpl is the only one you need to worry about.

The handleLineImpl method itself provides you with a lot of information about the line of CSV data that was just loaded. You get a String[] array (pLine), containing all the data. In order to reduce errors, this array is always the same size. For lines that are missing data fields, CSV Manager will add in empty String elements at the end of the array.

Of course, you may want to know exactly how many fields there were in the line, so that's what pNumFields tell you. When some data fields are missing, pNumFields with then be less than pLine.length.

CSV Manager also gives you the line number (pLineNumber), and the text of the original line (pOriginalLine), as it appears in the CSV file. This is so that you can produce nice error messages and logs.

Here's how you actually use this class:


    CsvManager           csvman = new CsvManager();
    PrintingLineListener pln    = new PrintingLineListener();
    csvManager.load( "input-file.csv", pln );
  

You just create a new instance of PrintingLineListener, and then pass it to CsvManager.

When using custom LineListeners, the only thing that is different from the normal load methods is that there is no return value. All the data is passed to the custom LineListener instead. You can still access this data by calling get methods on the custom LineListener. Of course, you'll have to write those get methods yourself.

For more information about implementing your own LineListeners, see the LineListener interface documentation. Also, take a look at the other methods you can implement:

Note: You can implement the LineListener interface directly if you need to. The danger is that your implementation may not remain compatible with future versions of CSV Manager. And you lose all the extra error-handling. So it's better to stick with extending CustomLineListener if you can.

Finally, if you want to save data with custom processing, see LineProvider.

The Source Code of this Java class is available under a BSD-style license.

Since:
1.2.1
See Also:
LineListener, LineListenerSupportImpl, BasicLineListener, CsvManager, CsvManagerException

Constructor Summary
CustomLineListener()
           
 
Method Summary
protected  void endProcessImpl()
          Implement this method to receive notification that the loading of CSV data has ended.
protected  void handleBadLineImpl(BadLine pBadLine)
          Implement this method to be notified when badly formatted data is encountered.
protected abstract  BadLine handleLineImpl(String[] pLine, int pNumFields, long pLineNumber, String pOriginalLine)
          Implement this method to receive each data line as it is loaded.
protected  void setCsvSpecImpl(CsvSpec pCsvSpec)
          Set the current CsvSpec used for loading CSV files.
protected  void setLineSpecImpl(LineSpec pLineSpec)
          Set the current LineSpec used for interpreting CSV data fields.
protected  void startProcessImpl()
          Implement this method to receive notification that the loading of CSV data is about to start.
 
Methods inherited from class com.ricebridge.csvman.LineListenerSupportImpl
endProcess, handleBadLine, handleLine, setCsvSpec, setLineSpec, startProcess
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

CustomLineListener

public CustomLineListener()
Method Detail

setCsvSpecImpl

protected void setCsvSpecImpl(CsvSpec pCsvSpec)
                       throws Exception
Set the current CsvSpec used for loading CSV files.

You can implement this method when you extend CustomLineListener, but it is not required.

The CsvSpec controls the CSV loading and saving process. It contains a number of settings such as the data field and line separators. You can also set your own custom settings using the CsvSpec.setProperty method. You can then access these settings inside your own LineListener using the CsvSpec object passed into this method.

This method is called before setLineSpecImpl is called.

Specified by:
setCsvSpecImpl in class LineListenerSupportImpl
Parameters:
pCsvSpec - CsvSpec object
Throws:
Exception
See Also:
CsvSpec, setLineSpecImpl

setLineSpecImpl

protected void setLineSpecImpl(LineSpec pLineSpec)
                        throws Exception
Set the current LineSpec used for interpreting CSV data fields.

You can implement this method when you extend CustomLineListener, but it is not required.

The LineSpec controls the conversion of individual CSV data fields into Java objects. Whereas CsvSpec controls the entire process, LineSpec only applies to each data field. In the current version of CSV Manager (1.2), LineSpec is used to load and save Java Beans, by providing the get and set method names for each data field. See BeanLineListener for more details.

You can subclass LineSpec to add your own data field specific information for your own custom LineListeners. You can then access these settings inside your own LineListener using the LineSpec object passed into this method.

This method is called after setCsvSpecImpl is called.

Specified by:
setLineSpecImpl in class LineListenerSupportImpl
Parameters:
pLineSpec - LineSpec object
Throws:
Exception
See Also:
LineSpec, setCsvSpecImpl, BeanLineListener

startProcessImpl

protected void startProcessImpl()
                         throws Exception
Implement this method to receive notification that the loading of CSV data is about to start.

You can implement this method when you extend CustomLineListener, but it is not required.

You can use this method to initialise any resource you need to process the CSV data. For example you can open a database connection to store the data as it is loaded.

This method is called after setCsvSpecImpl and setLineSpecImpl.

Specified by:
startProcessImpl in class LineListenerSupportImpl
Throws:
Exception
See Also:
endProcessImpl

handleLineImpl

protected abstract BadLine handleLineImpl(String[] pLine,
                                          int pNumFields,
                                          long pLineNumber,
                                          String pOriginalLine)
                                   throws Exception
Implement this method to receive each data line as it is loaded.

This method must be implemented when you extend CustomLineListener.

This method is where you will do the main work of processing the CSV data. As you get each line in, you can decide what to do with the data. The parameters of this method provide you with a lot of information about the CSV data line that you can use in your application.

First, the pLine parameter contains the actual data as a String[] array. This array is guaranteed not to contain any null Strings. If empty data fields are found in the CSV line (for example a,,b => ['a','','b']) then empty strings are placed in the array. This means that you can avoid nasty NullPointerExceptions.

Equally nasty are ArrayIndexOutOfBoundsExceptions. CSV Manager helps you avoid them by making sure that the pLine array is always long enough. By "long enough", we mean either as long as the longest line found so far, or as long as is specified by the CsvSpec.setNumFields method.

Of course, this means that in the case where there are fewer data fields than normal, you also need to know exactly how many data fields there actually were, as pLine.length will not tell you this. This is what the pNumFields parameter is for. So if you need to check exactly how many data fields a line had, use pNumFields.

To help with error reporting, CSV Manager also provides the line number of the current data line, passed in via pLineNumber. This includes any bad lines found. pLineNumber is a long, just in case you ever have a really, really big CSV file.

Finally, you also get the text of the original line (pOriginalLine), so you can create user-friendly error messages for your users. And it makes debugging easier.

Error Handling: What happens when the data in the CSV file is incorrect in some way? For example, it might not be valid for your database. In this case, even though the syntax of the CSV is correct, there is a semantic error. To capture this case, we use the following contract: if all is well, return a null from handleBadLineImpl. If there is an error with the data, return a BadLine object describing the error.

This provides consistent handling of errors. At any time you can of course just throw an Exception, but if you use a BadLine instead then you get proper summary statistics, nice error reporting, and faster performance as you avoid the overhead of Exception throwing and catching.

But if you have a error that is not data related, (if for example, your database goes down), then it is better to throw an Exception.

Specified by:
handleLineImpl in class LineListenerSupportImpl
Parameters:
pLine - String values of data fields in line
pNumFields - Number of data fields actually found on the current line
pLineNumber - Count of lines processed so far.
pOriginalLine - Text of original data line from data source
Returns:
null if line is OK, BadLine object if line was bad in some way
Throws:
Exception
See Also:
LineListener.handleLine, BadLine, handleBadLineImpl

handleBadLineImpl

protected void handleBadLineImpl(BadLine pBadLine)
                          throws Exception
Implement this method to be notified when badly formatted data is encountered.

You can implement this method when you extend CustomLineListener, but it is not required.

When a syntax error is encountered in the CSV file you are loading, a BadLine object is created by CSV Manager to describe the problem, and then it is passed to your custom LineListener for further handling. You can decide how to log the error or what other actions to take based on your error handling policy.

What happens after handleBadLineImpl is called? It depends on the CsvSpec.setIgnoreBadLines setting. If this setting is true, then loading will continue with the rest of the CSV file. If it is false, then loading will halt and a CsvManagerException will be thrown for the code that called the CsvManager.load method to catch.

Note: BadLines returned by handleLineImpl are not passed to this method. Since you already know about them in handeLineImpl, there would not be much point.

Specified by:
handleBadLineImpl in class LineListenerSupportImpl
Parameters:
pBadLine - BadLine object describing the error
Throws:
Exception
See Also:
LineListener.handleBadLine, handleLineImpl

endProcessImpl

protected void endProcessImpl()
                       throws Exception
Implement this method to receive notification that the loading of CSV data has ended.

You can implement this method when you extend CustomLineListener, but it is not required.

You can use this method to close any open resources that were used to handle the CSV data. For example you can close any open database connections.

This method is called last, after all handleLineImpl and handleBadLineImpl calls have been made.

Specified by:
endProcessImpl in class LineListenerSupportImpl
Throws:
Exception
See Also:
startProcessImpl


Copyright © 2003-2006 Ricebridge