/* 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 org.jostraca.util.Internal;

import java.util.*;


/** Describes a bad data record that failed for some reason.
 *    <p>Data records fail when the {@link RecordListener} processing them returns a <code>BadRecord</code>
 *  or throws an <code>Exception</code>.
 *  Either the actual data in the data fields was incorrect in some way, or the processing of the data record
 *  in a custom <code>RecordListener</code> failed due to database errors or similar problems.</p>
 *    <p>Since XML does not allow recovery from syntax errors, a <code>BadRecord</code> does not describe an XML syntax error,
 *  and no <code>BadRecord</code> object is created when an XML syntax error occurs. Instead,
 *  an {@link XmlManagerException} is always thrown, and processing halts. Note that the {@link RecordListener#endProcess endProcess}
 *  methods of any <code>RecordListeners</code> or <code>RecordProviders</code> 
 *  are still called when this happens, so that you can exit cleanly.</p>
 *    <p>When a {@link RecordListener} encounters a problem with a data record, it can choose to return a
 *  <code>BadRecord</code> object to <i>XML Manager</i> from the {@link RecordListener#handleRecord handleRecord} method. 
 *  This <code>BadRecord</code> is stored for later examination
 *  and you can access it using the {@link XmlManager#getBadRecords} method. Normally, only one <code>BadRecord</code> is available,
 *  as the default value for the setting {@link XmlSpec#setIgnoreBadRecords XmlSpec.setIgnoreBadRecords} is <code>false</code>.
 *  If you set this setting to <code>true</code>, then processing will continue despite errors in 
 *  {@link RecordListener RecordListeners}, and you can then examine all <code>BadRecords</code> that occurred 
 *  using the <code>getBadRecords</code> method.</p>
 *    <p>When an error occurs in a custom {@link RecordListener} that you have written, you have two options;
 *  1. you can create a <code>BadRecord</code> object yourself, with all the details you consider relevant, and return it, 
 *  or 2. you can just throw an <code>Exception</code>, and let XML Manager create a default BadRecord for you.
 *  When option for option 1, you would normally create a BadRecord of {@link #SEMANTIC} type, using the
 *  convenience constructor {@link #BadRecord(long,String[],Exception)} 
 *  (The <code>pRecordNumber</code> and <code>pRecord</code> parameters can be obtained from the
 *  arguments to the <code>handleRecord</code> method).
 *  For option 2, it is much easier (and recommended) to use the support classes such as {@link RecordListenerSupport}, as these
 *  handle checked <code>Exceptions</code> automatically.</p>
 *    <p>You can also subclass <code>BadRecord</code> to provide additional functionality for your own applications.</p> 
 *    <p>The <b><a href="BadRecord.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 class BadRecord {

  // public static

  /** Indicate that the bad record has an unknown origin. */
  public static final int UNKNOWN = 0;

  /** Indicate that the bad record was returned by the {@link RecordListener} (usually in response to invalid data). */
  public static final int SEMANTIC = 1;

  /** Indicate that the bad record occurred because an <code>Exception</code> was thrown in the {@link RecordListener}. */ 
  public static final int UNEXPECTED = 2;


  
  // protected static 

  /** String names for the type of <code>BadRecord</code>. */
  protected static final String[] sTypeNames = new String[] { "UNKNOWN", "SEMANTIC", "UNEXPECTED" };



  // protected instance

  /** An identification tag for the <code>BadRecord</code> origin, usually the record XPath expression, if available. */
  protected String iTag;

  /** The number of the record that caused the error (this number is specific to each {@link RecordSpec}). */
  protected long iRecordNumber;

  /** The data record that caused the error, if available. */
  protected String[] iRecord;

  /** A technical error message. */
  protected String iMessage;

  /** A context object describing the error, usually the <code>Exception</code> that caused it. */
  protected Object iContext;

  /** The type of error that created the BadRecord; {@link #UNKNOWN}, {@link #SEMANTIC}, {@link #UNEXPECTED}. */
  protected int iType;



  // constructors

  /** Create an empty <code>BadRecord</code> with no information content. */
  public BadRecord() {
    this("",0,new String[]{},"",null);
  }


  /** Create a <code>BadRecord</code> based on an Exception. 
   *  @param pRecordNumber number of the record that caused the error (counted per {@link RecordSpec})
   *  @param pRecord       record data (may be partial)
   *  @param pException    Exception that caused the error
   */
  public BadRecord( long pRecordNumber, String[] pRecord, Exception pException ) {
    this( "", pRecordNumber, pRecord, pException.getMessage(), pException );
  }


  /** Create a <code>BadRecord</code> with a specific error message. 
   *  @param pRecordNumber number of the record that caused the error (counted per {@link RecordSpec})
   *  @param pRecord       record data (may be partial)
   *  @param pMessage      technical message describing the error
   */
  public BadRecord( long pRecordNumber, String[] pRecord, String pMessage ) {
    this( "", pRecordNumber, pRecord, pMessage, SEMANTIC );
  }



  /** Create a <code>BadRecord</code> with a specific error message and 
   *    indicate the record XPath using the <code>pTag</code> parameter.  
   *  @param pTag   indentify the origin of the BadRecord, usually the XPath record expression
   *  @param pRecordNumber number of the record that caused the error (counted per {@link RecordSpec})
   *  @param pRecord       record data (may be partial)
   *  @param pMessage      technical message describing the error
   */
  public BadRecord( String pTag, long pRecordNumber, String[] pRecord, String pMessage ) {
    this( pTag, pRecordNumber, pRecord, pMessage, SEMANTIC );
  }


  /** Create a <code>BadRecord</code> with a specific error message and type, 
   *    and indicate the record XPath using the <code>pTag</code> parameter.  
   *  @param pTag   indentify the origin of the BadRecord, usually the XPath record expression
   *  @param pRecordNumber number of the record that caused the error (counted per {@link RecordSpec})
   *  @param pRecord       record data (may be partial)
   *  @param pMessage      technical message describing the error
   *  @param pType         type of <code>BadRecord</code>: {@link #SEMANTIC}, {@link #UNEXPECTED}, {@link #UNKNOWN}
   */
  public BadRecord( String pTag, long pRecordNumber, String[] pRecord, String pMessage, int pType ) {
    iTag   = Internal.null_arg( pTag );
    iRecordNumber = pRecordNumber;
    iRecord       = (String[]) Internal.null_array( pRecord );
    iMessage      = Internal.null_arg( pMessage );
    iType         = pType;
  }


  /** Create a <code>BadRecord</code> with a specific error message and context, and 
   *    indicate the record XPath using the <code>pTag</code> parameter.  
   *  @param pTag   indentify the origin of the BadRecord, usually the XPath record expression
   *  @param pRecordNumber number of the record that caused the error (counted per {@link RecordSpec})
   *  @param pRecord       record data (may be partial)
   *  @param pMessage      technical message describing the error
   *  @param pContext      context of the error, usually an Exception, can be null   
   */
  public BadRecord( String pTag, long pRecordNumber, String[] pRecord, String pMessage, Object pContext ) {
    this( pTag, pRecordNumber, pRecord, pMessage, pContext, SEMANTIC );
  }


  /** Create a fully described <code>BadRecord</code> object.
   *  @param pTag   indentify the origin of the BadRecord, usually the XPath record expression
   *  @param pRecordNumber number of the record that caused the error (counted per {@link RecordSpec})
   *  @param pRecord       record data (may be partial)
   *  @param pMessage      technical message describing the error
   *  @param pContext      context of the error, usually an Exception, can be null
   *  @param pType         type of <code>BadRecord</code>: {@link #SEMANTIC}, {@link #UNEXPECTED}, {@link #UNKNOWN}
   */
  public BadRecord( String pTag, long pRecordNumber, String[] pRecord, String pMessage, Object pContext, int pType ) {
    this( pTag, pRecordNumber, pRecord, pMessage, pType );
    iContext = pContext;
  }



  // public methods

  /** Get the origin identification tag, usually the record XPath expression. */ 
  public String getTag() {
    return iTag;
  }


  /** Get the record number of the failed record. 
   *    <p>The record number is a counter specific to each {@link RecordSpec}.
   *  If you are using more than one <code>RecordSpec</code> and you need a global counter, you will need to implement one in 
   *  a custom {@link RecordListener}.</p>
   */
  public long getRecordNumber() {
    return iRecordNumber;
  }


  /** Get the record data fields of the record that failed. 
   *    <p>Note: this <code>String[]</code> array may only contain partial data and
   *  may also contain <code>nulls</code>.</p>
   */
  public String[] getRecord() {
    return iRecord;
  }


  /** Get the technical error message associated with this failed record.
   *    <p>This message is intended for debugging purposes and is not normally
   *  intended for users.</p>
   */
  public String getMessage() {
    return iMessage;
  }


  /** Get the context in which the data record failed.
   *    <p>This can be any object that describes the error condition, but is normally the
   *  <code>Exception</code> that caused the processing of this data record to fail.</p>
   */
  public Object getContext() {
    return iContext;
  }


  /** Get the type of bad record that occurred. 
   *    <p>The current error types are <code>SEMANTIC</code>, for
   *  invalid data values, and <code>UNEXPECTED</code>, for unexpected exceptions thrown by the
   *  {@link RecordListener} (correctly functioning <code>RecordListener</code>s are 
   *  expected to return a <code>BadRecord</code> object instead of throwing an <code>Exception</code>).</p>
   */
  public int getType() {
    return iType;
  }


  /** Return a textual description of the <code>BadRecord</code> suitable for debugging purposes. */
  public String toString() {
    StringBuffer sb = new StringBuffer("[BadRecord:");
    int type = getType();
    sb.append( sTypeNames[ (0 < type && type < sTypeNames.length) ? type : 0 ] );
    sb.append( ",tag="+getTag() );
    sb.append( ",recnum="+getRecordNumber() );

    sb.append( ",fields=" );
    String[] rec = getRecord();
    if( null != rec ) {
      sb.append( Arrays.asList(getRecord()) );
    }
    else {
      sb.append( "[unknown]" );
    }

    sb.append( ",msg="+getMessage() );
    sb.append( ",context="+getContext() );
    sb.append("]");
    return sb.toString();
  }

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