GridSafeDocumentation/AccountingParser/ValueParserService/

The Value Parser Service associates a type of value with a parser that can parse a string into a particular type. The type is given a unique name that may be used by other configuration properties to assign types where appropriate. Unlike accounting parsers, these parsers are intended to parse a specific value into a Java obect to be used internally or stored in the database.

Several types have already been defined and may be used without any configuration. New types may be added that use the existing parsers provided. Alternatively, new parsers can be written and used. A possible use case would be that a value must conform to a specific set of rules. A user could write a special parser that makes sure the input string meets these rules before generating a Java object of the appropriate type from the String value.

Defining and Redefining Types

New types may be created by assigning a value parser to them. Using the following configuration property:

class.value_parser.type = binary-java-class-name

for example:

class.value_parser.newtype = com.example.NewSpecialParser 

The class must be on the class path and implement the uk.ac.ed.epcc.safe.accounting.parsers.value.ValueParser interface. Several value parsers have already been defined and can be found in the Java package uk.ac.ed.epcc.safe.accounting.parsers.value. Consult this package and the Javadoc within it to see the current set of value parsers available. See below to find out how to define new custom value parsers.

Names of the default parsers may be overridden using the above method. A parser defined in the configuration properties with the same name as a default parser will take presence over the default.

Creating New Value Parsers

To create a new value parser, a Java class must be written that implements uk.ac.ed.epcc.safe.accounting.parsers.value.ValueParser.

The interface requires the class to implement two methods:

getType()
Returns the Class of object the value parser returns with it's parse(String) method is invoked.
parse(java.lang.String)
Returns the object of the appropriate type generated from the string argument. This method may throw a java.lang.IllegalArgumentException if the appropriate object cannot be generated from the string. The exception should (but does not have to) contain a helpful error message describing why the string could not be converted.

All classes implementing this ValueParser must also define a no-argument constructor which properly constructs the parser. If no actual configuration is required, a constructor may be omitted entirely and the objects default constructor provided automatically by Java will be used instead. This restriction cannot be enforced at compile time, however it is a requirement of the ValueParserService.

Currently, only java.lang.Boolean, java.lang.String, java.lang.Number, uk.ac.ed.epcc.webapp.model.data.Duration and java.util.Date objects are persisted in the database. While value parsers can potentially parse strings into any type, it is highly recommended that the type be limited to one of these types or one of their subclasses. Otherwise, adverse effects may emerge (e.g. data may not be properly persisted).

For examples of value parsers that have already been implemented, see the value parsers in the uk.ac.ed.epcc.safe.accounting.parsers.value package.

Predefined Types

The following parsers are already defined and may be used without any configuration. They may be overridden by adding a parser of the same name as them to the configuration properties. For more information on how the parsers function, see their Javadoc

Type Value Parser Used
date uk.ac.ed.epcc.safe.accounting.parsers.value.DateParser
duration uk.ac.ed.epcc.safe.accounting.parsers.value.SimpleDurationParser
real uk.ac.ed.epcc.safe.accounting.parsers.value.DoubleParser
integer uk.ac.ed.epcc.safe.accounting.parsers.value.LongParser
string uk.ac.ed.epcc.safe.accounting.parsers.value.StringParser
timestamp uk.ac.ed.epcc.safe.accounting.parsers.value.TimestampParser
xml-datetime uk.ac.ed.epcc.safe.accounting.parsers.value.XMLDateTimeParser
xml-duration uk.ac.ed.epcc.safe.accounting.parsers.value.XMLDurationParser

Examples

The predefined types do not need to be declared in the configuration properties. They have been hard coded in. However, if they were to be declared, they would look like this:

class.value_parser.date = uk.ac.ed.epcc.safe.accounting.parsers.value.DateParser
class.value_parser.duration = uk.ac.ed.epcc.safe.accounting.parsers.value.SimpleDurationParser
class.value_parser.real = uk.ac.ed.epcc.safe.accounting.parsers.value.DoubleParser
class.value_parser.integer = uk.ac.ed.epcc.safe.accounting.parsers.value.LongParser
class.value_parser.string = uk.ac.ed.epcc.safe.accounting.parsers.value.StringParser
class.value_parser.timestamp = uk.ac.ed.epcc.safe.accounting.parsers.value.TimestampParser
class.value_parser.xml-datetime = uk.ac.ed.epcc.safe.accounting.parsers.value.XMLDateTimeParser
class.value_parser.xml-duration = uk.ac.ed.epcc.safe.accounting.parsers.value.XMLDurationParser

Suppose there is a particular type of string value that should always be stored in lower case. Further more, it's first character must be a letter (upper or lower case). We could manipulate values of this type and enforce this constraint by defining a new value parser:

package org.example

import uk.ac.ed.epcc.safe.accounting.parsers.value.ValueParser;

public class LowerCaseFirstChacaterIsLetterParser implements ValueParser<String> {

  /*
   * We don't have anything to initialise so we'll just use the default
   * no-argument constructor
   */

  /*
   * This method is always easy to implement.
   */
  public Class<String> getType() {
    return String.class;
  }

  public String parse(String valueString) throws IllegalArgumentException,
      NullPointerException {

    /* We won't allow null values for this parser */
    if (valueString == null) {
      throw new NullPointerException("value cannot be null");
    }

    if (valueString.length() == 0) {
      /* Empty strings are ok */
      return "";
    } else if (Character.isLetter(valueString.charAt(0)) == false) {
      /*
       * We won't allow this value. Send a helpful error message back explaining
       * why
       */
      throw new IllegalArgumentException("First character of '" + valueString
          + "' is not a letter character");
    } else {
      /* Value is acceptable. Lets modify it now so that it's all lower case. */
      return valueString.toLowerCase();
    }
  }
}

Now, we can create a new type that uses this value parser with the following configuration property:

class.value_parser.lower-case-string = org.example.LowerCaseFirstChacaterIsLetterParser

We must make sure that this class is on the classpath for the value parser to be found. The type lower-case-string may be used by other configuration properties whenever a type needs to be specified.

If we wanted all strings parsed to use the our LowerCaseFirstChacaterIsLetterParser we could set the configuration property:

class.value_parser.string = org.example.LowerCaseFirstChacaterIsLetterParser

Now, every time the string type is used, it will use the custom value parser. This includes properties and settings that have been predefined.

 

Grid-SAFE was funded by JISC and is maintained, developed, and managed by EPCC at the University of Edinburgh