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); } }