Coverage Report - org.melati.poem.Field
 
Classes in this File Line Coverage Branch Coverage Complexity
Field
95%
58/61
90%
20/22
1.545
Field$1
100%
2/2
N/A
1.545
 
 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  262
   public Field(Object raw, FieldAttributes<T> attrs) {
 74  262
     this.raw = raw;
 75  262
     this.attrs = attrs;
 76  262
     accessException = null;
 77  262
   }      
 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  10
   public Field(AccessPoemException accessException, FieldAttributes<T> attrs) {
 86  10
     this.accessException = accessException;
 87  10
     this.attrs = attrs;
 88  10
     raw = null;
 89  10
   }
 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  33
       return super.clone();
 104  
     }
 105  0
     catch (CloneNotSupportedException e) {
 106  0
       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  182
     return attrs.getName();
 122  
   }
 123  
 
 124  
   /**
 125  
    * {@inheritDoc}
 126  
    * @see org.melati.poem.FieldAttributes#getDisplayName()
 127  
    */
 128  
   public String getDisplayName() {
 129  3
     return attrs.getDisplayName();
 130  
   }
 131  
 
 132  
   /**
 133  
    * {@inheritDoc}
 134  
    * @see org.melati.poem.FieldAttributes#getDescription()
 135  
    */
 136  
   public String getDescription() {
 137  5
     return attrs.getDescription();
 138  
   }
 139  
 
 140  
   /**
 141  
    * {@inheritDoc}
 142  
    * @see org.melati.poem.FieldAttributes#getType()
 143  
    */
 144  
   public PoemType<T> getType() {
 145  268
     return attrs.getType();
 146  
   }
 147  
 
 148  
   /**
 149  
    * {@inheritDoc}
 150  
    * @see org.melati.poem.FieldAttributes#getIndexed()
 151  
    */
 152  
   public boolean getIndexed() {
 153  3
     return attrs.getIndexed();
 154  
   }
 155  
 
 156  
   /**
 157  
    * {@inheritDoc}
 158  
    * @see org.melati.poem.FieldAttributes#getUserEditable()
 159  
    */
 160  
   public boolean getUserEditable() {
 161  3
     return attrs.getUserEditable();
 162  
   }
 163  
 
 164  
   /**
 165  
    * {@inheritDoc}
 166  
    * @see org.melati.poem.FieldAttributes#getUserCreateable()
 167  
    */
 168  
   public boolean getUserCreateable() {
 169  3
     return attrs.getUserCreateable();
 170  
   }
 171  
 
 172  
   /**
 173  
    * {@inheritDoc}
 174  
    * @see org.melati.poem.FieldAttributes#getWidth()
 175  
    */
 176  
   public int getWidth() {
 177  3
     return attrs.getWidth();
 178  
   }
 179  
 
 180  
   /**
 181  
    * {@inheritDoc}
 182  
    * @see org.melati.poem.FieldAttributes#getHeight()
 183  
    */
 184  
   public int getHeight() {
 185  3
     return attrs.getHeight();
 186  
   }
 187  
 
 188  
   /**
 189  
    * {@inheritDoc}
 190  
    * @see org.melati.poem.FieldAttributes#getRenderInfo()
 191  
    */
 192  
   public String getRenderInfo() {
 193  3
     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  14
     if (accessException != null)
 212  2
       throw accessException;
 213  12
     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  9
     if (accessException != null)
 224  1
       throw accessException;
 225  8
     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  105
     if (accessException != null)
 234  3
       throw accessException;
 235  102
     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  0
     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  117
     if (accessException != null)
 255  1
       throw accessException;
 256  116
     return raw == null ? "" :
 257  92
                          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  31
     Field<T> it = (Field<T>)clone();
 269  31
     it.raw = rawP;
 270  31
     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  2
     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  2
     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  2
     return new Field<T>(raw, new BaseFieldAttributes<T>(
 301  2
                                         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  9
     final Field<T> _this = this;
 312  9
     Enumeration<T> en = getType().possibleRaws();
 313  9
     return
 314  
         en == null ? null :
 315  30
           new MappedEnumeration<Field<T>,T>(en) {
 316  
             protected Field<T> mapped(T rawP) {
 317  25
               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  3
     Enumeration<Field<T>> en = getPossibilities();
 330  3
     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  9
     if (accessException != null)
 342  1
       throw accessException;
 343  8
     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  54
     p.print(toString());
 353  54
   }
 354  
   
 355  
   /**
 356  
    * Dump to a string.
 357  
    * 
 358  
    * {@inheritDoc}
 359  
    * @see java.lang.Object#toString()
 360  
    */
 361  
   public String toString() {
 362  112
     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  8
     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  1
     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  1
     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  2
     return basic(value.troid(), name,
 416  1
                  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  1
     return basic(null, name, new ReferencePoemType(table, true));
 429  
   }
 430  
 }