View Javadoc
1   /*
2    * This software was designed and created by Jason Carroll.
3    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
4    * The author can be reached at jcarroll@cowsultants.com
5    * ITracker website: http://www.cowsultants.com
6    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
7    *
8    * This program is free software; you can redistribute it and/or modify
9    * it only under the terms of the GNU General Public License as published by
10   * the Free Software Foundation; either version 2 of the License, or
11   * (at your option) any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   */
18  
19  package org.itracker.model;
20  
21  import org.apache.commons.lang.builder.ToStringBuilder;
22  import org.apache.log4j.Logger;
23  import org.itracker.IssueException;
24  import org.itracker.core.resources.ITrackerResources;
25  import org.itracker.model.CustomField.Type;
26  
27  import java.text.SimpleDateFormat;
28  import java.util.Date;
29  import java.util.Locale;
30  import java.util.ResourceBundle;
31  
32  /**
33   * A CustomField with its value for an Issue.
34   * <p/>
35   * <p>
36   * An IssueField can only belong to 1 Issue (composition).
37   * </p>
38   *
39   * @author ready
40   * @see CustomField
41   */
42  public class IssueField extends AbstractEntity {
43  
44      /**
45       *
46       */
47      private static final long serialVersionUID = 1L;
48  
49      private static transient final Logger log = Logger
50              .getLogger(IssueField.class);
51  
52      private Issue issue;
53  
54      private CustomField customField;
55  
56      private String stringValue;
57  
58      private Integer intValue;
59  
60      private Date dateValue;
61  
62      /**
63       * Default constructor (required by Hibernate).
64       * <p/>
65       * <p>
66       * PENDING: should be <code>private</code> so that it can only be used by
67       * Hibernate, to ensure that the fields which form an instance's identity
68       * are always initialized/never <tt>null</tt>.
69       * </p>
70       */
71      public IssueField() {
72      }
73  
74      public IssueField(Issue issue, CustomField field) {
75          setIssue(issue);
76          setCustomField(field);
77      }
78  
79      public Issue getIssue() {
80          return issue;
81      }
82  
83      public void setIssue(Issue issue) {
84          if (issue == null) {
85              throw new IllegalArgumentException("null issue");
86          }
87          this.issue = issue;
88      }
89  
90      public CustomField getCustomField() {
91          return customField;
92      }
93  
94      public void setCustomField(CustomField customField) {
95          if (customField == null) {
96              throw new IllegalArgumentException("null customField");
97          }
98          this.customField = customField;
99      }
100 
101     public String getStringValue() {
102         if (null != this.getCustomField() && Type.DATE == this.getCustomField().getFieldType()) {
103             this.stringValue = "";
104             if (null != this.dateValue) {
105                 String stringValue = formatDate(ITrackerResources.getBundle(ITrackerResources.BASE_LOCALE));
106                 this.stringValue = stringValue;
107             }
108         }
109         return stringValue;
110     }
111 
112     public void setStringValue(String stringValue) {
113         this.stringValue = stringValue;
114     }
115 
116     public Integer getIntValue() {
117         return intValue;
118     }
119 
120     public void setIntValue(Integer intValue) {
121         this.intValue = intValue;
122     }
123 
124     public Date getDateValue() {
125         if (null == dateValue)
126             return null;
127         return new Date(dateValue.getTime());
128     }
129 
130     public void setDateValue(Date dateValue) {
131         if (null == dateValue) {
132             this.dateValue = null;
133         } else {
134             this.dateValue = new Date(dateValue.getTime());
135             this.stringValue = formatDate(ITrackerResources.getBundle());
136         }
137     }
138 
139     /**
140      * Gets the custom field value as a String.
141      *
142      * @param locale the locale used for any string formatting
143      * @return the current value of this field
144      */
145     public String getValue(Locale locale) {
146         // only date fields are currently localizable
147         if (getCustomField().getFieldType() == Type.DATE) {
148             return getValue(ITrackerResources.getBundle(locale));
149         } else if (getCustomField().getFieldType() == Type.INTEGER) {
150             return String.valueOf(getIntValue());
151         }
152         return getStringValue();
153 
154     }
155 
156     /**
157      * Gets the custom field value as a String.
158      *
159      * @param bundle a resource bundle to use for any string formatting
160      * @param locale a locale to use for any string formatting
161      * @return the current value of this field
162      * @deprecated use getValue(ResourceBundle bundle) instead, locale is taken
163      *             from bundle
164      */
165     public String getValue(ResourceBundle bundle, Locale locale) {
166         if (log.isDebugEnabled()) {
167             log.debug("getValue: called with bundle: " + bundle + ", locale: "
168                     + locale);
169         }
170         return getValue(bundle);
171     }
172 
173     /**
174      * Gets the custom field value as a String.
175      *
176      * @param bundle a resource bundle to use for any string formatting
177      * @return the current value of this field
178      * @deprecated this can not be in the entity, replace by Utility or service.
179      */
180     public String getValue(ResourceBundle bundle) {
181 
182         // skip this code, it's not approved
183         Locale locale = bundle.getLocale();
184 
185         if (log.isDebugEnabled()) {
186             log.debug("getValue: called with bundle: " + bundle + ", locale: "
187                     + locale);
188         }
189         switch (customField.getFieldType()) {
190 
191             case INTEGER:
192                 if (log.isDebugEnabled()) {
193                     log
194                             .debug("getValue: type was INTEGER, value: "
195                                     + this.intValue);
196                 }
197                 return String.valueOf(this.intValue);
198 
199             case DATE:
200                 if (log.isDebugEnabled()) {
201                     log.debug("getValue: type was DATE, value: " + this.dateValue);
202                 }
203                 if (!customField.isRequired() && this.dateValue == null) {
204 
205                     if (log.isDebugEnabled()) {
206                         log.debug("getValue: value was null and not required");
207                     }
208                     return null;
209                 }
210                 if (this.dateValue == null) {
211                     this.dateValue = new Date();
212                 }
213                 return formatDate(bundle);
214             default:
215                 return this.stringValue;
216         }
217 
218     }
219 
220     private String formatDate(ResourceBundle bundle) {
221         assert (dateValue != null) : "dateValue failed";
222         try {
223 
224             SimpleDateFormat sdf =
225                     new SimpleDateFormat(bundle
226                             .getString("itracker.dateformat."
227                                     + customField.getDateFormat()), bundle.getLocale());
228 
229             if (log.isDebugEnabled()) {
230                 log.debug("getValue: dateFormat from itracker configuration "
231                         + sdf.toPattern());
232             }
233 
234             // sdf = new SimpleDateFormat(dateFormat, locale);
235             String formattedDate = sdf.format(this.dateValue);
236             if (log.isDebugEnabled()) {
237                 log.debug("getValue: formated date " + this.dateValue
238                         + " to " + formattedDate);
239             }
240             return formattedDate;
241         } catch (NullPointerException ne) {
242             log.debug("getValue: ", ne);
243             if (dateValue == null) {
244                 log.warn("getValue: failed to format date, null for "
245                         + customField);
246             }
247             return "";
248         }
249     }
250 
251     /**
252      * Sets the custom field value.
253      * <p/>
254      * <p>
255      * Takes a string and then converts the value to the appropriate type based
256      * on the defined field type.
257      * </p>
258      * <p/>
259      * TODO : throw IllegalArgumentException instead of IssueException ?
260      *
261      * @param value  the value to set this field to as a string
262      * @param locale the locale used for any string formatting
263      * @param bundle the ResourceBundle used for any string formatting
264      * @throws org.itracker.IssueException represents an error formatting or parsing the value
265      * @deprecated locale is redundant set, in bundle and as separate parameter.
266      *             use {@link IssueField#setValue(String, ResourceBundle)}
267      *             instead
268      */
269     public void setValue(String value, Locale locale, ResourceBundle bundle)
270             throws IssueException {
271         this.stringValue = null;
272         this.intValue = 0;
273         this.dateValue = null;
274 
275         if (value != null && value.trim().length() > 0) {
276             switch (customField.getFieldType()) {
277 
278                 case INTEGER:
279                     setStringValue(value);
280                     try {
281                         setIntValue(Integer.parseInt(value));
282                     } catch (NumberFormatException nfe) {
283                         throw new IssueException("Invalid integer.",
284                                 IssueException.TYPE_CF_PARSE_NUM);
285                     }
286                     break;
287 
288                 case DATE:
289                     setStringValue(value);
290                     try {
291                         if (null == locale) {
292                             locale = bundle.getLocale();
293                         }
294                         SimpleDateFormat sdf = // CustomField.DEFAULT_DATE_FORMAT;
295                                 new SimpleDateFormat(bundle
296                                         .getString("itracker.dateformat."
297                                                 + customField.getDateFormat()), locale);
298 
299                         Date dateValue = sdf.parse(value);
300                         if (dateValue != null) {
301                             setDateValue(dateValue);
302                         } else {
303                             log.error("setValue: caught exception for date "
304                                     + value);
305                             throw new IssueException("Invalid date.",
306                                     IssueException.TYPE_CF_PARSE_DATE);
307                         }
308                     } catch (Exception ex) {
309                         log.error("setValue: caught exception for date " + value,
310                                 ex);
311                         throw new IssueException("Invalid date format.",
312                                 IssueException.TYPE_CF_PARSE_DATE);
313                     }
314                     break;
315 
316                 default:
317                     setStringValue(value);
318             }
319 
320         } else {
321             // reset value
322             setStringValue("");
323             setDateValue(null);
324             setIntValue(0);
325         }
326     }
327 
328     /**
329      * Sets the custom field value.
330      * <p/>
331      * <p>
332      * Takes a string and then converts the value to the appropriate type based
333      * on the defined field type.
334      * </p>
335      * <p/>
336      * TODO : throw IllegalArgumentException instead of IssueException ?
337      *
338      * @param value  the value to set this field to as a string
339      * @param bundle the ResourceBundle used for any string formatting
340      * @throws IssueException represents an error formatting or parsing the value
341      */
342     public void setValue(String value, ResourceBundle bundle)
343             throws IssueException {
344         setValue(value, bundle.getLocale(), bundle);
345     }
346 
347     @Override
348     public String toString() {
349         return new ToStringBuilder(this).append("id", getId()).append("issue",
350                 getIssue()).append("customField", getCustomField()).toString();
351     }
352 
353 }