Project Report: fawkez

Packagesummary org.jcoderz.commons.logging

org.jcoderz.commons.logging.WhitespaceFormat

LineHitsNoteSource
1  /*
2   * $Id: WhitespaceFormat.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons.logging;
34  
35  import java.text.FieldPosition;
36  import java.text.Format;
37  import java.text.ParsePosition;
38  import java.util.Iterator;
39  import java.nio.CharBuffer;
40  import java.util.NoSuchElementException;
41  
42  
43  /**
44   * This Formatter formats the whitespace of a string, The space char
45   * <code>'\u0020'</code> is left untouched, all other whitespace chars are
46   * replaced and compressed by exactly one space char in a row. It extends the
47   * Format type in a unsymmetric way: A formatted String cannot be parsed in a
48   * way that the result is equal to the source string.
49   * If allocated with a sub format, first the sub format is used for formatting,
50   * the rewsult will be formatted by this.
51   * In addition to the Format implementation it offers static access methods
52   * for the format functionality.
53   *
54   */
55 (1)(2)public final class WhitespaceFormat
56        extends Format
57  {
58     static final char PRESERVED_CHAR = '\u0020';
59  
60     private final Format mSubFormat;
61  
62     private static final class WhitespaceIterator
63           implements Iterator
64     {
65        private final CharBuffer mBuffer;
66  
67        /**
68         * Constructs a white space iterator fo the supplied text. Skips over
69         * initial whitespace.
70         *
71         * @param text The text which should be read line by line.
72         */
73        private WhitespaceIterator (final CharBuffer buffer)
74100       {
75100          mBuffer = buffer.duplicate();
76100          skip();
77100       }
78  
79        /** {@inheritDoc} */
80        public void remove ()
81        {
820          throw new UnsupportedOperationException();
83        }
84  
85        /** {@inheritDoc} */
86        public boolean hasNext ()
87        {
88100          return mBuffer.remaining() > 0;
89        }
90  
91        /**
92         * Gets the next character sequence up to the next whitespace char
93         * (excluding), which is not the space character <code>' '</code>.
94         * The character sequence being returned by this will never contain a
95         * whitespace char but the space char <code>'\u0020'</code>.
96         *
97         * @see java.util.Iterator#next()
98         */
99        public Object next ()
100        {
101100          if (mBuffer.remaining() <= 0)
102           {
1030             throw new NoSuchElementException();
104           }
105100          boolean wsFound = false;
106100          boolean postWsFound = false;
107  
108100          int startOfWs = 0;
109100          int endOfWs = 0;
110  
111 (3)         // CHECKME: on some platforms slice does not behave as stated in SDK
112           // api, mBuffer is simply duplicated.
113100          final CharBuffer rc = mBuffer.slice();
114100          for (int i = 0; i < mBuffer.remaining() && ! (wsFound && postWsFound);
115100                ++i)
116           {
117100             final char c = mBuffer.charAt(i);
118  
119100             if (Character.isWhitespace(c) && ! (c == PRESERVED_CHAR))
120              {
121100                if (! wsFound)
122                 {
123100                   startOfWs = i;
124                 }
125100                endOfWs = i;
126100                wsFound = true;
127100                postWsFound = false;
128              }
129              else
130              {
131100                postWsFound = true;
132              }
133           }
134100          setPositions(rc, wsFound, postWsFound, startOfWs, endOfWs);
135100          return rc;
136        }
137  
138        /**
139         * Sets the positions and limits of supplied buffer and internal buffer
140         * for the result of a next call.
141         *
142         * @param rc This buffer is returned to the <code>next()</code> caller.
143         * @param wsFound Flag denoting whether whitespace to replace has been
144         * found.
145         * @param postWsFound Flag for denoting whether chars after whitespace
146         * have been found.
147         * @param startOfWs The start index of whitespace chars to replace.
148         * @param endOfWs THe end index of teh whitespace chars to replace.
149         */
150        private void setPositions (
151              final CharBuffer rc,
152              final boolean wsFound,
153              final boolean postWsFound,
154              final int startOfWs,
155              final int endOfWs)
156        {
157100          if (wsFound)
158           {
159 (4)            // CHECKME: if slice does not work as said in the api, then position
160              // is > 0 and idx has to be added to the position to get the new
161              // limit
162100             if (rc.position() > 0)
163              {
1640                rc.limit(rc.position() + startOfWs);
165              }
166              else
167              {
168100                rc.limit(startOfWs);
169              }
170100             if (! postWsFound)
171              {
172100                mBuffer.position(mBuffer.limit());
173              }
174              else
175              {
176100                mBuffer.position(mBuffer.position() + endOfWs + 1);
177              }
178           }
179           else
180           {
181100             mBuffer.position(mBuffer.limit());
182           }
183100       }
184  
185        /**
186         * Skips over initial whitespace, which is not
187         * {@linkplain WhitespaceFormat#PRESERVED_CHAR}
188         */
189        private void skip ()
190        {
191100          boolean wsFound = false;
192100          boolean postWsFound = false;
193100(5)         boolean first = true;
194  
195100          int endOfWs = 0;
196  
197100          for (int i = 0; i < mBuffer.remaining()
198100             && ((wsFound ^ postWsFound) || first);
199100                ++i)
200           {
201100             first = false;
202100             final char c = mBuffer.charAt(i);
203  
204100             if (Character.isWhitespace(c) && ! (c == PRESERVED_CHAR))
205              {
206100                wsFound = true;
207100                endOfWs = i;
208              }
209              else
210              {
211100                postWsFound = wsFound;
212              }
213           }
214100          if (wsFound && ! postWsFound)
215           {
216              // only whitespace found
2170             mBuffer.position(mBuffer.limit());
218           }
219100          else if (wsFound)
220           {
221              // found chars after whitespace, so the following is correct
222100             mBuffer.position(mBuffer.position() + endOfWs);
223           }
224100       }
225     }
226  
227     /**
228      * Creates a new instance of this with no sub format.
229      */
230     public WhitespaceFormat ()
231     {
232100(6)      this(null);
233100    }
234  
235     /**
236      * Creates a new instance of this with the supplied sub format.
237      *
238      * @param subFormat The sub format to use for first step formatting of an
239      * object. This will be used for parsing an object as well. Might be null.
240      */
241     public WhitespaceFormat (final Format subFormat)
242100    {
243100       mSubFormat = subFormat;
244100    }
245  
246     /**
247      * Replaces and reduces whitespace in the supplied message. The resulting
248      * string will only have <code>'\u0020'</code> as white space. Any such
249      * character in the source string is left untouched, all other whitespace
250      * characters are replaced by <code>'\u0020'</code>, but with only one in a
251      * row, so, for example, a sequence of 2 line separators will be replaced
252      * by one <code>'\u0020'</code>.
253      *
254      * @param message The message in which to find and replace white space.
255      *
256      * @return String with replaced and reduced white space
257      */
258     public static String format (final String message)
259     {
260100       return format(CharBuffer.wrap(message)).toString();
261     }
262  
263     /**
264      * Replaced and reduces whitespace in the supplied character buffer.
265      *
266      * @see #format(String)
267  
268      * @param message The message buffer in which to find and replace white
269      * space.
270      *
271      * @return CharBuffer with replaced and reduced white space. This might be
272      * <code>message</code> if it does not contain whitespace to replace.
273      */
274     public static CharBuffer format (final CharBuffer message)
275     {
276100       final WhitespaceIterator iter = new WhitespaceIterator(message);
277  
278100       CharBuffer rc = null;
279100       boolean isFirst = true;
280100       boolean flip = false;
281  
282100       while (iter.hasNext())
283        {
284100          final CharBuffer cb = (CharBuffer) iter.next();
285  
286100          if (! (isFirst || (rc == null)))
287           {
288100             rc.put(PRESERVED_CHAR);
289100             rc.put(cb);
290           }
291100          else if (isFirst)
292           {
293100             isFirst = false;
294100             if ((cb.limit() == message.limit())
295                    && (cb.position() == message.position()))
296              {
297100                rc = message.duplicate();
298              }
299              else
300              {
301100                rc = CharBuffer.allocate(message.limit());
302100                rc.put(cb);
303100                flip = true;
304              }
305           }
306           else
307           {
308              // should never occur
3090(7)            throw new RuntimeException("More than one string parts and no "
310                    + "target buffer is allocated");
311           }
312100       }
313100       if (flip)
314        {
315100          rc.flip();
316        }
317100       return rc;
318     }
319  
320     /**
321      * If a sub format is set, it delegates parsing to the sub format. If no
322      * subformat is set, it takes the source string until the first whitespace
323      * char is found, which is not {@link #PRESERVED_CHAR}.
324      *
325      * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
326      */
327 (8)(9)(10)   public Object parseObject (final String source, final ParsePosition pos)
328     {
329        Object rc;
330100       if (mSubFormat == null)
331        {
332100          int i = pos.getIndex();
333100          final int len = source.length();
334100          boolean endFound = false;
335  
336100          while (i < len && ! endFound)
337           {
338100             final char c = source.charAt(i);
339100             if (Character.isWhitespace(c) && c != PRESERVED_CHAR)
340              {
341100                endFound = true;
342              }
343              else
344              {
345100                ++i;
346              }
347100          }
348100          if (endFound)
349           {
350100             rc = source.substring(pos.getIndex(), i);
351100             pos.setIndex(i);
352           }
353           else
354           {
355100             rc = source.substring(pos.getIndex());
356100             pos.setIndex(len);
357           }
358100       }
359        else
360        {
361100          rc = mSubFormat.parseObject(source, pos);
362        }
363100       return rc;
364     }
365  
366     /**
367      * If a sub format is set, it uses this to format the object and compresses
368      * the whitespace within the result.
369      * If no sub format is set, it expects a String object and compresses the
370      * whitespace on that.
371      *
372      * @param obj The object to format.
373      * @param toAppendTo The string buffer where to append to the formatted
374      * object.
375      * @param pos The field position for formatting.
376      *
377      * @return StringBuffer with formatted objects.
378      *
379      * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
380      */
381     public StringBuffer format (
382           final Object obj,
383           final StringBuffer toAppendTo,
384           final FieldPosition pos)
385     {
386100(11)      if (mSubFormat == null)
387        {
3880          if (! (obj instanceof String))
389           {
3900             throw new IllegalArgumentException("Supplied object to be formatted"
391                    + " must be a String but is "
392                    + obj.getClass().getName() + ": " + obj);
393           }
3940          toAppendTo.append(format((String) obj));
3950          if (pos != null)
396           {
3970             pos.setBeginIndex(0);
3980             pos.setEndIndex(0);
399           }
400        }
401        else
402        {
403100          StringBuffer sb = new StringBuffer();
404100          sb = mSubFormat.format(obj, sb, pos);
405100          toAppendTo.append(WhitespaceFormat.format(sb.toString()));
406        }
407100       return toAppendTo;
408     }
409  }

Findings in this File

c (1) 55 : 0 Type Javadoc comment is missing an @author tag.
d (2) 55 : 14 [serial] serializable class org.jcoderz.commons.logging.WhitespaceFormat has no definition of serialVersionUID
i (3) 111 : 0 Comment matches to-do format '(TODO|FIXME|CHECKME)'.
i (4) 159 : 0 Comment matches to-do format '(TODO|FIXME|CHECKME)'.
w (5) 193 : 0 Method org.jcoderz.commons.logging.WhitespaceFormat$WhitespaceIterator.skip() assigns a variable in a larger scope then is needed
i (6) 232 : 0 org.jcoderz.commons.logging.WhitespaceFormat is Serializable; consider declaring a serialVersionUID
i (7) 309 : 0 method org.jcoderz.commons.logging.WhitespaceFormat.format(CharBuffer) throws exception with static message string
c (8) 327 : 0 Expected an @return tag.
c (9) 327 : 44 Expected @param tag for 'source'.
c (10) 327 : 72 Expected @param tag for 'pos'.
w (11) 386 : 0 class org.jcoderz.commons.logging.WhitespaceFormat 'overloads' a method with both instance and static versions