Field.java
/*
* $Source$
* $Revision$
*
* Copyright (C) 2000 William Chesters
*
* Part of Melati (http://melati.org), a framework for the rapid
* development of clean, maintainable web applications.
*
* Melati is free software; Permission is granted to copy, distribute
* and/or modify this software under the terms either:
*
* a) the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version,
*
* or
*
* b) any version of the Melati Software License, as published
* at http://melati.org
*
* You should have received a copy of the GNU General Public License and
* the Melati Software License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
* GNU General Public License and visit http://melati.org to obtain the
* Melati Software License.
*
* Feel free to contact the Developers of Melati (http://melati.org),
* if you would like to work out a different arrangement than the options
* outlined here. It is our intention to allow Melati to be used by as
* wide an audience as possible.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contact details for copyright holder:
*
* William Chesters <williamc At paneris.org>
* http://paneris.org/~williamc
* Obrechtstraat 114, 2517VX Den Haag, The Netherlands
*/
package org.melati.poem;
import java.util.Enumeration;
import java.io.PrintStream;
import java.text.DateFormat;
import org.melati.poem.util.LimitedEnumeration;
import org.melati.poem.util.MappedEnumeration;
/**
* A Field.
* A field is a value (the raw) with its metadata
* (a set of attributes) and possibly an access violation
* if the current user is not allowed to access it.
*
*/
public class Field<T> implements FieldAttributes<T>, Cloneable {
private AccessPoemException accessException;
private Object raw;
private FieldAttributes<T> attrs;
/**
* Constructor.
*
* @param raw the object value, integer for reference types
* @param attrs the metadata attributes to set
*/
public Field(Object raw, FieldAttributes<T> attrs) {
this.raw = raw;
this.attrs = attrs;
accessException = null;
}
/**
* Constructor for a Field with an access violation.
*
* @param accessException the access violation
* @param attrs the metadata attributes to set
*/
public Field(AccessPoemException accessException, FieldAttributes<T> attrs) {
this.accessException = accessException;
this.attrs = attrs;
raw = null;
}
//
// -----------
// Cloneable
// -----------
//
/**
* {@inheritDoc}
* @see java.lang.Object#clone()
*/
public Object clone() {
try {
return super.clone();
}
catch (CloneNotSupportedException e) {
throw new UnexpectedExceptionPoemException(e, "Object no longer supports clone.");
}
}
//
// -----------------
// FieldAttributes
// -----------------
//
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getName()
*/
public String getName() {
return attrs.getName();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getDisplayName()
*/
public String getDisplayName() {
return attrs.getDisplayName();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getDescription()
*/
public String getDescription() {
return attrs.getDescription();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getType()
*/
public PoemType<T> getType() {
return attrs.getType();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getIndexed()
*/
public boolean getIndexed() {
return attrs.getIndexed();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getUserEditable()
*/
public boolean getUserEditable() {
return attrs.getUserEditable();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getUserCreateable()
*/
public boolean getUserCreateable() {
return attrs.getUserCreateable();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getWidth()
*/
public int getWidth() {
return attrs.getWidth();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getHeight()
*/
public int getHeight() {
return attrs.getHeight();
}
/**
* {@inheritDoc}
* @see org.melati.poem.FieldAttributes#getRenderInfo()
*/
public String getRenderInfo() {
return attrs.getRenderInfo();
}
//
// -------
// Field
// -------
//
/**
* Get the value of the Field.
*
* @return the Object value, Integer for reference types
* @throws AccessPoemException
* FIXME Integer/Persistent issue
*/
@SuppressWarnings("unchecked")
public final T getRaw() throws AccessPoemException {
if (accessException != null)
throw accessException;
return (T)raw;
}
/**
* Get the value as a String.
*
* @return the String representation of this Field.
* @throws AccessPoemException if the current AccessToken does not permit reading
*/
public final Object getRawString() throws AccessPoemException {
if (accessException != null)
throw accessException;
return raw == null ? "" : getType().stringOfRaw(raw);
}
/**
* @return the object represented by the raw
* @throws AccessPoemException if the current AccessToken does not permit reading
*/
public final Object getCooked() throws AccessPoemException {
if (accessException != null)
throw accessException;
return getType().cookedOfRaw(raw);
}
/**
* @return cooked value as a String with defaulted Locale and DateFormat
* @throws AccessPoemException
*/
public final String getCookedString()
throws AccessPoemException {
return getCookedString(PoemLocale.HERE,java.text.DateFormat.SHORT);
}
/**
* @param locale used in date rendering
* @param style used in date rendering
* @return a String representation of the Object represented by the raw
* @throws AccessPoemException if the current AccessToken does not permit reading
*/
public final String getCookedString(PoemLocale locale, int style)
throws AccessPoemException {
if (accessException != null)
throw accessException;
return raw == null ? "" :
getType().stringOfCooked(getCooked(), locale, style);
}
/**
* Clone this Field with a new value but same metadata.
*
* @param rawP new value to set
* @return a clone with the raw value set to new value
*/
public Field<T> withRaw(T rawP) {
@SuppressWarnings("unchecked")
Field<T> it = (Field<T>)clone();
it.raw = rawP;
return it;
}
/**
* Clone with a different nullability.
*
* @param nullable the new nullability
* @return a new Field with a new, presumably different, nullability
*/
public Field<T> withNullable(boolean nullable) {
return new Field<T>(raw, new BaseFieldAttributes<T>(attrs, nullable));
}
/**
* Clone with a new name.
*
* @param name the new name
* @return a new Field with a new name
*/
public Field<T> withName(String name) {
return new Field<T>(raw, new BaseFieldAttributes<T>(attrs, name));
}
/**
* Clone with a new description.
*
* @param description the new description
* @return a new Field with a new description
*/
public Field<T> withDescription(String description) {
return new Field<T>(raw, new BaseFieldAttributes<T>(
attrs, attrs.getName(), description));
}
/**
* Might be a bit big for some Reference types.
* Returns <code>null</code> for String or Integer Types.
*
* @return All possible values or null.
*/
public Enumeration<Field<T>> getPossibilities() {
final Field<T> _this = this;
Enumeration<T> en = getType().possibleRaws();
return
en == null ? null :
new MappedEnumeration<Field<T>,T>(en) {
protected Field<T> mapped(T rawP) {
return _this.withRaw(rawP);
}
};
}
/**
* Return a limited enumeration of possibilities.
*
* A bit of a hack?
* @return the first 100 possibilities or null
*/
public Enumeration<Field<T>> getFirst1000Possibilities() {
Enumeration<Field<T>> en = getPossibilities();
return en == null ? null : new LimitedEnumeration<Field<T>>(en, 1000);
}
/**
* Compare raws.
*
* @param other another field to check
* @return whether the other field has the same raw value as this one
* @throws AccessPoemException if it is already set
*/
public boolean sameRawAs(Field<T> other) throws AccessPoemException {
if (accessException != null)
throw accessException;
return raw == null ? other.raw == null : raw.equals(other.raw);
}
/**
* Dump to a PrintStream.
*
* @param p the PRintStream to write to
*/
public void dump(PrintStream p) {
p.print(toString());
}
/**
* Dump to a string.
*
* {@inheritDoc}
* @see java.lang.Object#toString()
*/
public String toString() {
return getName() + ": " + getCookedString(PoemLocale.HERE,
DateFormat.MEDIUM);
}
/**
* A convenience method to create a Field.
*
* @param value the Object to set the value to
* @param name the name of the new Field, also used as description
* @param type the PoemType of the Field
* @return a newly created Field
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Field basic(Object value, String name, PoemType type) {
return
new Field(value,
new BaseFieldAttributes(name, name, null, type, 20, 1, null,
false, true, true));
}
/**
* A convenience method to create nullable String Field.
*
* @param value the String to set the value to
* @param name the name of the new Field, also used as description
* @return a newly created nullable Field of type StringPoemType
*/
@SuppressWarnings("rawtypes")
public static Field string(String value, String name) {
return basic(value, name, StringPoemType.nullableInstance);
}
/**
* A convenience method to create nullable Integer Field.
*
* @param value the Integer to set the value to
* @param name the name of the new Field, also used as description
* @return a newly created nullable Field of type IntegerPoemType
*/
@SuppressWarnings("rawtypes")
public static Field integer(Integer value, String name) {
return basic(value, name, IntegerPoemType.nullableInstance);
}
/**
* A convenience method to create a populated, nullable, Reference Field.
*
* @param value the Persistent to set the value to
* @param name the name of the new Field, also used as description
* @return a newly created nullable Field of type ReferencePoemType
*/
@SuppressWarnings("rawtypes")
public static Field reference(Persistent value, String name) {
return basic(value.troid(), name,
new ReferencePoemType(value.getTable(), true));
}
/**
* A convenience method to create new unpopulated, nullable Reference Field.
*
* @param table the Table to refer to
* @param name the name of the new Field, also used as description
* @return a newly created nullable Field of type ReferencePoemType
*/
@SuppressWarnings("rawtypes")
public static Field reference(Table table, String name) {
return basic(null, name, new ReferencePoemType(table, true));
}
}