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@paneris.org>
42 * http://paneris.org/~williamc
43 * Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44 */
45 package org.melati.poem;
46
47 import org.melati.poem.generated.SettingTableBase;
48 import java.util.Hashtable;
49
50 /**
51 * A {@link Table} which is used like a properties file.
52 *
53 * Every Melati DB has one.
54 *
55 * Extended from a Melati POEM generated stub.
56 *
57 * <p>
58 * Description:
59 * A configurable setting for the application.
60 * </p>
61 *
62 *
63 * <table>
64 * <caption>
65 * Field summary for SQL table <code>Setting</code>
66 * </caption>
67 * <tr><th>Name</th><th>Type</th><th>Description</th></tr>
68 * <tr><td> id </td><td> Integer </td><td> The Table Row Object ID </td></tr>
69 * <tr><td> name </td><td> String </td><td> A code name for this setting
70 * </td></tr>
71 * <tr><td> value </td><td> String </td><td> The value of this setting
72 * </td></tr>
73 * </table>
74 *
75 * See org.melati.poem.prepro.TableDef#generateTableMainJava
76 */
77
78 public class SettingTable<T extends Setting> extends SettingTableBase<Setting> {
79
80 /**
81 * Constructor.
82 *
83 * See org.melati.poem.prepro.TableDef#generateTableMainJava
84 * @param database the POEM database we are using
85 * @param name the name of this <code>Table</code>
86 * @param definitionSource which definition is being used
87 * @throws PoemException if anything goes wrong
88 */
89 public SettingTable(
90 Database database, String name,
91 DefinitionSource definitionSource) throws PoemException {
92 super(database, name, definitionSource);
93 }
94
95 // programmer's domain-specific code here
96
97 private static final Object nullEntry = new Object();
98 private Hashtable<String, Object> cache = null;
99 private long cacheSerial = 0L;
100
101 /**
102 * Get an object of the appropriate type by name.
103 *
104 * Note this has not worked prior to 25/10/2006,
105 * a new cache was created every time.
106 * Transactions are so fine grained that it is not clear that
107 * this cache serves any purpose.
108 *
109 * @param name the name field of this Setting object
110 * @return its value, cast to the appropriate type.
111 */
112 public Object getCooked(String name) {
113 if (cache == null || cacheSerial != serial(PoemThread.transaction())) {
114 cacheSerial = serial(PoemThread.transaction());
115 cache = new Hashtable<String, Object>();
116 } else {
117 Object value = cache.get(name);
118 if (value == nullEntry)
119 return null;
120 else if (value != null)
121 return value;
122 }
123 Setting prop =
124 (Setting)getNameColumn().firstWhereEq(name);
125 if (prop == null) {
126 cache.put(name, nullEntry);
127 return null;
128 }
129 else {
130 Object propValue = prop.getCooked();
131 cache.put(name, propValue == null ? nullEntry : propValue);
132 return propValue;
133 }
134 }
135
136 /**
137 * Get the String representation of the setting.
138 * @param name the name field of the Setting object
139 * @return the value as a String or null
140 */
141 public String get(String name) {
142 Object it = getCooked(name);
143 return it == null ? null : it.toString();
144 }
145
146 /**
147 * Thrown when a {@link Setting} requested has not been set.
148 */
149 public static class UnsetException extends PoemException {
150 private static final long serialVersionUID = 1L;
151
152 /** The name of the requested setting. */
153 public String name;
154
155 /** Constructor. */
156 public UnsetException(String name) {
157 this.name = name;
158 }
159
160 /** @return The detail message. */
161 public String getMessage() {
162 return "The application's `" + name + "' parameter has not been set";
163 }
164 }
165
166 /**
167 * Get a set value.
168 *
169 * @param name the Setting's name field
170 * @return the Setting's value as an appropriate Object
171 */
172 public Object getOrDie(String name) {
173 Object it = get(name);
174 if (it == null)
175 throw new UnsetException(name);
176 return it;
177 }
178
179 /**
180 * Make sure that a setting with this name exists, if not then create it.
181 * Note that only the name is checked for existence, the other parameters
182 * are only used for creation, so enabling the setting to be manually changed.
183 *
184 * @param name the name of the Setting to ensure
185 * @param typefactory what type to use
186 * @param value the value of this setting
187 * @param displayname a human readable name
188 * @param description the purpose of the setting
189 * @return the existing or newly created Setting
190 */
191 public Setting ensure(String name, PoemTypeFactory typefactory, Object value,
192 String displayname, String description) {
193 Setting setting = (Setting)getNameColumn().firstWhereEq(name);
194 if (setting != null)
195 return setting;
196 else {
197 setting = (Setting)newPersistent();
198 setting.setName(name);
199 setting.setDisplayname(displayname);
200 setting.setDescription(description);
201
202 setting.setUsereditable(true);
203
204 setting.setWidth(20);
205 setting.setHeight(1);
206 setting.setPrecision(22);
207 setting.setScale(2);
208
209 setting.setNullable(true);
210 setting.setSize(-1);
211 setting.setTypefactory(typefactory);
212
213 setting.setRaw(value);
214
215 return (Setting)getNameColumn().ensure(setting);
216 }
217 }
218
219 /**
220 * Convenience method.
221 *
222 * @param name the name of the Setting to ensure
223 * @param value the value of this setting
224 * @param displayname a human readable name
225 * @param description the purpose of the setting
226 * @return the existing or newly created Setting
227 * @see #ensure(String, PoemTypeFactory, Object, String, String)
228 */
229 public Setting ensure(String name, String value,
230 String displayname, String description) {
231 return ensure(name, PoemTypeFactory.STRING, value,
232 displayname, description);
233 }
234
235 /**
236 * Convenience method.
237 * @param name the name of the Setting to ensure
238 * @param value the value of this setting
239 * @param displayname a human readable name
240 * @param description the purpose of the setting
241 * @return the existing or newly created Setting
242 * @see #ensure(String, PoemTypeFactory, Object, String, String)
243 */
244 public Setting ensure(String name, int value,
245 String displayname, String description) {
246 return ensure(name, PoemTypeFactory.INTEGER, new Integer(value),
247 displayname, description);
248 }
249
250 /**
251 * Convenience method.
252 * @param name the name of the Setting to ensure
253 * @param value the value of this setting
254 * @param displayname a human readable name
255 * @param description the purpose of the setting
256 * @return the existing or newly created Setting
257 * @see #ensure(String, PoemTypeFactory, Object, String, String)
258 */
259 public Setting ensure(String name, boolean value,
260 String displayname, String description) {
261 return ensure(name, PoemTypeFactory.BOOLEAN,
262 value ? Boolean.TRUE : Boolean.FALSE,
263 displayname, description);
264 }
265 }