Packages

  • package root

    Documentation for the Axiell Utilities Project

    Documentation for the Axiell Utilities Project

    Overview

    The Axiell Utilities Project attempts to provide a small library of classes and object applicable to most Axiell developments. The library is not geared towards any one project and so should be useful for new projects as well as existing ones.

    The library is based on a few simple principles, namely:

    • referential transparency. The principle that defines a call to a method with the same arguments will always return the same result and that the method does not have any side effects (e.g. updating global variables, etc).
    • functional programming support. If a method or class does have side effects then the method or class is marked as effectful. The library has been designed to not contain any effectful code.
    • minimal functionality. The library is designed to be small with support for a small number of common utilities. The main reason for the small size is to limit the number of dependencies drawn in by the package.

    Package structure

    The com.axiell.util package consists of a number of utilities, where each utility provides a single piece of functionality.

    Notable utilities are:

    • Configure generic configuration reader allowing application settings defined as resources to be interrogated.
    • Error generic error handling class defining a locale independent error message along with details relating to the context of the error. The context may include an exception and other relevant values.
    • Formatter retrieves and formats a locale specific string from a specified resource bundle. The formatting is specified in a C printf style.
    • Implicits implements implicit methods and classes used to pimp methods onto existing classes (e.g. fold() method to Boolean class) and to provide implicit implementations for the JsonLocal and ShowLocal type classes.
    • JsonLocal type class used to output locale specific JSON structures. Implementations exist for Message and Error.
    • Message provides a locale independent mechanism for handling strings. The strings for a given locale are stored in resource bundles that are accessed when the message is to be displayed.
    • ShowLocal type class used to show locale specific strings. Allows Message and Error to be converted to a given language string.

    Dependencies

    The list of dependencies are:

    • Typesafe Config a generic configuration file reader. The library is used by the Configure class to access settings stored as resources within an application.
    Definition Classes
    root
  • package com
    Definition Classes
    root
  • package axiell
    Definition Classes
    com
  • package util

    Axiell Utilities Project

    Axiell Utilities Project

    A set of classes and traits that provide a simple mechanism for the internationalisation of strings and error handling. A mechanism is also supplied to read an application's configuration resource. All methods have been designed to be referentially transparent without the introduction of an effectful library (e.g. cats).

    Imports

    The utility classes/traits can be imported in the usual way, however it is necessary to include the Implicits object if the showLocal and jsonLocal type class methods are used, similarly for the read method on Configure.

    Example:

    import com.axiell.util.Implicits._

    A shorthand way to gain access to all utility classes is to import:

    import com.axiell.util._
    import com.axiell.util.Implicits._

    For more detail on project see the root package page.

    Definition Classes
    axiell
  • package instances

    Contains implicit values used by type classes.

    Contains implicit values used by type classes.

    The implicit values are used by the ShowLocal, JsonLocal and ConfigureReader type classes to print out language dependent strings, language dependent JSON strings and read configuration values respectively.

    Implicit values exist for the following classes:

    • ConfigureReader (read)
    • Error (showLocal, jsonLocal)
    • Int (showLocal, jsonLocal)
    • List (showLocal, jsonLocal)
    • Message (showLocal, jsonLocal)
    • java.time.OffsetDateTime (showLocal, jsonLocal)
    • java.lang.String (showLocal, jsonLocal)
    • java.lang.Throwable (showLocal, jsonLocal)

    The method names appended in brackets are the extension methods added by the implicit values.

  • package syntax

    Contains implicit classes used to add extension methods.

    Contains implicit classes used to add extension methods.

    The implicit classes are used to add the following extension methods:

    • showLocal displays a language dependent version of an object
    • jsonLocal generates a JSON string with language dependent strings
    • masonLocal generates a Mason Draft 2 compliant JSON string for Error
    • fold functionality for Boolean type

    All traits found in the package are for the implementation of extension methods. The traits are mixed into the Implicits object so they can be easily imported into clients when required.

  • Configure
  • ConfigureReader
  • Error
  • ErrorException
  • Formatter
  • Implicits
  • JsonLocal
  • Message
  • MessageBundle
  • ShowLocal

package util

Axiell Utilities Project

A set of classes and traits that provide a simple mechanism for the internationalisation of strings and error handling. A mechanism is also supplied to read an application's configuration resource. All methods have been designed to be referentially transparent without the introduction of an effectful library (e.g. cats).

Imports

The utility classes/traits can be imported in the usual way, however it is necessary to include the Implicits object if the showLocal and jsonLocal type class methods are used, similarly for the read method on Configure.

Example:

import com.axiell.util.Implicits._

A shorthand way to gain access to all utility classes is to import:

import com.axiell.util._
import com.axiell.util.Implicits._

For more detail on project see the root package page.

Source
package.scala
Linear Supertypes
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. util
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Package Members

  1. package instances

    Contains implicit values used by type classes.

    Contains implicit values used by type classes.

    The implicit values are used by the ShowLocal, JsonLocal and ConfigureReader type classes to print out language dependent strings, language dependent JSON strings and read configuration values respectively.

    Implicit values exist for the following classes:

    • ConfigureReader (read)
    • Error (showLocal, jsonLocal)
    • Int (showLocal, jsonLocal)
    • List (showLocal, jsonLocal)
    • Message (showLocal, jsonLocal)
    • java.time.OffsetDateTime (showLocal, jsonLocal)
    • java.lang.String (showLocal, jsonLocal)
    • java.lang.Throwable (showLocal, jsonLocal)

    The method names appended in brackets are the extension methods added by the implicit values.

  2. package syntax

    Contains implicit classes used to add extension methods.

    Contains implicit classes used to add extension methods.

    The implicit classes are used to add the following extension methods:

    • showLocal displays a language dependent version of an object
    • jsonLocal generates a JSON string with language dependent strings
    • masonLocal generates a Mason Draft 2 compliant JSON string for Error
    • fold functionality for Boolean type

    All traits found in the package are for the implementation of extension methods. The traits are mixed into the Implicits object so they can be easily imported into clients when required.

Type Members

  1. final class Configure extends AnyRef

    Reads values from application configuration resource

    Reads values from application configuration resource

    A configuration resource consists of a hierarchical set of properties. The resource uses a superset of the JSON format called HOCON to specify settings.

    Example configuration file:

    server {
      # The interface the server should bind to for servicing requests.
      # The default value of 0.0.0.0 forces the server to bind to all
      # interfaces on the machine.
      interface = 0.0.0.0
      interface = ${?SERVER_INTERFACE}
    
      # The port the server should bind to when accepting requests. The
      # default port used is 8000.
      port = 8000
      port = ${?SERVER_PORT}
    }

    Property values are read using the read method defined in this class:

    val result: Either[Error, (String, Int)] =
      for {
        config <- Configure()
        interface <- config.read[String]
        port <- config.read[Int]
      } yield (interface, port)

    The read method returns an Error if the property cannot be read as the type requested.

  2. trait ConfigureReader[A] extends AnyRef

    Reads a configuration value

    Reads a configuration value

    ConfigureReader is a type class that implements the read method on Configure. The method takes a configuration and key and extracts the key's value. The type of the key's value is determined by the type of the constructed ConfigureReader. A set of implicit instances implement common return types (e.g. String, Int, List[_]). It is possible to define your own reader, however the most common will already be available as part of the com.axiell.util.Implicits._ import.

    Example:

    implicit val stringForConfigureReader =
      new ConfigureReader[String] {
        def read[String](config: Configure, key: String): Result[String] =
          Try { configure.config.getString(key) }
           .fold(
             { exc => Left(Error("BadString", key).withException(exc)) },
             { Right(_) }
           )
    A

    return type of key value

  3. final case class Error extends Product with Serializable

    Contains a language independent error.

    Contains a language independent error.

    When an error occurs in a method it is useful to be able to return a description of what the error was, along with some context values associated with the error. In order to support internationalisation the error description should not contain a language specific string, but rather a code used to identify the error. Fortunately we can use the Message class to describe the error in a language independent way.

    The context for an error may include an optional exception, if the error was due to an exception, but it may also contain many other context specific values (e.g. file paths, error codes, counts, etc). In order to handle arbitrary context data Error contains an internal map where the key is an arbitrary label identifying the context and the value is the context data itself.

    The withProperty method allows an entry to be added to the internal map. For example, if an exception and a status code are to be associated with the error then the following code is required:

    Error("BadInt", value)
      .withProperty("exception", exc)
      .withProperty("status", 404)

    The labels exception and status are arbitrary and identify the kind of context data. The data itself can be any type that has an implicit ShowLocal and JsonLocal defined and in scope. The labels message and code are set to the error message and error code when the error is created.

    It is possible to retrieve context data by using the get method. The method takes the label to retrieve and the expected type of the data:

    Error("BadInt", value)
      .withProperty("status", 404)
      .get[Int]("status")

    will return the Int 404.

    A common paradigm, especially in functional programming is to have methods that may generate errors return either an Error or the return value. So it is common to see method return values like:

    def method[A]: Either[Error, A]

    The use of Either for return values is encouraged.

    Example:

    def method(value: String): Either[Error, Int] =
      Try { value.toInt }
        .fold(
          { exc =>
              Left(Error("BadInt", value).withProperty("exception", exc)
          },
          { Right(_) }
        )

    The method tries to convert a string to an integer value, which may result in an exception being thrown if the conversion fails.

    The showLocal method allows a language specific string for an Error to be output as a string. The method takes an implicit java.util.Locale identifying the language to be shown. The method is an extension method added by the ShowLocal type class.

    The jsonLocal method outputs the error as a JSON object where the map labels are the property names and the map values the property values. An implicit java.util.Locale is required for language specific values (e.g. Message). The method is an extension method added by the JsonLocal type class.

    The masonLocal method outputs the error as a JSON object conforming to the Mason Draft 2 specification. The method is an extension method.

    A number of extension methods are provided to set specific values with predefined labels, these include:

    • withException (label: exception)
    • withId (label: id)
    • withTime (label: time)
    • withHttpStatusCode (label: httpStatusCode)
    • withMessages (label: messages)
  4. final case class ErrorException(error: Error) extends Exception with Product with Serializable

    Wraps an Error with an Exception

    Wraps an Error with an Exception

    In some instances an exception needs to be thrown that contains a language independent error message. The language independent error message is represented by an Error. The getMessage() method returns the error message using the system default Locale. In most instances the catching code will unpack the error and use it.

    Example:

    def method(value: String): Int =
      Try { value.toInt }
        .fold(
          { _ => throw ErrorException(Error("BadInt", value)) },
          { _ }
        )

    The showLocal method can be used to generate a String containing the error properties along with a stack trace. The jsonLocal method produces a JSON object consisting of the error properties and the stack trace of where the exception was created.

    error

    Error to be wrapped in a Exception

  5. final class Formatter extends AnyRef

    Provides access to a set of language specific strings.

    Provides access to a set of language specific strings.

    A code is used support language independent strings. The code is effectively a label used to identify a language specified string in a resource bundle loaded when the class was created. The string extracted from the bundle may contain printf() style formatting markers. In order to satisfy the formatting markers a variable number of arguments are passed along with the string code.

  6. trait JsonLocal[-A] extends AnyRef

    Displays locale specific JSON string for any object.

    Displays locale specific JSON string for any object.

    JsonLocal is a type class that adds the jsonLocal extension method to any object. The method takes an implicit java.util.Locale defining the language to use for language specific strings. An implicit implementation of the JsonLocal trait must exist in scope for the method to be available.

    Example:

    val error = Error(MessageBundle("Errors"), "Bad Error")
    
    implicit val locale = Locale.ENGLISH
    error.jsonLocal
    error.jsonLocal(Locale.GERMAN)

    Output:

    {"message":"A bad error","code":"BadError"}
    {"message":"Ein schlimmer Fehler","code":"BadError"}

    The jsonLocal extension method can be defined for any class A provided an implementation of JsonLocal[A] exists implicitly and is in scope. The code below shows the implementation of JsonLocal[Error]:

    implicit val utilJsonLocalForError: JsonLocal[Error] =
      new JsonLocal[Error] {
        def jsonLocal(error: Error)(implicit locale: Locale): String = {
          error.map.toList.map { case (key, (value, format, _)) =>
            s""""${escape(key)}":${format.jsonLocal(value)}"""
          }
            .mkString("{", ",", "}")
        }
      }
    A

    type for which a language specific JSON string is generated

  7. final case class Message extends Product with Serializable

    Contains a language independent message.

    Contains a language independent message.

    In order to support internationalisation of applications it is necessary to provide a mechanism that allows a string to be generated in a language independent way. The Message class provides such a mechanism.

    A Message contains information used to extract a string and format it when it needs to be displayed. In order to display the string it is necessary to invoke the showLocal method passing in an implicit java.util.Locale. The locale determines what language is used to extract the string.

    A language independent string is identified by three things, namely:

    • bundle identifies a group of strings stored within the one resource
    • code indicates which string to extract from the bundle
    • args that are interpolated into the string when displayed

    Message objects may be passed around and the showLocal method only invoked when it is necessary to display the string in a language dependent way.

    Let's look at an example:

    class Messages_en extends java.util.ListResourceBundle {
      final override val getContents: Array[Array[AnyRef]] =
        Array(
          Array("BadValue", "The bad value is %s")
          ...
        )
    }
    
    class Messages_de extends java.util.ListResourceBundle {
      final override val getContents: Array[Array[AnyRef]] =
        Array(
          Array("BadValue", "Der falsche Wert ist %s")
          ...
        )
    }
    
    implicit val bundle = MessageBundle("Messages")
    val message = Message("BadValue", "abc123")
    
    implicit val locale = Locale.ENGLISH
    message.showLocal
    message.showLocal(Locale.GERMAN)

    Output:

    The bad value is abc123
    Der falsche Wert ist abc123

    The Messages_en class contains a mapping between the code used to identify a string and its English message, similarly Messages_de contains the same codes with the equivalent German message.

    The Message is created using an implicit MessageBundle identifying the base class name containing the translated strings. Since the translated strings contain a format marker (%s) an argument must be supplied along with the code when the Message is instantiated.

    The showLocal method is used when a Message is to be displayed. The method takes an implicit java.util.Locale identifying which language is to be shown. The method is an extension method added by the ShowLocal type class.

  8. final case class MessageBundle(name: String) extends Product with Serializable

    Identifies the class name containing string resources.

    Identifies the class name containing string resources.

    A bundle is a set of classes containing string resources. Each class in the set begins with the MessageBundle name and has a locale appended to it identifying the language of the strings it contains. A special case is the class name without any locale appended. If a locale specific class cannot be located then the class without the locale is appended.

    A bundle extends the java.util.ListResoruceBundle class and overrides the getContents method. The method returns an Array where each element is an array containing two elements. The first element is a code used to identify a string in a language independent way and the second is a language dependent string.

    Example:

    class com.acme.Messages extends java.util.ListResourceBundle {
      final override val getContents: Array[Array[Object]] =
        Array(
          Array("BadValue", "The bad value is %s")
          ...
        )
    }
    
    class com.acme.Messages_de extends java.util.ListResourceBundle {
      final override val getContents: Array[Array[Object]] =
        Array(
          Array("BadValue", "Der falsche Wert ist %s")
          ...
        )
    }

    The name of the class to supply to the MessageBundle to access the above string resources is "com.acme.Messages". Hence the MessageBundle is instantiated with:

    MessageBundle("com.acme.Messages")

    Best practice would dictate that each resource bundle class is placed in a separate file so that only the strings for a given language are loaded when required.

    name

    of the class containing the resource strings

  9. trait ShowLocal[A] extends AnyRef

    Displays locale specific string for any object.

    Displays locale specific string for any object.

    ShowLocal is a type class that extends classes with the showLocal method. The method takes an implicit java.util.Locale defining in what language the returned string should be. In order to add the extension method to an object it is necessary to define an implicit implementation of the ShowLocal trait.

    Example:

    case class Person(name: String, age: Int)
    
    implicit val showLocalForPerson: ShowLocal[Person] =
      new ShowLocal[Person] {
        def showLocal(person: Person)(implicit locale: Locale): String = {
          locale.getLanguage match {
            case "en" => s"Name: ${person.name}, Age: ${person.age}"
            case "fr" => s"prénom: ${person.name}, âge: ${person.age}"
          }
        }
      }
    
    val person = Person("John Smith", 32)
    implicit val locale = Locale.ENGLISH
    
    person.showLocal
    person.showLocal(Locale.FRENCH)

    Output:

    Name: John Smith, Age: 32
    prénom: John Smith, âge: 32

    The showLocal extension method can be defined for any class A provided an implementation of ShowLocal[A] exists implicitly and is in scope. The implicit definitions are generally defined in separate classes in a "instances" sub-directory enclosed within a trait. The trait is then mixed into an Implicits object allowing user to only import Implicits._.

    For the example above the trait class would look like:

    trait PersonInstances {
      implicit val showLocalForPerson: ShowLocal[Person] =
        new ShowLocal[Person] {
          def showLocal(person: Person)(implicit locale: Locale): String = {
            locale.getLanguage match {
              case "en" => s"Name: ${person.name}, Age: ${person.age}"
              case "fr" => s"prénom: ${person.name}, âge: ${person.age}"
            }
          }
        }
    }

    stored in the file instances/PersonInstances.scala. All implicits would be mixed in a file called Implicits.scala that looks like:

    object Implicits
      extends instances.PersonInstances
    A

    type for which a language specific string is generated

Value Members

  1. object Configure

    Provides access to application configuration resource

    Provides access to application configuration resource

    The application configuration is defined in the application.conf file stored in the application resource directory. The configuration file is a superset of the JSON format. All JSON constructs are supported (e.g. string, number, array, object, etc) along with extensions like comments and environment variable substitution.

    The Typesafe Config library is wrapped by this class and full details on the configuration file format can be found in their documentation. The reason to wrap an existing library is to provide an interface supporting a consistent return type using Either[Error, A] .

    Example configuration file:

    server {
      # The interface the server should bind to for servicing requests.
      # The default value of 0.0.0.0 forces the server to bind to all
      # interfaces on the machine.
      interface = 0.0.0.0
      interface = ${?SERVER_INTERFACE}
    
      # The port the server should bind to when accepting requests. The
      # default port used is 8000.
      port = 8000
      port = ${?SERVER_PORT}
    }

    The ${?variable} construct indicates an environment variable should be consulted for a value. If a value is found it overrides the default setting.

    Referential Transparency

    The application configuration (stored in the resources/application.conf file) is read once first accessed. It is then cached for the life of the application. Hence the configuration definition itself is immutable. When a setting is consulted and the setting depends on an environment variable the environment is only read once and cached (via System.getEnv()). Since it is not possible change an environment variable value (as the values are cached and Java does not provide a mechanism to do so) the values are effectively immutable. Hence referential transparency is enforced.

  2. object ConfigureReader

    Contains factory method to extract reader from type bound definition

    Contains factory method to extract reader from type bound definition

    The read method on Configure is type bound, meaning an unnamed implicit argument is passed to the method (a ConfigureReader[A] in this case). In order to access the nameless implicit a factory method is defined that extracts a named implicit and returns it's value, allowing the value to be used.

  3. object Error extends Serializable

    Constructs Error objects

    Constructs Error objects

    An error may be created using either an explicit or implicit MessageBundle. The bundle defines the resource (class) containing the language specific error strings.

    Example:

    implicit bundle MessageBundle("Errors")
    val err1 = Error("ErrorCode")
    val err2 = Error(MessageBundle("Errors"), "ErrorCode")

    The MessageBundle is generally defined implicitly in package.scala making it available to all code within the enclosed package. Error strings may be placed in a separate resource bundle from general messages.

    When and error is created the message label is set to the error message (Message) and code is set to the error code (java.lang.String).

  4. object Formatter

    Creates a Formatter used to access strings for a given locale stored in a given bundle.

    Creates a Formatter used to access strings for a given locale stored in a given bundle.

    The support for language specific strings involves two values. The first is a MessageBundle that defines the name of a class containing language dependent strings. The second value is the java.util.Locale used to select the set of language strings to be accessed. When a Formatter is created an attempt is made to load the supplied bundle with the given locale. If the loading succeeds then the strings may be accessed via the returned Formatter.

    The current class loader is used to try and load the bundle class. The bundle class must extend java.util.ListResourceBundle. The class name may have a language code (e.g. _en) appended indicating the language whose strings are defined in the class. A class name without a language extension is the default bundle, used when a language specific version cannot be found.

    Example:

    package com.acme
    
    class Resources extends java.util.ListResourceBundle {
      final override val getContents: Array[Array[AnyRef]] =
        Array(
          Array("BadValue", "The bad value is %s")
          ...
        )
    }
    
    class Resources_de extends java.util.ListResourceBundle {
      final override val getContents: Array[Array[AnyRef]] =
        Array(
          Array("BadValue", "Der falsche Wert ist %s")
          ...
        )
    }

    The above bundle classes define strings for German (Resources_de) and the default bundle (Resources). When defining bundles it makes sense to define all languages within a single file.

    Referential Transparency

    The string resources are stored in a class and read as a java.util.ListResourceBundle. The strings are constants defined in a class ensuring that the same value is always returned for the same arguments. The read-only nature of the resource class ensures the Formatter methods are referentially transparent and so not effectful.

  5. object Implicits extends ConfigureReaderInstances with ErrorInstances with ErrorExceptionInstances with IntInstances with ListInstances with MessageInstances with OffsetDateTimeInstances with StringInstances with ThrowableInstances with BooleanSyntax with ErrorSyntax with JsonLocalSyntax with MasonLocalSyntax with ShowLocalSyntax

    Groups all implicits into a single object

    Groups all implicits into a single object

    Method extension implicits (Syntax suffix) and implicit variables (Instances Suffix) are mixed into a single object allowing a single import statement to be used to bring them all into scope.

    The required import statement is:

    import com.axiell.util.Implicits._
  6. object JsonLocal

    Implements type class extension method for JsonLocal[A]

  7. object Message extends Serializable

    Constructs Message objects.

    Constructs Message objects.

    Two ways of creating Message objects are supported. The first method requires the MessageBundle to be supplied explicitly while the second method accepts the MessageBundle implicitly.

    Example:

    implicit bundle = MessageBundle("Resources")
    val mess1 = Message("BadCode", "abc123")
    val mess2 = Message(MessageBundle("Resources"), "BadCode", "abc123")

    The mess1 assignment uses the implicit MessageBundle to determine where to locate the message strings, while the assignment to mess2 states the MessageBundle explicitly. In practice the implicit version is generally used, with the implicit MessageBundle declared in a package.scala file.

  8. object ShowLocal

    Implements type class extension method for ShowLocal[A]

Inherited from AnyRef

Inherited from Any

Ungrouped