Configuration of the Information Elements

You may have specific requirements in how to identify exceptions and how to structure your error and exception codes.

But first let us examine the central spot of most configuration issues: The de.smartics.exceptions.ExceptionContext.

Exception Context

The basic element of the configuration is the the factory for creating exception identifiers.

public interface ExceptionContext
{
  /**
   * Returns the factory for generating identifiers.
   *
   * @return the factory for generating identifiers.
   */
  IdFactory getIdFactory();
}

Note: Adding codes is done differently and will be covered in on of the next sections.

Exception Identifier

To provide another implementation you should extend de.smartics.exceptions.context.AbstractExceptionContext and provide a factory like in the following example:

public class SimpleUuidExceptionContext extends AbstractExceptionContext
{
  /**
   * Default constructor.
   */
   public SimpleUuidExceptionContext()
   {
     super(new UuidFactory());
   }
}

You install your context via the service provider facility. The current implementation is based on Java 5 and reimplements this facility provided by Java 6.

To use your implementation of the ExceptionContext specify the name of your class in

META-INF/services/de.smartics.exceptions.ExceptionContext

Specifying Error and Exception Codes

To specify your codes you should implement enumerations that implement the interface Code or any one of its sub interfaces. Currently only codes implemented by enumerations are supported (although only the reporting feature will not work if you use plain Java classes - so implementing codes by enumerations is highly recommended).

This is what it looks like:

public enum ParseExceptionCode implements NumberCode
{
  /**
   * The generic parsing error.
   */
  GENERIC(2000),

  /**
   * Parsing an OGNL path expression failed.
   */
  OGNL(2000, 1),

  /**
   * Parsing the value for a parent attribute failed because the <code>=</code>-sign
   * is missing. The <code>=</code>-sign separates the attribute name from
   * the index information.
   */
  MISSING_PARENT_PROPERTY_SEPARATOR(2000, 2),

  /**
   * Parsing the value for a parent attribute failed because the attribute in
   * front of the <code>=</code>-sign is missing.
   */
  MISSING_PARENT_PROPERTY_ATTRIBUTE(2000, 3),

  /**
   * Parsing the value for a parent attribute failed because the index after the
   * <code>=</code>-sign is missing.
   */
  MISSING_PARENT_PROPERTY_INDEX(2000, 4);

  /**
   * The code information.
   */
  private final NumberCodeInfo info;

  /**
   * Convenience constructor.
   *
   * @param majorNumber the major part of the error code.
   */
  private ParseExceptionCode(final Integer majorNumber)
  {
    this(majorNumber, null);
  }

  /**
   * Convenience constructor.
   *
   * @param majorNumber the major part of the error code.
   * @param minorNumber the minor part of the error code.
   */
  private ParseExceptionCode(final Integer majorNumber,
      final Integer minorNumber)
  {
    this(readComponentId(), majorNumber, minorNumber);
  }

  /**
   * Default constructor.
   *
   * @param componentId the component identifier.
   * @param majorNumber the major part of the error code.
   * @param minorNumber the minor part of the error code.
   */
  private ParseExceptionCode(final String componentId,
      final Integer majorNumber, final Integer minorNumber)
  {
    this.info = new NumberCodeInfo(componentId, majorNumber, minorNumber);
  }

  private static String readComponentId()
  {
    return Constant.COMPONENT_ID;
  }

  @Override
  public String getCode()
  {
    return info.getCode();
  }

  @Override
  public String getComponentId()
  {
    return info.getComponentId();
  }

  @Override
  public Integer getMajorNumber()
  {
    return info.getMajorNumber();
  }

  @Override
  public Integer getMinorNumber()
  {
    return info.getMinorNumber();
  }

  @Override
  public String toString()
  {
    return info.toString();
  }
}
        

You group codes semantically by the use of enumerations. Normally a certain exception type uses all codes of an enumeration.

public class ParseException extends
    AbstractLocalizedRuntimeException
{
  private static final long serialVersionUID = 1L;

  /**
   * The input that cannot be parsed.
   *
   * @serial
   */
  @MessageParam("0")
  protected final String input;

  /**
   * The index within the input string where the parsing error occurred.
   *
   * @serial
   */
  @MessageParam("1")
  protected final int index;

  /**
   * Constructor.
   *
   * @param code the error or exception code of the exception.
   * @param bundleBaseName the fully qualified name of the bundle to use.
   * @param input the input that cannot be parsed.
   * @param index the index within the input string where the parsing error
   *        occurred.
   */
  public ParseException(final ParseExceptionCode code,
      final String bundleBaseName, final String input, final int index)
  {
    this(null, code, bundleBaseName, input, index);
  }

  /**
   * Constructor.
   *
   * @param code the error or exception code of the exception.
   * @param input the input that cannot be parsed.
   * @param index the index within the input string where the parsing error
   *        occurred.
   */
  public ParseException(final ParseExceptionCode code, final String input,
      final int index)
  {
    this(code, null, input, index);
  }

  /**
   * Constructor.
   *
   * @param cause the cause (which is saved for later retrieval by the
   *        {@link #getCause()} method). (A <tt>null</tt> value is permitted,
   *        and indicates that the cause is nonexistent or unknown.)
   * @param code the error or exception code of the exception.
   * @param bundleBaseName the fully qualified name of the bundle to use.
   * @param input the input that cannot be parsed.
   * @param index the index within the input string where the parsing error
   *        occurred.
   */
  protected ParseException(final Throwable cause,
      final ParseExceptionCode code, final String bundleBaseName,
      final String input, final int index)
  {
    super(cause, code, bundleBaseName != null ? bundleBaseName
        : "de.smartics.exceptions.i18n.message.ParseExceptionBundle");
    this.input = input;
    this.index = index;
  }

  /**
   * Constructor.
   *
   * @param cause the cause (which is saved for later retrieval by the
   *        {@link #getCause()} method). (A <tt>null</tt> value is permitted,
   *        and indicates that the cause is nonexistent or unknown.)
   * @param code the error or exception code of the exception.
   * @param input the input that cannot be parsed.
   * @param index the index within the input string where the parsing error
   *        occurred.
   */
  protected ParseException(final Throwable cause,
      final ParseExceptionCode code, final String input, final int index)
  {
    this(cause, code, null, input, index);
  }

  public String getInput()
  {
    return input;
  }

  public int getIndex()
  {
    return index;
  }
}
        

What you can see in this example is the use of the ParseExceptionCode in the constructors.

Note: Please do not bother with the MessageParam annotation and the resource bundle stuff. They use the I18N library that is provided in an add-on project. If you are interested in this support please refer to smart-exceptions-i18n.