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 java.text.SimpleDateFormat;
22  import java.util.Date;
23  import java.util.Locale;
24  import java.util.ResourceBundle;
25  
26  import org.apache.commons.lang.builder.ToStringBuilder;
27  import org.apache.log4j.Logger;
28  import org.itracker.core.resources.ITrackerResources;
29  import org.itracker.model.CustomField.Type;
30  import org.itracker.services.exceptions.IssueException;
31  
32  /**
33   * A CustomField with its value for an Issue.
34   * 
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  	 * 
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
143 	 *            the locale used for any string formatting
144 	 * @return the current value of this field
145 	 */
146 	public String getValue(Locale locale) {
147 		// only date fields are currently localizable
148 		if (getCustomField().getFieldType() == Type.DATE) {
149 			return getValue(ITrackerResources.getBundle(locale));
150 		} else if (getCustomField().getFieldType() == Type.INTEGER) {
151 			return String.valueOf(getIntValue());
152 		}
153 		return getStringValue();
154 
155 	}
156 
157 	/**
158 	 * Gets the custom field value as a String.
159 	 * 
160 	 * @param bundle
161 	 *            a resource bundle to use for any string formatting
162 	 * @param locale
163 	 *            a locale to use for any string formatting
164 	 * @return the current value of this field
165 	 * @deprecated use getValue(ResourceBundle bundle) instead, locale is taken
166 	 *             from bundle
167 	 * 
168 	 */
169 	public String getValue(ResourceBundle bundle, Locale locale) {
170 		if (log.isDebugEnabled()) {
171 			log.debug("getValue: called with bundle: " + bundle + ", locale: "
172 					+ locale);
173 		}
174 		return getValue(bundle);
175 	}
176 
177 	/**
178 	 * Gets the custom field value as a String.
179 	 * 
180 	 * @param bundle
181 	 *            a resource bundle to use for any string formatting
182 	 * @return the current value of this field
183 	 * @deprecated this can not be in the entity, replace by Utility or service.
184 	 */
185 	public String getValue(ResourceBundle bundle) {
186 
187 		// skip this code, it's not approved
188 		Locale locale = bundle.getLocale();
189 
190 		if (log.isDebugEnabled()) {
191 			log.debug("getValue: called with bundle: " + bundle + ", locale: "
192 					+ locale);
193 		}
194 		switch (customField.getFieldType()) {
195 
196 		case INTEGER:
197 			if (log.isDebugEnabled()) {
198 				log
199 						.debug("getValue: type was INTEGER, value: "
200 								+ this.intValue);
201 			}
202 			return String.valueOf(this.intValue);
203 
204 		case DATE:
205 			if (log.isDebugEnabled()) {
206 				log.debug("getValue: type was DATE, value: " + this.dateValue);
207 			}
208 			if (!customField.isRequired() && this.dateValue == null) {
209 
210 				if (log.isDebugEnabled()) {
211 					log.debug("getValue: value was null and not required");
212 				}
213 				return null;
214 			}
215 			if (this.dateValue == null) {
216 				this.dateValue = new Date();
217 			}
218 			return formatDate(bundle);
219 		default:
220 			return this.stringValue;
221 		}
222 
223 	}
224 
225 	private String formatDate(ResourceBundle bundle) {
226 		assert (dateValue!= null): "dateValue failed";
227 		try {
228 
229 			SimpleDateFormat sdf =
230 				new SimpleDateFormat(bundle
231 						.getString("itracker.dateformat."
232 								+ customField.getDateFormat()), bundle.getLocale());
233 
234 			if (log.isDebugEnabled()) {
235 				log.debug("getValue: dateFormat from itracker configuration "
236 						+ sdf.toPattern());
237 			}
238 			
239 			// sdf = new SimpleDateFormat(dateFormat, locale);
240 			String formattedDate = sdf.format(this.dateValue);
241 			if (log.isDebugEnabled()) {
242 				log.debug("getValue: formated date " + this.dateValue
243 						+ " to " + formattedDate);
244 			}
245 			return formattedDate;
246 		} catch (NullPointerException ne) {
247 			log.debug("getValue: ", ne);
248 			if (dateValue == null) {
249 				log.warn("getValue: failed to format date, null for "
250 						+ customField);
251 			}
252 			return "";
253 		}
254 	}
255 
256 	/**
257 	 * Sets the custom field value.
258 	 * 
259 	 * <p>
260 	 * Takes a string and then converts the value to the appropriate type based
261 	 * on the defined field type.
262 	 * </p>
263 	 * 
264 	 * TODO : throw IllegalArgumentException instead of IssueException ?
265 	 * 
266 	 * @param value
267 	 *            the value to set this field to as a string
268 	 * @param locale
269 	 *            the locale used for any string formatting
270 	 * @param bundle
271 	 *            the ResourceBundle used for any string formatting
272 	 * @throws IssueException
273 	 *             represents an error formatting or parsing the value
274 	 * 
275 	 * @deprecated locale is redundant set, in bundle and as separate parameter.
276 	 *             use {@link IssueField#setValue(String, ResourceBundle)}
277 	 *             instead
278 	 */
279 	public void setValue(String value, Locale locale, ResourceBundle bundle)
280 			throws IssueException {
281 		this.stringValue = null;
282 		this.intValue = 0;
283 		this.dateValue = null;
284 		
285 		if (value != null && value.trim().length() > 0) {
286 			switch (customField.getFieldType()) {
287 
288 			case INTEGER:
289 				setStringValue(value);
290 				try {
291 					setIntValue(Integer.parseInt(value));
292 				} catch (NumberFormatException nfe) {
293 					throw new IssueException("Invalid integer.",
294 							IssueException.TYPE_CF_PARSE_NUM);
295 				}
296 				break;
297 
298 			case DATE:
299 				setStringValue(value);
300 				try {
301 					if (null == locale) {
302 						locale = bundle.getLocale();
303 					}
304 					SimpleDateFormat sdf = // CustomField.DEFAULT_DATE_FORMAT;
305 					new SimpleDateFormat(bundle
306 							.getString("itracker.dateformat."
307 									+ customField.getDateFormat()), locale);
308 
309 					Date dateValue = sdf.parse(value);
310 					if (dateValue != null) {
311 						setDateValue(dateValue);
312 					} else {
313 						log.error("setValue: caught exception for date "
314 								+ value);
315 						throw new IssueException("Invalid date.",
316 								IssueException.TYPE_CF_PARSE_DATE);
317 					}
318 				} catch (Exception ex) {
319 					log.error("setValue: caught exception for date " + value,
320 							ex);
321 					throw new IssueException("Invalid date format.",
322 							IssueException.TYPE_CF_PARSE_DATE);
323 				}
324 				break;
325 
326 			default:
327 				setStringValue(value);
328 			}
329 
330 		} else {
331 			// reset value
332 			setStringValue("");
333 			setDateValue(null);
334 			setIntValue(0);
335 		}
336 	}
337 
338 	/**
339 	 * Sets the custom field value.
340 	 * 
341 	 * <p>
342 	 * Takes a string and then converts the value to the appropriate type based
343 	 * on the defined field type.
344 	 * </p>
345 	 * 
346 	 * TODO : throw IllegalArgumentException instead of IssueException ?
347 	 * 
348 	 * @param value
349 	 *            the value to set this field to as a string
350 	 * @param bundle
351 	 *            the ResourceBundle used for any string formatting
352 	 * @throws IssueException
353 	 *             represents an error formatting or parsing the value
354 	 * 
355 	 */
356 	public void setValue(String value, ResourceBundle bundle)
357 			throws IssueException {
358 		setValue(value, bundle.getLocale(), bundle);
359 	}
360 
361 	@Override
362 	public String toString() {
363 		return new ToStringBuilder(this).append("id", getId()).append("issue",
364 				getIssue()).append("customField", getCustomField()).toString();
365 	}
366 
367 }