1 /*
2 * $Source$
3 * $Revision$
4 *
5 * Copyright (C) 2000 William Chesters
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * William Chesters <williamc At paneris.org>
42 * http://paneris.org/~williamc
43 * Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44 */
45
46 package org.melati.poem;
47
48 import org.melati.poem.generated.SettingBase;
49
50 /**
51 * A setting, analageous to a Property.
52 * <p>
53 * NOTE While the underlying value is held as a String
54 * that is converted to any type.
55 *
56 * <p>
57 *
58 * Melati POEM generated, modified definition of
59 * a <code>Persistent</code> <code>Setting</code> object.
60 *
61 * <p>
62 * Description:
63 * A configurable setting for the application.
64 * </p>
65 *
66 * <table>
67 * <caption>
68 * Field summary for SQL table <code>Setting</code>
69 * </caption>
70 * <tr><th>Name</th><th>Type</th><th>Description</th></tr>
71 * <tr><td> id </td><td> Integer </td><td> The Table Row Object ID </td></tr>
72 * <tr><td> name </td><td> String </td><td> A code name for this setting
73 * </td></tr>
74 * <tr><td> value </td><td> String </td><td> The value of this setting
75 * </td></tr>
76 * </table>
77 *
78 * See org.melati.poem.prepro.TableDef#generateMainJava
79 * @author WilliamC@paneris.org
80 */
81
82 public class Setting extends SettingBase {
83 /**
84 * Constructor
85 * for a <code>Persistent</code> <code>Setting</code> object.
86 * <p>
87 * Description:
88 * A configurable setting for the application.
89 * </p>
90 *
91 * See org.melati.poem.prepro.TableDef#generateMainJava
92 */
93 public Setting() { }
94
95 // programmer's domain-specific code here
96
97 private FieldAttributes<?> valueAttributes = null;
98 private Object raw = null;
99 private Object cooked = null;
100
101 /**
102 * Constructor with reasonable defaults for a String setting
103 * Use SettingTable.create to persist this.
104 * @param typefactory The type factory integer code
105 * @param name the name of the setting
106 * @param value the string value
107 * @param displayname the name to display
108 * @param description the description to display
109 */
110 public Setting(Integer typefactory, String name, String value,
111 String displayname, String description) {
112 setTypefactory_unsafe(typefactory);
113 setName_unsafe(name);
114 setValue_unsafe(value);
115 setDisplayname_unsafe(displayname);
116 setDescription_unsafe(description);
117 setUsereditable_unsafe(Boolean.TRUE);
118 setNullable_unsafe(Boolean.TRUE);
119 setSize_unsafe(new Integer(-1));
120 setWidth_unsafe(new Integer(20));
121 setHeight_unsafe(new Integer(1));
122 setPrecision_unsafe(new Integer(22));
123 setScale_unsafe(new Integer(2));
124 }
125
126 /**
127 * Thrown when a {@link Setting} value fails validation.
128 */
129 public static class SettingValidationException extends PoemException {
130 private static final long serialVersionUID = 1L;
131
132 /** The name of the requested setting. */
133 public String name;
134
135 /** Constructor. */
136 public SettingValidationException(String name, Exception problem) {
137 super(problem);
138 this.name = name;
139 }
140
141 /** @return The detail message. */
142 public String getMessage() {
143 return "A problem arose updating the value of the `" + name +
144 "' setting:\n" + subException.getMessage();
145 }
146 }
147
148 /**
149 * Check that value is of correct type before setting.
150 * {@inheritDoc}
151 * @see org.melati.poem.generated.SettingBase#setValue(java.lang.String)
152 */
153 public void setValue(String value) {
154 Object rawLocal;
155 try {
156 rawLocal = getType().rawOfString(value);
157 } catch (Exception e) {
158 throw new SettingValidationException(getName_unsafe(), e);
159 }
160
161 super.setValue(value);
162 this.raw = rawLocal;
163 cooked = null;
164 }
165
166 /**
167 * Set from a raw value; checking that the value is of the correct type first.
168 * @param raw the raw to set
169 */
170 public void setRaw(Object raw) {
171 String string;
172 Object newRaw;
173 try {
174 string = getType().stringOfRaw(raw);
175 } catch (Exception e) {
176 throw new SettingValidationException(getName_unsafe(), e);
177 }
178 try {
179 newRaw = getType().rawOfString(string);
180 } catch (Exception e) {
181 throw new SettingValidationException(getName_unsafe(), e);
182 }
183 super.setValue(newRaw == null ? null : string);
184 this.raw = newRaw;
185 cooked = null;
186 }
187
188 /**
189 * @return the raw value
190 */
191 public Object getRaw() {
192 if (raw == null)
193 try {
194 raw = getType().rawOfString(getValue());
195 } catch (Exception e) {
196 throw new SettingValidationException(getName_unsafe(), e);
197 }
198
199 return raw;
200 }
201
202 /**
203 * @return the cooked, ie typed, Object
204 */
205 public Object getCooked() {
206 if (cooked == null)
207 cooked = getType().cookedOfRaw(getRaw());
208 return cooked;
209 }
210
211 /**
212 * Thrown when a {@link Setting}'s type does not match the type required.
213 */
214 public static class
215 SettingTypeMismatchException extends AppBugPoemException {
216 private static final long serialVersionUID = 1L;
217
218 /** Name of the setting. */
219 public String name;
220 /** The factory used. */
221 public PoemTypeFactory type;
222 /** Required type. */
223 public String reqType;
224
225 /** Constructor. */
226 public SettingTypeMismatchException(String name, PoemTypeFactory type,
227 String reqType) {
228 this.name = name;
229 this.type = type;
230 this.reqType = reqType;
231 }
232
233 /** @return The detail message. */
234 public String getMessage() {
235 return "The setting `" + name + "' has type `" + type + "' but " +
236 "the application asked for a value of type " + reqType;
237 }
238 }
239
240 /**
241 * @return value as an Integer
242 */
243 public Integer getIntegerCooked() {
244 Object cookedLocal = getCooked();
245 if (cookedLocal == null && getNullable().booleanValue())
246 return null;
247 else if (cookedLocal instanceof Integer)
248 return (Integer)cookedLocal;
249 else
250 throw new SettingTypeMismatchException(getName_unsafe(),
251 getTypefactory(), "Integer");
252 }
253
254 /**
255 * @return value as a String
256 */
257 public String getStringCooked() {
258 Object cookedLocal = getCooked();
259 if (cookedLocal == null && getNullable().booleanValue())
260 return null;
261 else if (cookedLocal instanceof String)
262 return (String)cookedLocal;
263 else
264 throw new SettingTypeMismatchException(getName_unsafe(),
265 getTypefactory(), "String");
266 }
267
268 /**
269 * @return value as a Boolean
270 */
271 public Boolean getBooleanCooked() {
272 Object cookedLocal = getCooked();
273 if (cookedLocal == null && getNullable().booleanValue())
274 return null;
275 else if (cookedLocal instanceof Boolean)
276 return (Boolean)cookedLocal;
277 else
278 throw new SettingTypeMismatchException(getName_unsafe(),
279 getTypefactory(), "Boolean");
280 }
281
282 /**
283 * @return the attributes set in this Setting as the attributes for the
284 * value field
285 */
286 @SuppressWarnings("rawtypes")
287 private FieldAttributes valueFieldAttributes() {
288 if (valueAttributes == null)
289 valueAttributes =
290 fieldAttributesRenamedAs(getSettingTable().getValueColumn());
291
292 return valueAttributes;
293 }
294
295 /**
296 * Override the normal field attributes for the Value field,
297 * use the attribute values set in this setting.
298 * @see org.melati.poem.generated.SettingBase#getValueField()
299 */
300 @SuppressWarnings({ "rawtypes", "unchecked" })
301 public Field getValueField() {
302 try {
303 return new Field<String>(getRaw(), valueFieldAttributes());
304 } catch (AccessPoemException accessException) {
305 return new Field<Exception>(accessException, valueFieldAttributes());
306 }
307 }
308
309 /**
310 * Slight overkill, force recreation of value field attributes even
311 * if it is the value that has been changed.
312 *
313 * {@inheritDoc}
314 * @see org.melati.poem.ValueInfo#postEdit(boolean)
315 */
316 public void postEdit(boolean creating) {
317 super.postEdit(creating);
318 valueAttributes = null;
319 }
320
321 }