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 java.util.Enumeration; 49 import java.io.PrintStream; 50 import java.text.DateFormat; 51 import org.melati.poem.util.LimitedEnumeration; 52 import org.melati.poem.util.MappedEnumeration; 53 54 /** 55 * A Field. 56 * A field is a value (the raw) with its metadata 57 * (a set of attributes) and possibly an access violation 58 * if the current user is not allowed to access it. 59 * 60 */ 61 public class Field<T> implements FieldAttributes<T>, Cloneable { 62 63 private AccessPoemException accessException; 64 private Object raw; 65 private FieldAttributes<T> attrs; 66 67 /** 68 * Constructor. 69 * 70 * @param raw the object value, integer for reference types 71 * @param attrs the metadata attributes to set 72 */ 73 public Field(Object raw, FieldAttributes<T> attrs) { 74 this.raw = raw; 75 this.attrs = attrs; 76 accessException = null; 77 } 78 79 /** 80 * Constructor for a Field with an access violation. 81 * 82 * @param accessException the access violation 83 * @param attrs the metadata attributes to set 84 */ 85 public Field(AccessPoemException accessException, FieldAttributes<T> attrs) { 86 this.accessException = accessException; 87 this.attrs = attrs; 88 raw = null; 89 } 90 91 // 92 // ----------- 93 // Cloneable 94 // ----------- 95 // 96 97 /** 98 * {@inheritDoc} 99 * @see java.lang.Object#clone() 100 */ 101 public Object clone() { 102 try { 103 return super.clone(); 104 } 105 catch (CloneNotSupportedException e) { 106 throw new UnexpectedExceptionPoemException(e, "Object no longer supports clone."); 107 } 108 } 109 110 // 111 // ----------------- 112 // FieldAttributes 113 // ----------------- 114 // 115 116 /** 117 * {@inheritDoc} 118 * @see org.melati.poem.FieldAttributes#getName() 119 */ 120 public String getName() { 121 return attrs.getName(); 122 } 123 124 /** 125 * {@inheritDoc} 126 * @see org.melati.poem.FieldAttributes#getDisplayName() 127 */ 128 public String getDisplayName() { 129 return attrs.getDisplayName(); 130 } 131 132 /** 133 * {@inheritDoc} 134 * @see org.melati.poem.FieldAttributes#getDescription() 135 */ 136 public String getDescription() { 137 return attrs.getDescription(); 138 } 139 140 /** 141 * {@inheritDoc} 142 * @see org.melati.poem.FieldAttributes#getType() 143 */ 144 public PoemType<T> getType() { 145 return attrs.getType(); 146 } 147 148 /** 149 * {@inheritDoc} 150 * @see org.melati.poem.FieldAttributes#getIndexed() 151 */ 152 public boolean getIndexed() { 153 return attrs.getIndexed(); 154 } 155 156 /** 157 * {@inheritDoc} 158 * @see org.melati.poem.FieldAttributes#getUserEditable() 159 */ 160 public boolean getUserEditable() { 161 return attrs.getUserEditable(); 162 } 163 164 /** 165 * {@inheritDoc} 166 * @see org.melati.poem.FieldAttributes#getUserCreateable() 167 */ 168 public boolean getUserCreateable() { 169 return attrs.getUserCreateable(); 170 } 171 172 /** 173 * {@inheritDoc} 174 * @see org.melati.poem.FieldAttributes#getWidth() 175 */ 176 public int getWidth() { 177 return attrs.getWidth(); 178 } 179 180 /** 181 * {@inheritDoc} 182 * @see org.melati.poem.FieldAttributes#getHeight() 183 */ 184 public int getHeight() { 185 return attrs.getHeight(); 186 } 187 188 /** 189 * {@inheritDoc} 190 * @see org.melati.poem.FieldAttributes#getRenderInfo() 191 */ 192 public String getRenderInfo() { 193 return attrs.getRenderInfo(); 194 } 195 196 // 197 // ------- 198 // Field 199 // ------- 200 // 201 202 /** 203 * Get the value of the Field. 204 * 205 * @return the Object value, Integer for reference types 206 * @throws AccessPoemException 207 * FIXME Integer/Persistent issue 208 */ 209 @SuppressWarnings("unchecked") 210 public final T getRaw() throws AccessPoemException { 211 if (accessException != null) 212 throw accessException; 213 return (T)raw; 214 } 215 216 /** 217 * Get the value as a String. 218 * 219 * @return the String representation of this Field. 220 * @throws AccessPoemException if the current AccessToken does not permit reading 221 */ 222 public final Object getRawString() throws AccessPoemException { 223 if (accessException != null) 224 throw accessException; 225 return raw == null ? "" : getType().stringOfRaw(raw); 226 } 227 228 /** 229 * @return the object represented by the raw 230 * @throws AccessPoemException if the current AccessToken does not permit reading 231 */ 232 public final Object getCooked() throws AccessPoemException { 233 if (accessException != null) 234 throw accessException; 235 return getType().cookedOfRaw(raw); 236 } 237 238 /** 239 * @return cooked value as a String with defaulted Locale and DateFormat 240 * @throws AccessPoemException 241 */ 242 public final String getCookedString() 243 throws AccessPoemException { 244 return getCookedString(PoemLocale.HERE,java.text.DateFormat.SHORT); 245 } 246 /** 247 * @param locale used in date rendering 248 * @param style used in date rendering 249 * @return a String representation of the Object represented by the raw 250 * @throws AccessPoemException if the current AccessToken does not permit reading 251 */ 252 public final String getCookedString(PoemLocale locale, int style) 253 throws AccessPoemException { 254 if (accessException != null) 255 throw accessException; 256 return raw == null ? "" : 257 getType().stringOfCooked(getCooked(), locale, style); 258 } 259 260 /** 261 * Clone this Field with a new value but same metadata. 262 * 263 * @param rawP new value to set 264 * @return a clone with the raw value set to new value 265 */ 266 public Field<T> withRaw(T rawP) { 267 @SuppressWarnings("unchecked") 268 Field<T> it = (Field<T>)clone(); 269 it.raw = rawP; 270 return it; 271 } 272 273 /** 274 * Clone with a different nullability. 275 * 276 * @param nullable the new nullability 277 * @return a new Field with a new, presumably different, nullability 278 */ 279 public Field<T> withNullable(boolean nullable) { 280 return new Field<T>(raw, new BaseFieldAttributes<T>(attrs, nullable)); 281 } 282 283 /** 284 * Clone with a new name. 285 * 286 * @param name the new name 287 * @return a new Field with a new name 288 */ 289 public Field<T> withName(String name) { 290 return new Field<T>(raw, new BaseFieldAttributes<T>(attrs, name)); 291 } 292 293 /** 294 * Clone with a new description. 295 * 296 * @param description the new description 297 * @return a new Field with a new description 298 */ 299 public Field<T> withDescription(String description) { 300 return new Field<T>(raw, new BaseFieldAttributes<T>( 301 attrs, attrs.getName(), description)); 302 } 303 304 /** 305 * Might be a bit big for some Reference types. 306 * Returns <code>null</code> for String or Integer Types. 307 * 308 * @return All possible values or null. 309 */ 310 public Enumeration<Field<T>> getPossibilities() { 311 final Field<T> _this = this; 312 Enumeration<T> en = getType().possibleRaws(); 313 return 314 en == null ? null : 315 new MappedEnumeration<Field<T>,T>(en) { 316 protected Field<T> mapped(T rawP) { 317 return _this.withRaw(rawP); 318 } 319 }; 320 } 321 322 /** 323 * Return a limited enumeration of possibilities. 324 * 325 * A bit of a hack? 326 * @return the first 100 possibilities or null 327 */ 328 public Enumeration<Field<T>> getFirst1000Possibilities() { 329 Enumeration<Field<T>> en = getPossibilities(); 330 return en == null ? null : new LimitedEnumeration<Field<T>>(en, 1000); 331 } 332 333 /** 334 * Compare raws. 335 * 336 * @param other another field to check 337 * @return whether the other field has the same raw value as this one 338 * @throws AccessPoemException if it is already set 339 */ 340 public boolean sameRawAs(Field<T> other) throws AccessPoemException { 341 if (accessException != null) 342 throw accessException; 343 return raw == null ? other.raw == null : raw.equals(other.raw); 344 } 345 346 /** 347 * Dump to a PrintStream. 348 * 349 * @param p the PRintStream to write to 350 */ 351 public void dump(PrintStream p) { 352 p.print(toString()); 353 } 354 355 /** 356 * Dump to a string. 357 * 358 * {@inheritDoc} 359 * @see java.lang.Object#toString() 360 */ 361 public String toString() { 362 return getName() + ": " + getCookedString(PoemLocale.HERE, 363 DateFormat.MEDIUM); 364 } 365 366 /** 367 * A convenience method to create a Field. 368 * 369 * @param value the Object to set the value to 370 * @param name the name of the new Field, also used as description 371 * @param type the PoemType of the Field 372 * @return a newly created Field 373 */ 374 @SuppressWarnings({ "unchecked", "rawtypes" }) 375 public static Field basic(Object value, String name, PoemType type) { 376 return 377 new Field(value, 378 new BaseFieldAttributes(name, name, null, type, 20, 1, null, 379 false, true, true)); 380 } 381 382 /** 383 * A convenience method to create nullable String Field. 384 * 385 * @param value the String to set the value to 386 * @param name the name of the new Field, also used as description 387 * @return a newly created nullable Field of type StringPoemType 388 */ 389 @SuppressWarnings("rawtypes") 390 public static Field string(String value, String name) { 391 return basic(value, name, StringPoemType.nullableInstance); 392 } 393 394 /** 395 * A convenience method to create nullable Integer Field. 396 * 397 * @param value the Integer to set the value to 398 * @param name the name of the new Field, also used as description 399 * @return a newly created nullable Field of type IntegerPoemType 400 */ 401 @SuppressWarnings("rawtypes") 402 public static Field integer(Integer value, String name) { 403 return basic(value, name, IntegerPoemType.nullableInstance); 404 } 405 406 /** 407 * A convenience method to create a populated, nullable, Reference Field. 408 * 409 * @param value the Persistent to set the value to 410 * @param name the name of the new Field, also used as description 411 * @return a newly created nullable Field of type ReferencePoemType 412 */ 413 @SuppressWarnings("rawtypes") 414 public static Field reference(Persistent value, String name) { 415 return basic(value.troid(), name, 416 new ReferencePoemType(value.getTable(), true)); 417 } 418 419 /** 420 * A convenience method to create new unpopulated, nullable Reference Field. 421 * 422 * @param table the Table to refer to 423 * @param name the name of the new Field, also used as description 424 * @return a newly created nullable Field of type ReferencePoemType 425 */ 426 @SuppressWarnings("rawtypes") 427 public static Field reference(Table table, String name) { 428 return basic(null, name, new ReferencePoemType(table, true)); 429 } 430 }