/* Copyright (c) 2005 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.xmlman;


import com.ricebridge.xmlman.in.RecordTrigger;

import java.util.*;


/** Implement this interface by extending {@link RecordListenerSupport} to receive each data record as it is loaded.
 *    <p>This callback interface allows you to handle data records as they are loaded. This is the
 *  fastest way to load data and also means that you can avoid storing all of the data in memory at once.
 *  The most common use-case is database loading, where individual XML data records are converted to SQL statements
 *  that are executed immediately. 
 *  See the <a href="http://www.ricebridge/com/products/xmlman/doc/examples/database/readme.htm">database example</a> 
 *  for more information.</p>
 *    <p>Once you have created your own <code>RecordListener</code>, you can use it by calling the <code>load</code> methods
 *  of {@link XmlManager} that accept a <code>RecordListener</code> as an argument, for example: 
 *  {@link XmlManager#load(File,RecordSpec,RecordListener)}. <code>XmlManager</code> than starts to load the data and calls the
 *  methods of the <code>RecordListener</code> in a defined sequence:</p>
 *    <ol><li>{@link #setXmlSpec setXmlSpec}</li>
 *        <li>{@link #setFieldNames setFieldNames}</li>
 *        <li>{@link #startProcess startProcess}</li>
 *        <li>{@link #handleRecord handleRecord}</li>
 *        <li>{@link #endProcess endProcess}</li></ol>
 *    <p>The {@link #handleRecord handleRecord} method is called once for each data record in the source XML.</p>
 *    <p>When writing your own <code>RecordListener</code>, the easiest way to get started is to review the source code for the
 *  existing <code>RecordListeners</code> used by <code>XmlManager</code>. <code>XmlManager</code> uses <code>RecordListeners</code> 
 *  internally for all data loading operations.
 *  The {@link StringArrayRecordListener} is a very simple example and a good place to start.</p>
 *    <p><b>Error Handling</b><br />
 *  The <code>handleRecord</code> method can return a <code>BadRecord</code> object that describes any semantically incorrect
 *  data records. This allows you to perform validation against the input data. You can also return a <code>BadRecord</code> when database
 *  access fails, or some other problem occurs. When everything is OK, there is no need to return a <code>BadRecord</code>, 
 *  simply return <code>null</code> from the <code>handleRecord</code> method. You can also allow <code>Exceptions</code> to pass up
 *  to the support class, without handling them yourself. In this case <code>XmlManager</code> will handle them for you, either
 *  halting the load operation, or creating a <code>BadRecord</code> and storing it, depending on the value of the
 *  {@link XmlSpec#setIgnoreBadRecords} setting.</p>
 *    <p><b>Important</b><br />
 *  In order to ensure the greatest compatibility with future releases and to take advantage of additional error handling
 *  functionality, please implement your <code>RecordListener</code> by extending the abstract {@link RecordListenerSupport} class.
 *  This class ensures that all data you receive is well-formed (no <code>nulls</code>), and also creates standard
 *  exceptions when problems do occur.</p>
 *    <p>The <b><a href="RecordListener.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>
 */
public interface RecordListener {

  // public methods

  /** Set the current {@link XmlSpec} settings.
   *   <p>You can implement this method to get the values of the current settings,
   *  and use them to modify your data handling. For example, {@link TableModelRecordListener}
   *  uses the custom property <code>TableModel.editable</code> to make any 
   *  {@link javax.swing.table.TableModel TableModels} that it returns editable. You can easily use your own
   *  custom properties by calling the {@link XmlSpec#setProperty XmlSpec.setProperty} method.</p>
   *  @param pXmlSpec <code>XmlSpec</code> object
   */
  public void setXmlSpec( XmlSpec pXmlSpec );


  /** Set the field names of the primary {@link RecordSpec}. 
   *    <p>You can implement this method to get the list of field names that
   *  apply to the data. This is useful when you need to identify the data fields
   *  for additional functionality. For example, the {@link BeanRecordListener} class uses the field
   *  names to determine the correct <i>set</i> methods to call.</p>
   *    <p>Note: if no field names are provided in the primary <code>RecordSpec</code>, then this method is <i>not</i> called.</p>
   *    <p>When you extend {@link RecordListenerSupport} to implement the <code>RecordListener</code> interface,
   *  you gain access to the protected instance variable <code>iFieldNames</code>, which will contain any
   *  field names if provided, or otherwise be empty. You can override the 
   *  {@link RecordListenerSupport#setFieldNamesImpl} method to handle the field names in a different manner.</p>
   *    <p>If more than one <code>RecordSpec</code> was specified, then only the field names
   *  from the primary <code>RecordSpec</code> are used. See the {@link RecordSpec} documentation for details.
   *  @param pFieldNames <code>String[]</code> of field names
   */
  public void setFieldNames( String[] pFieldNames );


  /** Indicate the start of the loading process.
   *    <p>This method is called just before loading from the XML source document begins.
   *  You can initialise any database connections or other resources that you need to use to process the data.</p>
   */
  public void startProcess();


  /** Handle each data record as it is parsed from the XML source document.
   *    <p>This is the most important method of the <code>RecordListener</code> interface. This is where you
   *  actually receive your data. The data is provided as a <code>String[]</code> array of field values.
   *  You will always get a <code>String[]</code> array that is equal in length to the number of field paths
   *  specified in the {@link RecordSpec}. Any empty fields are set to empty strings.</p>
   *    <p>The <code>pRecordNumber</code> argument contains a count of the number of records parsed so far.
   *  It starts at <code>1</code>, not <code>0</code>. The count is separate for each <code>RecordSpec</code>, so if you
   *  are using multiple <code>RecordSpecs</code>, you will need to provide your own global counter that is
   *  shared between all the <code>RecordListeners</code> that you are using.</p>
   *  @param pRecord       record data as a <code>String[]</code> 
   *  @param pRecordNumber current count of records
   *  @return {@link BadRecord} if there was a problem, <code>null</code> otherwise
   */
  public BadRecord handleRecord( String[] pRecord, long pRecordNumber );


  /** Indicate the end of the loading process.
   *    <p>This method is called once the XML source document has been fully parsed. You can use it to
   *  release any resources such as database connections that you were using to handle the data.</p>
   *    <p>Note: this method <i>will</i> be called even if other errors occur, 
   *  so long as the call to {@link #startProcess} returned normally.
   *  If your <code>startProcess</code> method does critical things, make sure that it fails cleanly.</p>
   */
  public void endProcess();

}


Syntax Highlighting created using the com.Ostermiller.Syntax package.
Thursday, February 23 2006 at 16:47