/* Copyright (c) 2006 Ricebridge. All Rights Reserved. * * This file is available under the terms and conditions of the * Ricebridge "Open Source API" policy; Ricebridge grants use of this * copyrighted work under the terms of a BSD-style license only. See * http://www.opensource.org/licenses/bsd-license.php for more * information. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Ricebridge nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.ricebridge.csvman; import org.jostraca.util.Internal; /** Extend this class to create your own {@link LineProvider}. * <p>You can export your data to CSV by overriding and implementing the methods in this class. * You can do this when your source data must be accessed in a specific way and you need to control * the exact data that is output. The basic idea is that you implement the {@link #hasNextLineImpl} and * {@link #nextLineImpl nextLineImpl} methods. These are called each time a line of CSV data is to be saved. * You then return a <code>String[]</code> array containing your own data that <i>CSV Manager</i> * will output as the fields of the CSV data line.</p> * <p>Here's a very simple example. This <code>LineProvider</code> just creates a set of numbers to use * as a data set. In your own projects, you'll probably source the data from a database or XML file, or other * data storage system.</p> * <pre><!--code-[--> * public static class NumbersLineProvider extends CustomLineProvider { * private int line = 0; * * protected boolean hasNextLineImpl() throws Exception { * return line < 11; * } * * protected String[] nextLineImpl() throws Exception { * line++; * return new String[] {""+line, ""+(10*line) }; * } * } * <!--code-]--></pre> * <p>You can see from this code that instead of implementing the public * {@link LineProvider#hasNextLine LineProvider.hasNextLine} and * {@link LineProvider#nextLine LineProvider.nextLine} * methods directly, you implement the protected {@link #hasNextLineImpl hasNextLineImpl} * and {@link #nextLineImpl nextLineImpl} methods. This insulates you from * API changes and also provides an extra layer of error checking. * Also, <code>CustomLineProvider</code> provides default * implementations for most of the methods of <code>LineProvider</code>, * so <code>hasNextLineImpl</code> and <code>nextLineImpl</code> are the only ones * you need to worry about.</p> * <p>Here's how you actually use this class:</p> * <pre><!--code-[--> * CsvManager csvman = new CsvManager(); * NumbersLineProvider nlp = new NumbersLineProvider(); * csvManager.save( "output-file.csv", nlp ); * <!--code-]--></pre> * <p>You just create a new instance of <code>NumbersLineProvider</code>, * and then pass it to {@link CsvManager}.</p> * <p>When using custom <code>LineProviders</code>, the only thing that is * different from the normal <code>save</code> methods is that you do not pass in the data to the <code>save</code> method. * You have to initialise your {@link LineProvider} with the data first. * <p>For more information about implementing your own <code>LineProviders</code>, * see the {@link LineProvider} interface documentation. Also, take a look at the other methods * you can implement:</p> * <ul><li>{@link #setCsvSpecImpl setCsvSpecImpl}</li> * <li>{@link #setLineSpecImpl setLineSpecImpl}</li> * <li>{@link #startProcessImpl startProcessImpl}</li> * <li>{@link #endProcessImpl endProcessImpl}</li></ul> * <p>Note: You can implement the {@link LineProvider} interface directly if you need to. * The danger is that your implementation may not remain compatible with future versions of * <i>CSV Manager</i>. And you lose all the extra error-handling. * So it's better to stick with extending <code>CustomLineProvider</code> if you can.</p> * <p>Finally, if you want to load data with custom processing, see {@link LineListener}.</p> * <p>The <b><a href="CustomLineProvider.java.html">Source Code</a></b> of this Java class * is available under a <a href="http://www.opensource.org/licenses/bsd-license.php">BSD-style license</a>.</p> * * @since 1.2.1 * @see LineProvider * @see LineProviderSupportImpl * @see BasicLineProvider * @see CsvManager * @see CsvManagerException */ public abstract class CustomLineProvider extends LineProviderSupportImpl { // protected methods /** Set the current {@link CsvSpec} used for saving CSV files. * <p>You can implement this method when you extend <code>CustomLineProvider</code>, * but it is not required.</p> * <p>The <code>CsvSpec</code> 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 {@link CsvSpec#setProperty CsvSpec.setProperty} method. * You can then access these settings inside your own {@link LineProvider} * using the <code>CsvSpec</code> object passed into this method.</p> * <p>This method is called before {@link #setLineSpecImpl setLineSpecImpl} is called.</p> * @param pCsvSpec {@link CsvSpec} object * @see CsvSpec * @see #setLineSpecImpl setLineSpecImpl */ protected void setCsvSpecImpl( CsvSpec pCsvSpec ) throws Exception { // default does nothing } /** Set the current {@link LineSpec} used for interpreting CSV data fields. * <p>You can implement this method when you extend <code>CustomLineProvider</code>, * but it is not required.</p> * <p>The <code>LineSpec</code> controls the conversion of internal data into individual CSV data fields. * Whereas {@link CsvSpec} controls the entire process, <code>LineSpec</code> only applies to each data field. * In the current version of <i>CSV Manager</i> (1.2), <code>LineSpec</code> is used to load and save Java Beans, * by providing the <code>get</code> and <code>set</code> method names for each data field. * See {@link BeanLineProvider} for more details.</p> * <p>You can subclass <code>LineSpec</code> to add your own * data field specific information for your own custom {@link LineProvider LineProviders}. * You can then access these settings inside your own <code>LineProvider</code> * using the <code>LineSpec</code> object passed into this method.</p> * <p>This method is called after {@link #setCsvSpecImpl setCsvSpecImpl} is called.</p> * @param pLineSpec {@link LineSpec} object * @see LineSpec * @see #setCsvSpecImpl setCsvSpecImpl * @see BeanLineProvider */ protected void setLineSpecImpl( LineSpec pLineSpec ) throws Exception { // default does nothing } /** Implement this method to receive notification that the saving of CSV data is about to start. * <p>You can implement this method when you extend <code>CustomLineProvider</code>, * but it is not required.</p> * <p>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 retrieve the data as it is saved.</p> * <p>This method is called <i>after</i> {@link #setCsvSpecImpl setCsvSpecImpl} and * {@link #setLineSpecImpl setLineSpecImpl}. * @see #endProcessImpl endProcessImpl */ protected void startProcessImpl() throws Exception { // empty implementation } /** Implement this method to let <i>CSV Manager</i> know that there is another line of data to save. * <p>This method must be implemented when you extend <code>CustomLineProvider</code>.</p> * <p>Return <code>true</code> from this method so long as you have more data lines to save.</p> * @see LineProvider#hasNextLine LineProvider.hasNextLine * @see #nextLineImpl nextLineImpl */ protected abstract boolean hasNextLineImpl() throws Exception; /** Implement this method to supply each data line as it is saved. * <p>This method must be implemented when you extend <code>CustomLineProvider</code>.</p> * <p>This method is where you will do the main work of providing the CSV data. Each time this * method is called you will need to provide a new line of CSV data as a <code>String[]</code> array.</p> * <p><b>Error Handling:</b> What happens when you cannot provide the line data for some reason? * For example your database connection may fail. In this case, all you have to do is throw an * <code>Exception</code> to let <i>CSV Manager</i> know about the problem. But note that if the * {@link CsvSpec#setIgnoreBadLines CsvSpec.setIgnoreBadLines} setting is <code>true</code>, then * <i>CSV Manager</i> will not stop asking you for more data lines until you also return * <code>false</code> from {@link #hasNextLineImpl}.</p> * @see LineProvider#nextLine LineProvider.nextLine * @see #hasNextLineImpl hasNextLineImpl */ protected abstract String[] nextLineImpl() throws Exception; /** Implement this method to receive notification that the saving of CSV data has ended. * <p>You can implement this method when you extend <code>CustomLineProvider</code>, * but it is not required.</p> * <p>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.</p> * <p>This method is called <i>last</i>, after all {@link #hasNextLineImpl hasNextLineImpl} * and {@link #nextLineImpl nextLineImpl} calls have been made.</p> * @see #startProcessImpl startProcessImpl */ protected void endProcessImpl() throws Exception { // empty implementation } }