EMMA Coverage Report (generated Tue Dec 09 03:51:57 CET 2014)
[all classes][org.jdtaus.banking]

COVERAGE SUMMARY FOR SOURCE FILE [AlphaNumericText27.java]

nameclass, %method, %block, %line, %
AlphaNumericText27.java100% (1/1)74%  (14/19)70%  (297/426)69%  (57.2/83)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class AlphaNumericText27100% (1/1)74%  (14/19)70%  (297/426)69%  (57.2/83)
format (StringBuffer): StringBuffer 0%   (0/1)0%   (0/12)0%   (0/3)
normalize (String): String 0%   (0/1)0%   (0/45)0%   (0/9)
subSequence (int, int): CharSequence 0%   (0/1)0%   (0/6)0%   (0/1)
toString (AlphaNumericText27): String 0%   (0/1)0%   (0/10)0%   (0/3)
valueOf (String): AlphaNumericText27 0%   (0/1)0%   (0/12)0%   (0/3)
AlphaNumericText27 (String): void 100% (1/1)68%  (21/31)75%  (6/8)
hashCode (): int 100% (1/1)78%  (7/9)77%  (0.8/1)
equals (Object): boolean 100% (1/1)79%  (26/33)93%  (4.6/5)
compareTo (Object): int 100% (1/1)80%  (40/50)89%  (9.8/11)
parse (String, ParsePosition): AlphaNumericText27 100% (1/1)84%  (52/62)88%  (15/17)
parse (String): AlphaNumericText27 100% (1/1)91%  (50/55)90%  (9/10)
<static initializer> 100% (1/1)100% (6/6)100% (1/1)
charAt (int): char 100% (1/1)100% (5/5)100% (1/1)
checkAlphaNumeric (char): boolean 100% (1/1)100% (58/58)100% (1/1)
format (): String 100% (1/1)100% (3/3)100% (1/1)
getCache (): Map 100% (1/1)100% (19/19)100% (5/5)
isEmpty (): boolean 100% (1/1)100% (3/3)100% (1/1)
length (): int 100% (1/1)100% (4/4)100% (1/1)
toString (): String 100% (1/1)100% (3/3)100% (1/1)

1/*
2 *  jDTAUS Banking API
3 *  Copyright (C) 2005 Christian Schulte
4 *  <cs@schulte.it>
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2.1 of the License, or any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 *
20 */
21package org.jdtaus.banking;
22 
23import java.io.Serializable;
24import java.lang.ref.Reference;
25import java.lang.ref.SoftReference;
26import java.text.ParseException;
27import java.text.ParsePosition;
28import java.util.Collections;
29import java.util.HashMap;
30import java.util.Map;
31 
32/**
33 * Alpha numeric text with a maximum length of twenty seven characters.
34 * <p>Data type for the alpha-numeric DTAUS alphabet. For further information
35 * see the <a href="../../../doc-files/Anlage3_Datenformate_V2.7.pdf">
36 * Spezifikation der Datenformate</a>. An updated version of the document may be found at
37 * <a href="http://www.ebics.de">EBICS</a>.</p>
38 *
39 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
40 * @version $JDTAUS: AlphaNumericText27.java 8860 2014-01-10 17:09:37Z schulte $
41 */
42public final class AlphaNumericText27 implements CharSequence, Comparable, Serializable
43{
44 
45    /** Serial version UID for backwards compatibility with 1.0.x classes. */
46    private static final long serialVersionUID = -5231830564347967536L;
47 
48    /** Used to cache instances. */
49    private static volatile Reference cacheReference = new SoftReference( null );
50 
51    /** Constant for the maximum length allowed for an instance. */
52    public static final int MAX_LENGTH = 27;
53 
54    /**
55     * The alpha-numeric text.
56     * @serial
57     */
58    private String text;
59 
60    /**
61     * Flag indicating that {@code text} contains no text.
62     * @serial
63     */
64    private boolean empty;
65 
66    /**
67     * Creates a new {@code AlphaNumericText27} instance holding {@code text}.
68     *
69     * @param text The text for the instance.
70     *
71     * @throws NullPointerException if {@code text} is {@code null}.
72     * @throws IllegalArgumentException if the length of {@code text} is greater than {@code MAX_LENGTH}.
73     *
74     * @see #parse(String, ParsePosition)
75     */
76    private AlphaNumericText27( final String text )
77    {
78        if ( text == null )
79        {
80            throw new NullPointerException( "text" );
81        }
82        if ( text.length() > MAX_LENGTH )
83        {
84            throw new IllegalArgumentException( text );
85        }
86 
87        this.text = text;
88        this.empty = text.trim().length() == 0;
89    }
90 
91    /**
92     * Parses text from a string to produce an {@code AlphaNumericText27} instance.
93     * <p>The method attempts to parse text starting at the index given by {@code pos}. If parsing succeeds, then the
94     * index of {@code pos} is updated to the index after the last character used (parsing does not necessarily use all
95     * characters up to the end of the string), and the parsed value is returned. The updated {@code pos} can be used to
96     * indicate the starting point for the next call to this method.</p>
97     *
98     * @param text A string to parse alpha numeric characters from.
99     * @param pos A {@code ParsePosition} object with index and error index information as described above.
100     *
101     * @return The parsed value, or {@code null} if the parse fails.
102     *
103     * @throws NullPointerException if either {@code text} or {@code pos} is {@code null}.
104     */
105    public static AlphaNumericText27 parse( final String text, final ParsePosition pos )
106    {
107        if ( text == null )
108        {
109            throw new NullPointerException( "text" );
110        }
111        if ( pos == null )
112        {
113            throw new NullPointerException( "pos" );
114        }
115 
116        int i;
117        boolean valid = true;
118        AlphaNumericText27 ret = null;
119        final int beginIndex = pos.getIndex();
120        final int len = text.length();
121 
122        for ( i = beginIndex; i < beginIndex + MAX_LENGTH && i < len; i++ )
123        {
124            if ( !AlphaNumericText27.checkAlphaNumeric( text.charAt( i ) ) )
125            {
126                pos.setErrorIndex( i );
127                valid = false;
128                break;
129            }
130        }
131 
132        if ( valid )
133        {
134            pos.setIndex( i );
135            ret = new AlphaNumericText27( text.substring( beginIndex, i ) );
136        }
137 
138        return ret;
139    }
140 
141    /**
142     * Parses text from the beginning of the given string to produce an {@code AlphaNumericText27} instance.
143     * <p>Unlike the {@link #parse(String, ParsePosition)} method this method throws a {@code ParseException} if
144     * {@code text} cannot be parsed or is of invalid length.</p>
145     *
146     * @param text A string to parse alpha numeric characters from.
147     *
148     * @return The parsed value.
149     *
150     * @throws NullPointerException if {@code text} is {@code null}.
151     * @throws ParseException if the parse fails or the length of {@code text} is greater than {@code 27}.
152     */
153    public static AlphaNumericText27 parse( final String text ) throws ParseException
154    {
155        if ( text == null )
156        {
157            throw new NullPointerException( "text" );
158        }
159 
160        AlphaNumericText27 txt = (AlphaNumericText27) getCache().get( text );
161 
162        if ( txt == null )
163        {
164            final ParsePosition pos = new ParsePosition( 0 );
165            txt = AlphaNumericText27.parse( text, pos );
166 
167            if ( txt == null || pos.getErrorIndex() != -1 || pos.getIndex() < text.length() )
168            {
169                throw new ParseException( text, pos.getErrorIndex() != -1 ? pos.getErrorIndex() : pos.getIndex() );
170            }
171            else
172            {
173                getCache().put( text, txt );
174            }
175        }
176 
177        return txt;
178    }
179 
180    /**
181     * Parses text from the beginning of the given string to produce an {@code AlphaNumericText27} instance.
182     * <p>Unlike the {@link #parse(String)} method this method throws an {@code IllegalArgumentException} if
183     * {@code text} cannot be parsed or is of invalid length.</p>
184     *
185     * @param text A formatted string representation of an {@code AlphaNumericText27} instance.
186     *
187     * @return The parsed value.
188     *
189     * @throws NullPointerException if {@code text} is {@code null}.
190     * @throws IllegalArgumentException if the parse fails or the length of {@code text} is greater than {@code 27}.
191     */
192    public static AlphaNumericText27 valueOf( final String text )
193    {
194        try
195        {
196            return AlphaNumericText27.parse( text );
197        }
198        catch ( final ParseException e )
199        {
200            throw (IllegalArgumentException) new IllegalArgumentException( text ).initCause( e );
201        }
202    }
203 
204    /**
205     * Formats alpha-numeric characters and appends the resulting text to the given string buffer.
206     *
207     * @param toAppendTo The buffer to which the formatted text is to be appended.
208     *
209     * @return The value passed in as {@code toAppendTo}.
210     *
211     * @throws NullPointerException if {@code toAppendTo} is {@code null}.
212     */
213    public StringBuffer format( final StringBuffer toAppendTo )
214    {
215        if ( toAppendTo == null )
216        {
217            throw new NullPointerException( "toAppendTo" );
218        }
219 
220        return toAppendTo.append( this.text );
221    }
222 
223    /**
224     * Formats alpha-numeric characters to produce a string. Same as
225     * <blockquote>
226     * {@link #format(StringBuffer) format<code>(new StringBuffer()).toString()</code>}
227     * </blockquote>
228     *
229     * @return The formatted string.
230     */
231    public String format()
232    {
233        return this.text;
234    }
235 
236    /**
237     * Formats alpha-numeric characters to produce a string. Same as
238     * <blockquote>
239     * {@link #format() alphaNumericText27.format()}
240     * </blockquote>
241     *
242     * @param alphaNumericText27 The {@code AlphaNumericText27} instance to format.
243     *
244     * @return The formatted string.
245     *
246     * @throws NullPointerException if {@code alphaNumericText27} is {@code null}.
247     */
248    public static String toString( final AlphaNumericText27 alphaNumericText27 )
249    {
250        if ( alphaNumericText27 == null )
251        {
252            throw new NullPointerException( "alphaNumericText27" );
253        }
254 
255        return alphaNumericText27.format();
256    }
257 
258    /**
259     * Checks a given character to belong to the alpha-numeric alphabet.
260     *
261     * @param c The character to check.
262     *
263     * @return {@code true} if {@code c} is a character of the alpha-numeric DTAUS alphabet; {@code false} if not.
264     */
265    public static boolean checkAlphaNumeric( final char c )
266    {
267        return ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) ||
268               ( c == '.' || c == '+' || c == '*' || c == '$' || c == ' ' || c == ',' || c == '&' || c == '-' ||
269                 c == '/' || c == '%' || c == 'Ä' || c == 'Ö' || c == 'Ü' || c == 'ß' );
270 
271    }
272 
273    /**
274     * Normalizes text to conform to the alpha-numeric alphabet.
275     * <p>This method converts lower case letters to upper case letters and replaces all illegal characters with spaces.
276     * It will return the unchanged text if for every given character {@code C} the method {@code checkAlphaNumeric(C)}
277     * returns {@code true}.</p>
278     * <p>Note that code like
279     * <blockquote><code>
280     * AlphaNumericText27.parse(AlphaNumericText27.normalize(getSomething()));
281     * </code></blockquote>
282     * may be dangerous if {@code getSomething()} may provide unchecked or otherwise invalid data which will get
283     * converted to valid data by this method.</p>
284     * <p>Also note that
285     * <blockquote><code>
286     * AlphaNumericText27.normalize(<i>something</i>).length() == <i>something</i>.length();
287     * </code></blockquote>
288     * is always {@code true} although
289     * <blockquote><code>
290     * AlphaNumericText27.normalize(<i>something</i>).equals(<i>something</i>);
291     * </code></blockquote> may be {@code false}.</p>
292     * <p>It is recommended to always check for changes before proceeding with the data this method returns.
293     * For example:
294     * <blockquote><pre>
295     * something = getSomething();
296     * normalized = AlphaNumericText27.normalize(something);
297     * if(!something.equals(normalized)) {
298     *
299     *     <i>e.g. check the normalized value, log a warning, display the
300     *     normalized value to the user for confirmation</i>
301     *
302     * }</pre></blockquote></p>
303     *
304     * @param text The text to normalize.
305     *
306     * @return {@code text} normalized to conform to the alpha-numeric alphabet.
307     *
308     * @throws NullPointerException if {@code text} is {@code null}.
309     */
310    public static String normalize( final String text )
311    {
312        if ( text == null )
313        {
314            throw new NullPointerException( "text" );
315        }
316 
317        final char[] ret = text.toCharArray();
318 
319        for ( int i = ret.length - 1; i >= 0; i-- )
320        {
321            if ( Character.isLowerCase( ret[i] ) )
322            {
323                ret[i] = Character.toUpperCase( ret[i] );
324            }
325 
326            if ( !AlphaNumericText27.checkAlphaNumeric( ret[i] ) )
327            {
328                ret[i] = ' ';
329            }
330        }
331 
332        return new String( ret );
333    }
334 
335    /**
336     * Flag indicating that the instance contains no text.
337     *
338     * @return {@code true} if the instance contains no text but just whitespace characters; {@code false} if the
339     * instance contains text.
340     */
341    public boolean isEmpty()
342    {
343        return this.empty;
344    }
345 
346    /**
347     * Gets the current cache instance.
348     *
349     * @return Current cache instance.
350     */
351    private static Map getCache()
352    {
353        Map cache = (Map) cacheReference.get();
354        if ( cache == null )
355        {
356            cache = Collections.synchronizedMap( new HashMap( 1024 ) );
357            cacheReference = new SoftReference( cache );
358        }
359 
360        return cache;
361    }
362 
363    /**
364     * Returns the length of this character sequence.  The length is the number of 16-bit {@code char}s in the sequence.
365     *
366     * @return The number of {@code char}s in this sequence.
367     */
368    public int length()
369    {
370        return this.text.length();
371    }
372 
373    /**
374     * Returns the {@code char} value at the specified index.
375     * <p>An index ranges from zero to {@code length() - 1}. The first {@code char} value of the sequence is at index
376     * zero, the next at index one, and so on, as for array indexing.</p>
377     *
378     * @param index The index of the {@code char} value to be returned.
379     *
380     * @return The specified {@code char} value.
381     *
382     * @throws IndexOutOfBoundsException if {@code index} is negative or not less than {@code length()}.
383     */
384    public char charAt( final int index )
385    {
386        return this.text.charAt( index );
387    }
388 
389    /**
390     * Returns a new {@code CharSequence} that is a subsequence of this sequence.
391     * <p>The subsequence starts with the {@code char} value at the specified index and ends with the {@code char} value
392     * at index {@code end - 1}. The length (in {@code char}s) of the returned sequence is {@code end - start}, so if
393     * {@code start == end} then an empty sequence is returned.</p>
394     *
395     * @param start The start index, inclusive.
396     * @param end The end index, exclusive.
397     *
398     * @return The specified subsequence.
399     *
400     * @throws  IndexOutOfBoundsException if {@code start} or {@code end} are negative, if {@code end} is greater than
401     * {@code length()}, or if {@code start} is greater than {@code end}.
402     */
403    public CharSequence subSequence( final int start, final int end )
404    {
405        return this.text.subSequence( start, end );
406    }
407 
408    /**
409     * Returns a string containing the characters in this sequence in the same order as this sequence. The length of the
410     * string will be the length of this sequence.
411     *
412     * @return A string consisting of exactly this sequence of characters.
413     */
414    public String toString()
415    {
416        return this.text;
417    }
418 
419    /**
420     * Compares this object with the specified object for order.  Returns a negative integer, zero, or a positive
421     * integer as this object is less than, equal to, or greater than the specified object.
422     *
423     * @param o The Object to be compared.
424     * @return A negative integer, zero, or a positive integer as this object is less than, equal to, or greater than
425     * the specified object.
426     *
427     * @throws NullPointerException if {@code o} is {@code null}.
428     * @throws ClassCastException if the specified object's type prevents it from being compared to this Object.
429     */
430    public int compareTo( final Object o )
431    {
432        if ( o == null )
433        {
434            throw new NullPointerException( "o" );
435        }
436        if ( !( o instanceof AlphaNumericText27 ) )
437        {
438            throw new ClassCastException( o.getClass().getName() );
439        }
440 
441        final AlphaNumericText27 that = (AlphaNumericText27) o;
442 
443        int result = 0;
444 
445        if ( !this.equals( o ) )
446        {
447            if ( this.text == null )
448            {
449                result = that.text == null ? 0 : -1;
450            }
451            else
452            {
453                result = that.text == null ? 1 : this.text.compareTo( that.text );
454            }
455        }
456 
457        return result;
458    }
459 
460    /**
461     * Indicates whether some other object is equal to this one.
462     *
463     * @param o The reference object with which to compare.
464     *
465     * @return {@code true} if this object is the same as {@code o}; {@code false} otherwise.
466     */
467    public boolean equals( final Object o )
468    {
469        boolean ret = o == this;
470 
471        if ( !ret && o instanceof AlphaNumericText27 )
472        {
473            final AlphaNumericText27 that = (AlphaNumericText27) o;
474            ret = this.text == null ? that.text == null : this.text.equals( that.text );
475        }
476 
477        return ret;
478    }
479 
480    /**
481     * Returns a hash code value for this object.
482     *
483     * @return A hash code value for this object.
484     */
485    public int hashCode()
486    {
487        return this.text == null ? 0 : this.text.hashCode();
488    }
489 
490}

[all classes][org.jdtaus.banking]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov