package org.aplikator.server.descriptor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import org.aplikator.client.shared.data.ListItem;
import org.aplikator.client.shared.data.RecordDTO;
import org.aplikator.client.shared.descriptor.PropertyDTO;
import org.aplikator.server.Configurator;
import org.aplikator.server.data.BinaryData;
import org.aplikator.server.data.Context;
import org.aplikator.server.query.QueryParameterReference;
import org.aplikator.server.query.TermQueryExpression;
import org.aplikator.server.query.TermQueryOperator;
public class Property<T extends Serializable> extends LocalizedServerDescriptorBase implements Cloneable {
private final Class<T> type;
private final Entity entity;
private final double size;
private final boolean required;
private final boolean virtual; //does not exist in the corresponding database table, must be filled in onLoad trigger
private JoinableProperty<? extends Entity> refferedThrough;
private ListProvider listProvider;
private boolean editable;
private String formatPattern;
public Property(String id, Class<T> type, double size, boolean required, Entity entity, boolean virtual, String formatPattern) {
super(id);
this.type = type;
this.entity = entity;
this.size = size;
this.required = required;
this.virtual = virtual;
if (virtual) {
this.editable = false;
} else {
this.editable = true;
}
if (type.equals(Date.class)) {
if (formatPattern == null) {
setFormatPattern(Configurator.get().getConfig().getString(Configurator.DEFAULT_DATE_FORMAT));
} else {
setFormatPattern(formatPattern);
}
} else if (type.equals(BigDecimal.class)) {
int prec = (int) size;
int scale = (int) ((size - prec) * 10 + 0.5);
if (prec > 0 && scale > 0) {
StringBuilder sb = new StringBuilder("#,##0.");
for (int i = 0; i < scale; i++) {
sb.append('0');
}
setFormatPattern(sb.toString());
}
} else if (type.equals(BinaryData.class)) {
setFormatPattern(Configurator.get().getConfig().getInt(Configurator.DEFAULT_THUMBNAIL_SIZE) + "," + Configurator.get().getConfig().getInt(Configurator.DEFAULT_PREVIEW_SIZE));
}
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Property))
return false;
if (!super.equals(o))
return false;
Property<?> property = (Property<?>) o;
return refferedThrough != null ? refferedThrough.equals(property.refferedThrough) : property.refferedThrough == null;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (refferedThrough != null ? refferedThrough.hashCode() : 0);
return result;
}
public Class<T> getType() {
return type;
}
public PropertyDTO getPropertyDTO(Context ctx) {
PropertyDTO clientRefThrough = null;
if (refferedThrough != null) {
clientRefThrough = refferedThrough.getPropertyDTO(ctx);
}
PropertyDTO retval = new PropertyDTO(getId(), getLocalizedName(ctx), getType().getName(), getSize(), clientRefThrough, editable, required, formatPattern);
if (listProvider != null) {
List<ListItem> clientListValues = listProvider.getListValues(ctx);
retval.setListValues(clientListValues);
}
return retval;
}
@SuppressWarnings("unchecked")
@Override
public Property<T> clone() throws CloneNotSupportedException {
return (Property<T>) super.clone();
}
public Entity getEntity() {
return entity;
}
public ListProvider getListProvider() {
return listProvider;
}
public Property<T> setListProvider(ListProvider listProvider) {
this.listProvider = listProvider;
return this;
}
public double getSize() {
return size;
}
public boolean isRequired() {
return required;
}
public boolean isVirtual() {
return virtual;
}
public boolean isEditable() {
return editable;
}
public Property<T> setEditable(boolean editable) {
this.editable = editable;
return this;
}
public String getFormatPattern() {
return formatPattern;
}
public Property setFormatPattern(String formatPattern) {
this.formatPattern = formatPattern;
return this;
}
/**
* Creates the default widget for this property, based on its type.
*
* @return The default widget or null (for unsupported types, currently
* Reference and Collection) TODO - add support for references and
* collections, avoid infinite recursion
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public Widget widget() {
Widget retval = null;
if (listProvider != null) {
retval = new ComboBox(this);
} else if (type.equals(Boolean.class)) {
retval = new CheckBox((Property<Boolean>) this);
} else if (type.equals(Date.class)) {
retval = new DateField((Property<Date>) this);
} else if (type.equals(BinaryData.class)) {
retval = new BinaryField((BinaryProperty) this);
} else if (type.equals(Date.class)) {
retval = new DateField((Property<Date>) this);
} else if (this instanceof Reference) {
retval = null;//ReferenceField.reference((Reference) this);// TODO avoid
// circular
// references
} else if (this instanceof Collection) {
retval = null;
} else if (type.equals(String.class) && size == 0) {
retval = new TextArea((Property<String>) this);
} else {
retval = new TextField(this);
}
return retval;
}
public JoinableProperty<? extends Entity> getRefferedThrough() {
return refferedThrough;
}
void setRefferedThrough(JoinableProperty<? extends Entity> refferedThrough) {
this.refferedThrough = refferedThrough;
}
public String getRecordId() {
if (getRefferedThrough() != null) {
return getRefferedThrough().getRecordId() + PATH_DELIMITER + getId();
} else {
return getId();
}
}
@SuppressWarnings("unchecked")
public T getValue(RecordDTO record) {
return (T) record.getValue(getRecordId());
}
public void setValue(RecordDTO record, T value) {
record.setValue(getRecordId(), value);
}
public String getStringValue(RecordDTO record, Context ctx) {
Object val = record.getValue(getRecordId());
if (val == null) {
return "";
}
if (listProvider != null) {
for (ListItem listItem : listProvider.getListValues(ctx)) {
if (listItem.getValue().equals(val)) {
return listItem.getName();
}
}
}
return val.toString();
}
public boolean isDirty(RecordDTO record) {
return record.isDirty(getRecordId());
}
@Override
public AccessControl getAccessControl() {
AccessControl retval = super.getAccessControl();
if (retval == null) {
retval = entity.getAccessControl();
}
return retval;
}
/*Query support methods*/
public TermQueryExpression<T> EQUAL(T value) {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, value);
}
public TermQueryExpression<T> EQUAL(QueryParameterReference ref) {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, ref);
}
public TermQueryExpression<T> NOTEQUAL(T value) {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTEQUAL, value);
}
public TermQueryExpression<T> NOTEQUAL(QueryParameterReference ref) {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTEQUAL, ref);
}
public TermQueryExpression<T> LESSTHAN(T value) {
return new TermQueryExpression<T>(this, TermQueryOperator.LESSTHAN, value);
}
public TermQueryExpression<T> LESSTHAN(QueryParameterReference ref) {
return new TermQueryExpression<T>(this, TermQueryOperator.LESSTHAN, ref);
}
public TermQueryExpression<T> MOREOREQUAL(T value) {
return new TermQueryExpression<T>(this, TermQueryOperator.MOREOREQUAL, value);
}
public TermQueryExpression<T> MOREOREQUAL(QueryParameterReference ref) {
return new TermQueryExpression<T>(this, TermQueryOperator.MOREOREQUAL, ref);
}
public TermQueryExpression<T> GREATERTHAN(T value) {
return new TermQueryExpression<T>(this, TermQueryOperator.GREATERTHAN, value);
}
public TermQueryExpression<T> GREATERTHAN(QueryParameterReference ref) {
return new TermQueryExpression<T>(this, TermQueryOperator.GREATERTHAN, ref);
}
public TermQueryExpression<T> LESSOREQUAL(T value) {
return new TermQueryExpression<T>(this, TermQueryOperator.LESSOREQUAL, value);
}
public TermQueryExpression<T> LESSOREQUAL(QueryParameterReference ref) {
return new TermQueryExpression<T>(this, TermQueryOperator.LESSOREQUAL, ref);
}
public TermQueryExpression<T> LIKE(T value) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.LIKE, value);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, value);
}
}
public TermQueryExpression<T> LIKE(QueryParameterReference ref) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.LIKE, ref);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, ref);
}
}
public TermQueryExpression<T> STARTSWITH(T value) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.STARTSWITH, value);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, value);
}
}
public TermQueryExpression<T> STARTSWITH(QueryParameterReference ref) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.STARTSWITH, ref);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, ref);
}
}
public TermQueryExpression<T> STARTSWITH_IGNORECASE(QueryParameterReference ref) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.STARTSWITH_IGNORECASE, ref);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.EQUAL, ref);
}
}
public TermQueryExpression<T> NOTLIKE(T value) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTLIKE, value);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTEQUAL, value);
}
}
public TermQueryExpression<T> NOTLIKE(QueryParameterReference ref) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTLIKE, ref);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTEQUAL, ref);
}
}
public TermQueryExpression<T> NOTSTARTSWITH(T value) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTSTARTSWITH, value);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTEQUAL, value);
}
}
public TermQueryExpression<T> NOTSTARTSWITH(QueryParameterReference ref) {
if (type.equals(String.class)) {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTSTARTSWITH, ref);
} else {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTEQUAL, ref);
}
}
@SuppressWarnings("unchecked")
public TermQueryExpression<T> NULL() {
return new TermQueryExpression(this, TermQueryOperator.NULL, (T) null);
}
@SuppressWarnings("unchecked")
public TermQueryExpression<T> NOTNULL() {
return new TermQueryExpression<T>(this, TermQueryOperator.NOTNULL, (T) null);
}
public TermQueryExpression<T> BETWEEN(T min, T max) {
throw new UnsupportedOperationException("BETWEEN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.BETWEEN,min, max);
}
public TermQueryExpression<T> BETWEEN(QueryParameterReference refMin, QueryParameterReference refMax) {
throw new UnsupportedOperationException("BETWEEN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.BETWEEN,refMin, refMax);
}
public TermQueryExpression<T> NOTBETWEEN(T min, T max) {
throw new UnsupportedOperationException("NOTBETWEEN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.NOTBETWEEN,min, max);
}
public TermQueryExpression<T> NOTBETWEEN(QueryParameterReference refMin, QueryParameterReference refMax) {
throw new UnsupportedOperationException("NOTBETWEEN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.NOTBETWEEN,refMin,refMax );
}
public TermQueryExpression<T> IN(T[] value) {
throw new UnsupportedOperationException("IN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.IN,value);
}
public TermQueryExpression<T> IN(QueryParameterReference[] ref) {
throw new UnsupportedOperationException("IN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.IN,ref);
}
public TermQueryExpression<T> NOTIN(T[] value) {
throw new UnsupportedOperationException("NOTIN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.NOTIN,value);
}
public TermQueryExpression<T> NOTIN(QueryParameterReference[] ref) {
throw new UnsupportedOperationException("NOTIN is not yet implemented");
//return new QueryCompareExpression<T>(this, QueryCompareOperator.NOTIN,ref);
}
}