Project Report: fawkez

Packagesummary org.jcoderz.commons.types

org.jcoderz.commons.types.YearMonth

LineHitsNoteSource
1  /*
2   * $Id: YearMonth.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.types;
34  
35  import java.io.Serializable;
36  import java.util.Calendar;
37  import java.util.GregorianCalendar;
38  import java.util.TimeZone;
39  
40  import org.jcoderz.commons.ArgumentMalformedException;
41  import org.jcoderz.commons.util.Assert;
42  
43  
44  /**
45   * Encapsulates the Year Month type.
46   * Instances of this class are immutable.
47   * Years before 1 are not fully supported and might result in wrong string
48   * representations. Not parseable time zones might be ignored.
49   * @author Andreas Mandel
50   */
51  public final class YearMonth
52        implements Serializable
53  {
54     /** The name of this type. */
55     public static final String TYPE_NAME = "YearMonth";
56  
57     /** Minimum length for the year. */
58     public static final int MINIMUM_NUMBER_OF_YEAR_DIGITS = 4;
59  
60     /** Fixed length for the month. */
61     public static final int MONTH_LENGTH = 2;
62  
63     private static final int TWO_DIGIT_MONTH = 10;
64  
65     /** The <code>serialVersionUID</code>. */
66     private static final long serialVersionUID = 1L;
67  
68     private final int mYear;
69     /** Month counting from 1 (January) to 12 (December). */
70     private final int mMonth;
71  
72     // Lazy init members
73     private transient Date mEndDate;
74     private transient Date mStartDate;
75     private transient int mHashCode;
76     private transient String mString;
77     private transient Period mPeriod;
78  
79     /**
80      *
81      */
82     private YearMonth (int year, int month)
83100    {
84100       if (1 > month || month > Date.MONTH_PER_YEAR)
85        {
86100(1)         throw new ArgumentMalformedException(TYPE_NAME, String.valueOf(month),
87                 "Month must be between 1 and 12.");
88        }
89100       if (year == 0)
90        {
91100(2)         throw new ArgumentMalformedException(TYPE_NAME, String.valueOf(year),
92                 "Value of Year must not be 0.");
93        }
94100       mYear = year;
95100       mMonth = month;
96100    }
97  
98     /**
99      * Parses a valid XML representation of the gYearMonth type.
100      * The format is <tt>CCYY-MM</tt>.
101      * @param str the string representing the year month.
102      * @return a YearMonth object representing the given year month.
103      */
104     public static YearMonth fromString (String str)
105     {
106100       Assert.notNull(str, TYPE_NAME);
107        // find separating '-' char.
108100       final int minusPos = str.indexOf('-', 1);
109100       if (minusPos == -1)
110        {
111100(3)         throw new ArgumentMalformedException(TYPE_NAME, str,
112                 "MonthYear type must contain a '-' character. (CCYY-MM)");
113        }
114100       if ((minusPos + 1) < MINIMUM_NUMBER_OF_YEAR_DIGITS)
115        {
116100(4)         throw new ArgumentMalformedException(TYPE_NAME, str,
117                 "MonthYear type have at least "
118                 + MINIMUM_NUMBER_OF_YEAR_DIGITS + " digits in front of the '-' "
119                 + "character. (CCYY-MM)");
120        }
121        final int year;
122        try
123        {
124100          year = Integer.parseInt(str.substring(0, minusPos));
125        }
1260       catch (NumberFormatException ex)
127        {
1280(5)         throw new ArgumentMalformedException(TYPE_NAME, str,
129                 "Failed to parse year. (CCYY-MM)", ex);
130100       }
131100       if (str.length() - minusPos <= MONTH_LENGTH)
132        {
133100(6)         throw new ArgumentMalformedException(TYPE_NAME, str,
134                 "Month must be 2 digits long. (CCYY-MM)");
135        }
136        final int month;
137        try
138        {
139100          month = Integer.parseInt(str.substring(minusPos + 1,
140                 minusPos + 1 + MONTH_LENGTH));
141        }
142100       catch (NumberFormatException ex)
143        {
144100(7)         throw new ArgumentMalformedException(TYPE_NAME, str,
145                 "Failed to parse month. (CCYY-MM)", ex);
146100       }
147100       if (str.length() > minusPos + 1 + MONTH_LENGTH)
148        {
149           // Check timezone
150100          final String tz = str.substring(minusPos + 1 + MONTH_LENGTH);
151100          final TimeZone timeZone = TimeZone.getTimeZone(tz);
152100          if (timeZone.getRawOffset() != 0)
153           {
154100             throw new ArgumentMalformedException(TYPE_NAME, str,
155                    "Only UTC is supported as time zone, not '" + tz + "'.");
156           }
157        }
158100       return new YearMonth(year, month);
159     }
160  
161     /**
162      * Returns the valid date that represents the beginning of the
163      * month year type.
164      * The date in time is the first second in the month year.
165      * @return a date denoting the first second in the month year.
166      */
167     public Date toStartDate ()
168     {
169100       if (mStartDate == null)
170        {
171100          final Calendar cal = Calendar.getInstance(Date.TIME_ZONE);
172100          cal.setLenient(false);
173100          cal.clear();
174100          if (getYear() > 0)
175           {
176100             cal.set(getYear(), getMonth() - 1, 1);
177           }
178           else
179           {
1800             cal.set(-getYear(), getMonth() - 1, 1);
1810             cal.set(Calendar.ERA, GregorianCalendar.BC);
182           }
183100          cal.set(Calendar.DAY_OF_MONTH,
184              cal.getActualMinimum(Calendar.DAY_OF_MONTH));
185100          cal.set(Calendar.HOUR_OF_DAY,
186              cal.getActualMinimum(Calendar.HOUR_OF_DAY));
187100          cal.set(Calendar.MINUTE, cal.getActualMinimum(Calendar.MINUTE));
188100          cal.set(Calendar.SECOND, cal.getActualMinimum(Calendar.SECOND));
189100          cal.set(Calendar.MILLISECOND,
190                 cal.getActualMinimum(Calendar.MILLISECOND));
191100          mStartDate = new Date(cal.getTimeInMillis());
192        }
193100       return mStartDate;
194     }
195  
196     /**
197      * Returns the valid date that represents the end of the
198      * month year type.
199      * The date in time is the first second in the month year.
200      * @return a date denoting the first second in the month year.
201      */
202     public Date toEndDate ()
203     {
204100       if (mEndDate == null)
205        {
206100          final Calendar cal = Calendar.getInstance(Date.TIME_ZONE);
207100          cal.setLenient(false);
208100          cal.clear();
209100          if (getYear() > 0)
210           {
211100             cal.set(getYear(), getMonth() - 1, 1);
212           }
213           else
214           {
2150             cal.set(-getYear(), getMonth() - 1, 1);
2160             cal.set(Calendar.ERA, GregorianCalendar.BC);
217           }
218100          cal.set(Calendar.DAY_OF_MONTH,
219              cal.getActualMaximum(Calendar.DAY_OF_MONTH));
220100          cal.set(Calendar.HOUR_OF_DAY,
221              cal.getActualMaximum(Calendar.HOUR_OF_DAY));
222100          cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
223100          cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
224100          cal.set(Calendar.MILLISECOND,
225                 cal.getActualMaximum(Calendar.MILLISECOND));
226100          mEndDate = new Date(cal.getTimeInMillis());
227        }
228100       return mEndDate;
229     }
230  
231     /**
232      * Returns this as period from start date to end date of this
233      * YearMonth.
234      * @return a period representing the time period of this year month.
235      */
236     public Period toPeriod ()
237     {
238100       if (mPeriod == null)
239        {
240100          mPeriod = Period.createPeriod(toStartDate(), toEndDate());
241        }
242100       return mPeriod;
243     }
244  
245     /**
246      * Returns the month counting from 1 (January) to 12 (December).
247      * @return The month counting from 1 (January) to 12 (December).
248      */
249     public int getMonth ()
250     {
251100       return mMonth;
252     }
253     /**
254      * @return Returns the year.
255      */
256     public int getYear ()
257     {
258100       return mYear;
259     }
260  
261     /**
262      * Returns true if the given date is within this year/month.
263      * @param date the point in time to check.
264      * @return true if the given date is within this year/month.
265      */
266     public boolean isWithin (Date date)
267     {
2680       final long current = date.getTime();
2690       return toStartDate().getTime() <= current
270              && current <= toEndDate().getTime();
271     }
272  
273     /** {@inheritDoc} */
274     public String toString ()
275     {
276100       if (mString == null)
277        {
278           String year;
279100          if (mYear >= 0)
280           {
281100             year = Integer.toString(mYear);
282100             if (year.length() < MINIMUM_NUMBER_OF_YEAR_DIGITS)
283              {
284100(8)               year = "0000".substring(year.length()) + year;
285              }
286           }
287           else
288           {
289100             year = Integer.toString(-mYear);
290100             if (year.length() < MINIMUM_NUMBER_OF_YEAR_DIGITS)
291              {
292100(9)               year = "0000".substring(year.length()) + year;
293              }
294100(10)            year = "-" + year;
295           }
296100          if (mMonth < TWO_DIGIT_MONTH)
297           {
298100             mString = year + "-0" + Integer.toString(mMonth) + 'Z';
299           }
300           else
301           {
302100             mString = year + '-' + Integer.toString(mMonth) + 'Z';
303           }
304        }
305100       return mString;
306     }
307  
308     /** {@inheritDoc} */
309     public int hashCode ()
310     {
3110       if (mHashCode == 0)
312        {
3130          mHashCode = mYear * Date.MONTH_PER_YEAR + mMonth;
314        }
3150       return mHashCode;
316     }
317  
318     /** {@inheritDoc} */
319     public boolean equals (Object o)
320     {
321        final boolean result;
3220       if (o instanceof YearMonth)
323        {
3240          final YearMonth other = (YearMonth) o;
3250          result = other.mMonth == mMonth && other.mYear == mYear;
3260       }
327        else
328        {
3290          result = false;
330        }
3310       return result;
332     }
333  }

Findings in this File

i (11) The field org.jcoderz.commons.types.YearMonth.mEndDate is transient but isn't set by deserialization
i (12) The field org.jcoderz.commons.types.YearMonth.mHashCode is transient but isn't set by deserialization
i (13) The field org.jcoderz.commons.types.YearMonth.mPeriod is transient but isn't set by deserialization
i (14) The field org.jcoderz.commons.types.YearMonth.mStartDate is transient but isn't set by deserialization
i (15) The field org.jcoderz.commons.types.YearMonth.mString is transient but isn't set by deserialization
i (1) 86 : 0 method new org.jcoderz.commons.types.YearMonth(int, int) throws exception with static message string
i (2) 91 : 0 method new org.jcoderz.commons.types.YearMonth(int, int) throws exception with static message string
i (3) 111 : 0 method org.jcoderz.commons.types.YearMonth.fromString(String) throws exception with static message string
i (4) 116 : 0 method org.jcoderz.commons.types.YearMonth.fromString(String) throws exception with static message string
i (5) 128 : 0 method org.jcoderz.commons.types.YearMonth.fromString(String) throws exception with static message string
i (6) 133 : 0 method org.jcoderz.commons.types.YearMonth.fromString(String) throws exception with static message string
i (7) 144 : 0 method org.jcoderz.commons.types.YearMonth.fromString(String) throws exception with static message string
c (8) 284 : 16 Prefer StringBuffer over += for concatenating strings
c (9) 292 : 16 Prefer StringBuffer over += for concatenating strings
c (10) 294 : 13 Prefer StringBuffer over += for concatenating strings