Subclasses of IFmt are responsible for converting primitive XMA types (see IAtomic ) to the UI and back. The former operation is usually called formatting , the latter validation . Both operations are encapsulated in an instance of a class derived from IFmt. The next figure show the involved data-flow:
Every type defines a so called internal encoding , that's how the value is stored in widget-models and also transmitted over the wide area network between XMA client and XMA server. Every formatter is able to map the internal encoding to an external encoding , that's the string-representation how the value is displayed in the SWT-widget to the end-user.
The next interaction-diagram shows an event-flow to demonstrate how validation works in XMA:
On every keystroke, two operations are performed:
Verification: For every new
characters inserted in the UI-text-field, the methods
isLegalExternalChar() and
maxLenOfExternal() are consulted to decide if the new
characters may even be input and if the maximum length would not be
exceeded. If at least one of these checks fails, the modification is
rejected in the UI-text-field.
Modification: If the input
passes the verification-step, the input is accepted and the
UI-text-field will show the modification. However, the input may not
be valid. The XMA-Runtime calls the method IFmt.parse
to convert the external string-encoding to an internal.
parse throws an AParseException
if the input is rejected. The message-text of the
AParseException will be shown in the status-line of the dialog that
contains the erroneous field.
Formatting is the process of mapping an internal string-encoding of a supported XMA type to an UI-encoding adequate for the end-user, see the next interaction diagram:
Method IFmt.format does all the work.
Custom formatters are created by using the class FmtFactory
and providing a string-pattern. See FmtFactory
's javadoc for a list of permissible string-patterns. The
create -methods of class FmtFactory require a
string-pattern and return an object derived from
IFmt
, which is the base class for all custom formatters.
If performance is of great importance in your application, do not
use FmtFactory . Instead, create the formatters directly by
using the getInstance() -methods in the classes ABcdFmt
, ADateFmt
, AStringFmt
and ATimeStampFmt
.
The following table gives some examples of formatter-patterns, although this list is just an example. For a complete description please refer to FmtFactory .
| pattern | meaning |
| s,35 | String which must not be longer than 35 digits. |
| s,35,m | As above, but mandatory (expressed by style "m"), i.e., must not be empty. |
| sm,3,5,m | At least 3 and at most 5 characters must be entered. |
| sr,0,35,a-c | String of length not more than 35 consisting only of characters { 'a', 'b', 'c' }. |
| n,13,2,m&t | Numeric with at most 13 digits before and 2 after the dec-point, example: -1.000.000,99 in the austrian locale |
| n,inf,2,nn&m | Numeric; example: 10000000000000,99 in the austrian locale. Negative inputs are not allowed (expressed by style "nn"). The number of digits in front of the decimal separator is not limited. |
| nr,inf,0,5,596 | Integer number between 5 and 596. |
| nr,13,0,inf,596 | Integer number between -9999999999999 and 596. |
| d | Date using the format 24.04.2000 (this is Locale-dependent). |
| d,m | As above, but input is required. |
| d,m&ful | Mandatory date using the format "Montag, 24. April 2000" (expressed through style "ful"), although this is locale-dependent. |
| dr,0,7,m | Mandatory date that must lie in the range [today ... today plus 7 days]. |
| dp,dd-MM-yyyy,m | Mandatory, non-localized date format as defined
in |
Table 6.9. FmtFactory patterns
XMA provides a built-in set of formatters in the package
at.spardat.enterprise.fmt . Writing your own formatters is
usually done by subclassing one of the provided formatter-classes.
Creating your own formatter-classes is recommended if you can reuse the
formatter for many text-fields, so that the formatting/validation-code
can be shared. Suppose, numeric input should be constrained for a
particular field in a way, that only integer numbers x
having (x%1000==0) with a maximum length of 10 digits are
allowed. Then your subclass may look like that:
public class MyNumberFmt extends ABcdFmtDefault {
/**
* Constructor
*/
public MyNumberFmt (int style, Locale l) {
super (10, 0, style, l);
}
/**
* @see at.spardat.enterprise.fmt.IFmt#parse(String)
*/
public String parse (String external) throws AParseException {
/**
* Call all the validation-logic of the super-class. This call would throw an exception if something
* would went wrong.
*/
String internal = super.parse (external);
/**
* Create an Atom from the internal string
*/
Atom atom = Atom.newInstance (Types.T_BCD, internal);
if (atom.hasValue()) {
long val = (long) atom.toDouble();
if ((val%1000) != 0) throw new AParseException ("Please enter a number that divides by 1000.");
}
return internal;
}
} Conclusion: Narrowing the validation rules is accomplished
by extending method parse , but do not forget to call parse
on the superclass.