Package org.ujorm

The Ujorm tutorial.

See: Description

Package org.ujorm Description

The Ujorm tutorial.

UJO IconsContent

What is UJO ?

UjoUml.png The Ujorm core (original name was UJO Framework) is an open source Java small library which providing non-traditional objects based on the key‑value architecture to open up new exciting opportunities for writing efficient code. The original idea was a toy with generic data types of Java 5.0 however over time it appears, that the architecture has many interesting features: These keys open up new possibilities for the use in the J2EE mainly in a production of generic operations over objects. Framework contains some tools for managing the UJO object in addition. So what are the main advantages? UJO is an abbreviation for Unified Java Object and they are all objects, which implements an interface Ujo. You can imagine the object UJO like a map (an object that maps keys to values) with data access by methods of the key for example. This key is made up of the implementation of the Key including (among others) two type-safe methods: There is possible to send the keys to another objects simply contrary of the methods of JavaBean object. An example of usage can be a list of table columns sent to the data model type of TableModel or references to the methods of the bean in a JSP page. The core of the project are two interfaces Ujo a Key, which have got three abstract implementation: I took inspiration for my work from project Cayenne (a solution for a persistence BO ORM)

Simplified Key

The interface WeakKey is a simplified Key interface without the generic domain type parameter and it is intended for a common use. The WeakKey need not to use Ujo objects, because it works with objects of type Map and List.

Note, the default implementation does not have the full support of several methods:

, and some more methods are not fully type-safe. To create new keys use an instance of the factory class WeakKeyFactory.

The sample of use

public class MyService {
    private static final WeakKeyFactory f = new WeakKeyFactory(MyService.class);

    public static final WeakKey<String>     NAME = f.newKey();
    public static final WeakKey<Date>       BORN = f.newKey();
    public static final WeakKey<Boolean>    WIFE = f.newKeyDefault(Boolean.TRUE);
    public static final WeakKey<BigDecimal> CASH = f.newKeyDefault(BigDecimal.ZERO);

    static {
        f.lock(); // Initialize all keys and lock them
    }

    /** Sample how to use weak keys with a Map. */
    public void testWeakKeys2Map() {
        Map<String,Object> map = new HashMap<String, Object>();

        assert NAME.of(map) == null;
        assert BORN.of(map) == null;
        assert WIFE.of(map) == Boolean.TRUE;
        assert CASH.of(map) == BigDecimal.ZERO;

        final String name = "Lucy";
        final Boolean wife = true;
        final Date today = new Date();
        final BigDecimal cash = BigDecimal.TEN;

        NAME.setValue(map, name);
        BORN.setValue(map, today);
        WIFE.setValue(map, wife);
        CASH.setValue(map, cash);

        assert NAME.of(map).equals(name);
        assert BORN.of(map).equals(today);
        assert WIFE.of(map).equals(wife);
        assert CASH.of(map).equals(cash);
    }

    /** Similar sample how to use weak keys with a List. */
    public void testWeakKeys2List() {
        List<Object> list = new ArrayList<Object>();

        // and the same code works for the List instance:
        assert NAME.of(list) == null;
        assert BORN.of(list) == null;
        assert WIFE.of(list) == Boolean.TRUE;
        assert CASH.of(list) == BigDecimal.ZERO;

        final String name = "Lucy";
        final Boolean wife = true;
        final Date today = new Date();
        final BigDecimal cash = BigDecimal.TEN;

        NAME.setValue(list, name);
        BORN.setValue(list, today);
        WIFE.setValue(list, wife);
        CASH.setValue(list, cash);

        assert NAME.of(list).equals(name);
        assert BORN.of(list).equals(today);
        assert WIFE.of(list).equals(wife);
        assert CASH.of(list).equals(cash);
    }
}
The next example shows some interesting features of the Key object.
    /** Test key attributes */
    public void testWeakKeyAttributes() {
        assert NAME.getIndex()==0;
        assert BORN.getIndex()==1;
        assert WIFE.getIndex()==2;
        assert CASH.getIndex()==3;

        assert NAME.getName().equals("name");
        assert BORN.getName().equals("born");
        assert WIFE.getName().equals("wife");
        assert CASH.getName().equals("cash");

        assert NAME.isTypeOf(CharSequence.class);
        assert BORN.isTypeOf(Date.class);
        assert WIFE.isTypeOf(Boolean.class);
        assert CASH.isTypeOf(BigDecimal.class);
    }

Where to use the WeakKey?

My first Ujo object

Ujo interface is an envelope for any data source. Ujo object have got your own related Keys always. So, how to write the first Ujo object? The fastest way is to use some abstract UJO implementation from this project and via few code lines we can make quickly and easily our own implementation, too. Here is an example - the implementation of the Person class by an abstract AbstractUjo class.

The class code

The typical implementation of the Person class based on the AbstractUjo:
public class Person extends AbstractUjo {
  private static final KeyFactory<Person> f = newFactory(Person.class);

  public static final Key<Person,String > NAME = f.newKey();
  public static final Key<Person,Boolean> MALE = f.newKey();
  public static final Key<Person,Double > CASH = f.newKey();

  @Override public KeyList<?> readKeys() {
      return f.getKeys();
  }
}
or more easy implementation without the class KeyFactory for a child of the class SmartUjo:
public class Person extends SmartUjo {
public static final Key<Person,String > NAME = newKey(); public static final Key<Person,Boolean> MALE = newKey(); public static final Key<Person,Double > CASH = newKey();
}
Now, when the Person class is done, we can make its instance and enter or fetch some data. It´s possible to use one of two API methods for writing the object attributes:
  1. Person.writeValue(Key, Object), or
  2. Key.setValue(person, Object).
These methods are equivalent from a point of result, but the second solution offers the type safe access during the writing and reading of a value. A show of the second (2) method use up:
import static org.Person.*;
Person person = new Person();
// Writing: NAME.setValue(person, "Pavel Ponec"); MALE.setValue(person, true); CASH.setValue(person, 34.5);
// Reading: String name = NAME.of(person); // method of() is an alias for Key.getValue() boolean male = MALE.of(person); double cash = CASH.of(person);
There is possible to use an extended API with a more obvious source code to the property access since the UJO release 0.80. The new solution allows to you a chaining more keys according to the model of a language Groovy. The new API extends the old one so that you can use an combination of both types.
import static org.Person.*;
Person person = new Person(); // An extension of MapUjoExt
// Writing: person.set(NAME, "Pavel Ponec"); person.set(MALE, true); person.set(CASH, 34.5);
// Reading: String name = person.get(NAME); boolean male = person.get(MALE); double cash = person.get(CASH);
A note:
If you use a compilation parameter -Xlint:unchecked, an assembler can warn you of absent declaration of generic data types in the Key initialization sometimes. There are three possibilities now:

The implementation of the equals() method

Our Person class has the equals() function implemented already, which inherited from parental class AbstractUjo. But if you want by some reason to write your own Ujo implementation with this method, it´s enough to write into the class this code:
public boolean equals(Object obj) {
  return UjoManager.getInstanceManager().equals(this, (Ujo) obj );
}

Implementation of the clone() method

Analogous to the equals method you can make the clone() method :
public Object clone() {
  return UjoManager.getInstanceManager().clone(this, 1, null);
}

Implementation of the hash() method

A similar example of the hash() method implementation:
public int hash() {
  return UjoManager.getInstanceManager().getHash(this);
}
All of these implementations are generally applicable to all the Ujo objects posterity.

Using the KeyFactory in interfaces

In some cases can be useful to define Ujo Keys in an interface. See the next simple example how to design the inteface using the class KeyFactory:
public interface MyUjoInterface extends Ujo {
    /** The factory will be an immutable object after locking */
    public static final KeyFactory<MyUjoInterface> $factory
            = KeyFactory.CamelBuilder.get(MyUjoInterface.class);

    public static final Key<MyUjoInterface,Long>      PRO_P0 = $factory.newKey();
    public static final Key<MyUjoInterface,Integer>   PRO_P1 = $factory.newKey();
    public static final Key<MyUjoInterface,String>    PRO_P2 = $factory.newKey();
    public static final Key<MyUjoInterface,Date>      PRO_P3 = $factory.newKey();
    public static final ListKey<MyUjoInterface,Float> PRO_P4 = $factory.newListKey();

    /** Size of the all keys and lock internal factory. */
    public static final int KEY_SIZE = $factory.lockAndSize();

}
The interface MyUjoInterface can be a child of another Ujo interface optionally, however an implementation of multiple interfaces is not recommended due to the risk of duplicate Key indexes. The next example shows a sample of a real implementation:
public class MyUjoImpl implements MyUjoInterface {
    private Object[] data = new Object[KEY_SIZE];

    @Override
    public KeyList<?> readKeys() {
        return $factory.getKeys();
    }

    @Override
    public Object readValue(Key property) {
        return data[property.getIndex()];
    }

    @Override
    public void writeValue(Key property, Object value) {
        data[property.getIndex()] = value;
    }

    @Override
    public boolean readAuthorization(UjoAction action, Key property, Object value) {
        return true;
    }
}

 

Default values

A JavaBean property can have got a default value by the sample:
{
  private Double cash = 10.0;
}
Also the UJO property can have got a default value. All the implementations of method Ujo.readValue(...) from this frameworks replaces an undefined value (NULL) by the default value from the Key.
{
  public static final Key<Person, Double> CASH = newKey("Cash", 10.0);
}
Note, you can change a default key name also using the first text parameter. The default property name have got Special features:

 

Validators

The framework provides a special interface to validation a data input value. The Ujorm validators have got a similar meaning for Ujo object how the Bean Validation (JSR 303) implementation for the JavaBeans. The main diferences are:
Ujo ValidationBean Validation (JSR 303)
  • validator can be assigned on a Key of an Ujo implementation using the Java code
  • assigned validator is evaluated on the event of each entry values
  • validators can be joined using AND / OR operator
  • validator is assigned on a field of a java-bean implementation using an annotation or XML
  • assigned validator is evaluead on an special event
  • validators can be joined using AND operator

Using the validator

There is an short example how to use the Ujorm Validator:
    Integer maxValidValue = 10;
    Integer wrongValue = 120;
    Validator<Integer> maxValidator = Validator.Build.max(maxValidValue);
    ValidationError error = maxValidator.validate(wrongValue, null, null);

    // Get the default message:
    String defaultMessage = error.getDefaultMessage();

    // Or get a localized message using your template:
    String template = "My input ${INPUT} must be up to ${LIMIT}.";
    String myMessage = error.getMessage(template);
    assertEquals("My input 120 must be up to 10.", myMessage);
If the validation check is correct, then the method Validator.validate(..) returns the NULL value, else the method returns an instance of the ValidationError class. Each the instance of the class ValidationError provides the default validation message and offers tools to create a localized message using a user template with named parameters with the format: ${argument,format}, where the optional format phrase have got the same syntax as the tool Formatter. Each Ujorm validator contains at least three argument values: More arguments depends on the Validator implementation and their descriptions are referred to in JavaDoc. On the second example is an extended solution.
import static org.ujorm.validator.impl.BetweenValidator.*;
    ...
    Integer minValidValue = 1;
    Integer maxValidValue = 9;
    Integer wrongValue = 130;

    Validator<Integer> rangeValidator = Validator.Build.range(minValidValue, maxValidValue);
    ValidationError error = rangeValidator.validate(wrongValue, ValidBo.CODE, null);
    //
    String expectedDefaultMesage = "An attribute ValidBo.code must be between 1 and 9 (including)"
            + ", but the input is: 130";
    assertEquals(expectedDefaultMesage, error.getDefaultMessage());
    //
    String expectedMyMesage = "My input is not between 1 and 9";
    String myTemplate = "My input is not between ${MIN} and ${MAX}";
    String message = error.getMessage(myTemplate, Locale.ENGLISH);
    assertEquals(expectedMyMesage, message);
    //
    Object[] arrayTemplate = {"My input is not between ", MIN, " and ", MAX};
    assertEquals(expectedMyMesage, error.getMessage(arrayTemplate, Locale.ENGLISH));
    assertEquals(myTemplate, new MessageService().template(myTemplate));

Validator on the Key

Any Validator imlementation can be assigned to an immutable Ujo-key. In this case any event of writting on the key will be checked by the assigned Validator. The default Key value is not be validated similar as any value written out from the Key because the value is not written using the Key. See some examples to building the key:
public class ValidBo extends AbstractUjo {

    /** Factory */
    private static final KeyFactory<ValidBo> f = newFactory(ValidBo.class);
    /** Documentation: */
    public static final Key<ValidBo, Long> PID = f.newKey(notNull());
    public static final Key<ValidBo, Integer> CODE = f.newKey(between(0, 10));
    public static final Key<ValidBo, String> NAME = f.newKey(regexp("T.*T"));
    public static final Key<ValidBo, Double> CASH = f.newKey(min(0.0).and(notNull()));

    static {
        f.lock();
    }
}
The most of Ujorm Validators allows the null value, however there is possible to join one validator with another one, see the key name "CASH" for example how to do it. There are four methods to create a non-null validator: Build.notNull(), Bulid.notEmpty(), Build.notBlank() and Build.readOnly().

Create a user validator

The simple way to make your own validator is to create a child of the AbstractValidator and overwrite the method: validate(...). The next example is an implementaiton from the Ujorm-core:
public class BetweenValidator<VALUE extends Comparable> extends AbstractValidator<VALUE> {

    /** Serializable minimum (inclusive) */
    public static final MessageArg MIN = new MessageArg("MIN");
    /** Serializable maximum (exclusive) */
    public static final MessageArg MAX = new MessageArg("MAX");

    /** Serializable minimum (inclusive) */
    protected final Comparable min;
    /** Serializable maximum (exclusive) */
    protected final Comparable max;

    /**
     * Between validator
     * @param min Serializable minimum (inclusive)
     * @param max Serializable maximum (exclusive)
     */
    public BetweenValidator(VALUE min, VALUE max) {
        this.min = min;
        this.max = max;
    }

    /** {@Inherited} */
    public <UJO extends Ujo> ValidationError validate(VALUE input
            , Key<UJO, VALUE> key
            , UJO bo
            ) {
            final boolean ok = input==null
                    || input.compareTo(min) >= 0
                    && input.compareTo(max) < 0;
            return !ok ? new ValidationError
                    ( input
                    , key
                    , bo
                    , getClass()
                    , getLocalizationKey()
                    , getDefaultTemplate()
                    , service.map
                    ( MIN, min
                    , MAX, max
                    ))
                    : null;
    }

    /** Returns a default message */
    @Override
    protected String getDefaultTemplate() {
        return service.template("An attribute ", KEY, " must be between "
                , MIN, " and ", MAX, " (excluding), but the input is: ", INPUT);
    }

    /** Default value is: "org.ujorm.between" */
    public String getLocalizationKey() {
        return KEY_PREFIX + "between";
    }
}
See the JavaDoc for some more validator implementations.

Extended Ujo

The most of information in this tutorial are related to a basic Ujo interface however since a version Ujorm 0.80 is available an extended interface called UjoExt for an easier utilization in a source code. The extended features are described by a slide show format in a different document or you can try an UjoExt JavaDoc description.

 

The JavaBean implements Ujo

It´s easy to create a JavaBean from an UJO object. It´s enough to implement a setter and a getter for each attribute. An example of usage:
public class Person extends SmartUjo {
public static final Key<Person, String> NAME = newKey(); public static final Key<Person, Double> CASH = newKey();
public void setName(String name) { NAME.setValue(this, name); } public String getName() { return NAME.getValue(this); } public void setCash(Double cash) { CASH.setValue(this, cash); } public Double getCash() { return CASH.getValue(this); } }
There is possible to use an special implementation BeanUjo to an implementation UJO features to your complete JavaBeans. This BeanUjo implementation calls JavaBean setters and getters by a Java reflection for writing and reading values (fields). A name of Ujo property must accord with a related name of the JavaBean attribute (methods) in the implementation. There is allowed to use a primitive types of the object fields if you can (e.g. Double -> double).
import org.ujorm.implementation.bean.*;
public class Person extends BeanUjo {
public static final BeanProperty<Person, String> NAME = newKey(); public static final BeanProperty<Person, Double> CASH = newKey(); private String myname; private Double mycash; public void setName(String name) { this.myname = name; } public String getName() { return myname; } public void setCash(Double cash) { this.mycash = cash; } public Double getCash() { return mycash; } }
Keep the mind that getters of implementation BeanUjo don't call a method Ujo.readProperty(..) similar like setters don't call Ujo.writeProperty(). For example this is the reason why method getCash() can't return a default value from Key for example. The way NAME.getValue(...) works fine.

XML serialization

Usage of an UJO serialization is very simple, that is how the code looks like:
Person person = somePersonProvider().getPerson();
// Make Serialization: UjoManagerXML.getInstance().saveXML(writer, person, null, "My Export");
// Make Deserialization: person = UjoManagerXML.getInstance().parseXML(inputStream, Person.class, "My Import");
A content of created XML is now:
<?xml version="1.0" encoding="UTF-8"?>
<body>
  <NANE>Pavel Ponec</NAME>
  <MALE>true</MALE>
  <CASH>34.5</CASH>
</body>

List property

It´s often very useful some attribute to contain a list of another UJO objects. It´s possible to make the ArrayList<UjoItem> type object though, but preferable is to use for an attribute the ListProperty class. The first reason is a clearer content of an export to XML, because an export doesn't contain the information about the data type items of the list. I recommend to read up API for more detailed information.
 
Recommended solution for the implementation of a link 1:N for the Person - Child objects.
public class Person extends AbstractUjo {
  public static final Key <Person,String> NAME  = newKey();
  public static final ListProperty<Person,Child> CHILDS = newListKey();
}

Hidden elements

What to do, when you need to export only some of the UJO object attributes and to ignore the rest? There is the readAuthorization(...) method for this case.
This method can allow a participation of the chosen attributes in dependence on: On the following example we will illustrate, how the suppression of the NAME attribute by an export into XML looks like:
public boolean readAuthorization(UjoAction action, Key property, Object value) {
  switch(action.getType()) {
    case ACTION_XML_EXPORT:
      return property!=NAME;
    default: {
      return super.readAuthorization(action, property, value);
    }
  }
}
Notice: because all the Keys of the UJO object are the final type, it is not necessary to compare by the equals() method, but it is possible to use a quicker operator ==.

The attributes

The Ujorm enables to write some keys like a XML attribute of the element contrary of the XML child element (it is a default feature). The solution is to use an annotation @XmlAttribute by next sample:
@XmlAttribute
public static final Key<Ujo,String> NAME = newKey();

Body value

There is possible print the a one property value per object like an element body text. For the purpose is designed an annotation @XmlElementBody by next sample:
@@XmlElementBody
public static final Key<Ujo,String> MALE = newKey();
A content of the new XML file using both annotations @XmlAttribute and @XmlElementBody is next:
<?xml version="1.0" encoding="UTF-8"?>
<body Name="Pavel Ponec">
  true
  <CASH>34.5</CASH>
</body>
Some more features:

CSV serialization

The Ujorm support a CSV serialization and deserializationm, see the simple example:
UjoManagerCSV manager = UjoManagerCSV.getInstance(UjoCSV.class);
ByteArrayOutputStream out = new ByteArrayOutputStream();

// Save the ujoList to an outputStream:
manager.saveCSV(out, UjoManagerCSV.UTF_8, ujoList, "CSV-Context");

// Restore original objects from the byte array:
InputStream is = new ByteArrayInputStream(out.toByteArray());
List<UjoCSV> result = manager.loadCSV(new Scanner(is), "CSV-Context");

// Check the first objects
assertEquals(ujoList.get(0), result.get(0));
Eeach Ujo object can disable some columns by a method "readAuthorization(..)" and an operation context (the String "CSV-Context" for the example above).

Support of the JTable component

The Ujorm contains a support for the UJO object list displaying in the JTable. For simple editable table creating it´s not necessary to create any new class, you can only create the UjoTableModel class instance and to set it to the JTable object using the setModel() method. Example of simple usage:
// Create a model for all attributes:
UjoTableModel<Person> model = new UjoTableModel(Person.NAME, Person.MALE, Person.BIRTH);
// or simply: ... model = new UjoTableModel(Person.class)
jTable.setModel(model);
// We can set an data optionally: List<Person> persons = new ArrayList(); model.setRows(persons);
Other possibilities of the UjoTableModel class::
// Add a row:
model.addRow(new Person());
// Set a value: model.setValueAt("Prokop", 0, Person.NAME );
// Get the last row of table: Person person = model.getRowLast();
// Sort the model: model.sort(Person.NAME); // or descending: model.sort(Person.NAME.descending());

Confrontation with the AbstractTableModel

For creating a new editable table data model you have to implement or overwrite a few methods of the AbstractTableModel abstract class. All of these methods in the UjoTableModel class you´ll get implemented yet. A name of the column and corresponding class are taken straightly from the Key object, a column list inputs in constructor.

Stream searching

Framework provides a special tool for a very fast searching in a stream using the class RingBuffer. The static methods of this class allow you to search the contents placed between the two texts. See the next sample:
    final Reader reader = RingBuffer.createReader("xxx ${abc} ${def} zzz");

    String word1 = RingBuffer.findWord(reader, "${", "}");
    assertEquals("abc", word1);

    String word2 = RingBuffer.findWord(reader, "${", "}");
    assertEquals("def", word2);

    String word3 = RingBuffer.findWord(reader, "${", "}");
    assertEquals("", word3);

Object-relation mapping (ORM)

The object-relation mapping (ORM) is a bridge between the object word and the relation database. Some features: See a special page for more information.

Ujo inheritance

An inheritance of the UJO clasess are supported along the the next examples:
public class PersonExt extends Person {
  private static final KeyFactory<Person> f = newFactory(PersonExt.class);

  public static final Key<PersonExt,Float> WEIGHT = f.newKey();
  public static final Key<PersonExt,Date > BORN   = f.newKey();

  @Override public KeyList<?> readKeys() {
      return f.getKeys();
  }
}
Or the similar example without the class KeyFactory for a child of the class SmartUjo:
public class PersonExt extends Person {

  public static final Key<PersonExt,Float> WEIGHT = newKey();
  public static final Key<PersonExt,Date > BORN   = newKey();
}

Performance

The processing performance of the UJO objects is dependent on the implementation. During the processing of the AbstractUjo type object is performance (writing/reading) approximately consistent with the operations writing/reading of the HashMap object. The ArrayUjo solution provides the quicker implementation, the JavaBean object is the speediest.

There are the results of a simple mensuration in the following table.
Environment: Windows XP system, Intel DuoCore 1.66 MHz processor, 1GB RAM, JRE 6.0, Ujorm 0.80.
The test description:
Implementation Performance
[sec per 5M loops]
Ratio
[%]
ArrayUjo 1.972 177
MapUjo 6.651 597
BeanUjo 20.995 1883
JavaBean 1.115 100
It´s evidently from the table, that the performance of the ArrayUjo implementation is high and it gets near to the JavaBeans object performance. The results can be affected in some cases by costs of making an instance of a primitive values. However the speed of JavaBeans dramatically drops near to BeanUjo value in case a property access via Java reflection tools.

The XML serialization of UJO objects is based on a quick SAX parser, performance tests are very favorable, mainly a comparison to XML serialization implemented in JER (classes XMLEncoder, XMLDecoder).

A measurement was provided on the same PC like the last test (UJO release 0.84), all results are shown in next table.
A test description:

Implementation Time of serialization
[sec]
Time of deserialization
[sec]
Total ratio
[%]
ArrayUjo 0.332 0.305 93
MapUjo 0.340 0.340 99
BeanUjo 0.375 0.336 104
XMLEncoder 2.797 1.770 668
JAXB 0.211 0.473 100

Conclusion: The XML serialization implemented in Ujorm is approximately six times faster in comparison with the XMLEncoder persistence implemented in JRE 6.0. The UJO speed of serialization is slightly smaller than the speed of the great JAXB framework, however all UJO implementations got a the shortest time of deserialization.

Other possibilities of usage?

What are the other possibilities of usage?

Commons

Persistence

Servlet

The UJO usage in servlets is not described in detail yet, but the basic idea for the text characteristics processing of the ServletRequest object is circa here:
ServletRequest request;
UjoTextable person;
Key personName;
...
person.writeValueString(personName, request.getParameters(personName.getName());

Referential Application

The jWorkSheet is a referential implementation of the framework. This Swing project is powered by the Ujorm. It is published under an open license on a home page http://jworksheet.ponec.net/. The jWorkSheet is an application for time tracking different projects.
You can study the usage of the UJO object persistence and its collaboration with a graphics component JTable on the source codes. The jWorkSheet application characteristics::
The jWorkSheet project is written in Java 5.0, the development was realized by the NetBeans IDE.
 
PekiLine - the desktop application manages your personal (English) vocabulary to learn.

Where ?

The project home page: http://ujorm.org/
Referential implementation: http://jworksheet.ponec.net/. Another implementations: (here can be referenced your project).

License

The code was released under the Apache License, Version 2.0.

Copyright 2007-2014 Pavel Ponec Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

FAQ

See the Wiki tutorial for more information.

Release notes

See a detail release notes in a text format for more information.
 

Copyright 2013, Pavel Ponec