001: package simpleorm.data;
002:
003: import org.apache.commons.beanutils.PropertyUtils;
004:
005: import java.util.Collections;
006:
007: /**
008: * A real instance of a record, eg. an Employee or a Department.
009: * Normally specialized for the actual record, eg. Emp extends DRecordInstance.<p>
010: *
011: * This delegates the actual storage of the record's field to a Commons-beanutils bean.
012: * If needed, users can specialize with dyna beans.
013: * (Not as elegant as our own hashMap of DFieldInstances, for old values etc., but simpler
014: * given main implementation will be simple beans or ddlutils.)
015: */
016: public class DRecordInstance {
017:
018: final DRecordMeta recordMeta;
019:
020: Object bean; // that stores the acual values.
021:
022: public DRecordInstance(DRecordMeta meta) { // SORM no param so can be newInstanced
023: this .recordMeta = meta;
024: }
025:
026: /**
027: * Get value as its base object, without any conversion, from the Bean.
028: *
029: */
030: public Object getObject(DFieldMeta meta) {
031: return getObject(meta.getName());
032: }
033:
034: public Object getObject(String property) {
035: try {
036: return PropertyUtils.getSimpleProperty(bean, property);
037: } catch (Exception ex) {
038: throw new DException("Could not access prop " + property,
039: ex);
040: }
041: }
042:
043: public void setObject(DFieldMeta meta, Object value) {
044: setObject(meta.name, value);
045: }
046:
047: public void setObject(String property, Object value) {
048: try {
049: PropertyUtils.setSimpleProperty(bean, property, value);
050: } catch (Exception ex) {
051: throw new DException("While " + this + "." + property
052: + " = " + value, ex);
053: }
054: }
055:
056: /** just GetObject.toString */
057: public String getString(DFieldMeta meta) {
058: Object res = getObject(meta);
059: return res == null ? null : res.toString();
060: }
061:
062: /** Compares primary keys only. */
063: public boolean equals(Object other) {
064: DRecordInstance otherRec = (DRecordInstance) other;
065: for (DFieldMeta field : recordMeta.getFields())
066: if (field.isPrimaryKey()) {
067: Object val1 = getObject(field);
068: if (val1 == null)
069: throw new DException("Null Primary Key " + this );
070: Object val2 = otherRec.getObject(field);
071: if (!val1.equals(val2))
072: return false;
073: }
074: return true;
075: }
076:
077: /** Of the primary keys only. */
078: public int hashCode() {
079: int hash = 0;
080: for (DFieldMeta field : recordMeta.getFields()) {
081: if (field.isPrimaryKey()) {
082: Object val1 = getObject(field);
083: if (val1 == null)
084: throw new DException("Null Primary Key " + this );
085: hash = (hash << 13) + hash + val1.hashCode(); // Java doesn;t detect int overflow.
086: }
087: }
088: return hash;
089: }
090:
091: /** Hack, and badly implemented (key could contain "~"). */
092: public String hackPrimaryKeyString() {
093: String pkey = "";
094: for (DFieldMeta field : recordMeta.getFields())
095: if (field.isPrimaryKey())
096: pkey += getObject(field) + "~"; // hack
097: return pkey;
098: }
099:
100: public String toString() {
101: StringBuilder buf = new StringBuilder("{"
102: + recordMeta.getTableName() + " ");
103: for (DFieldMeta field : recordMeta.getFields())
104: if (field.isPrimaryKey()) {
105: buf.append(getObject(field) + "");
106: buf.append(", ");
107: }
108: buf.append("}");
109: return buf.toString();
110: }
111:
112: public String toLongString() {
113: try {
114: StringBuilder buf = new StringBuilder("{ "
115: + recordMeta.getTableName() + " ");
116: for (Object propName : PropertyUtils.describe(bean)
117: .keySet()) {
118: buf.append(getObject((String) propName) + "");
119: buf.append(", ");
120: }
121: buf.append("}");
122: return buf.toString();
123: } catch (Exception ex) {
124: throw new DException(ex);
125: }
126: }
127:
128: /** Called whenever the record is updated or inserted, override in subtypes.
129: * Mainly used to validate. Use onPostUpSert to update related tables.
130: */
131: public void onPreUpSert(DConnection connection, QueryMode mode) {
132: }
133:
134: public enum QueryMode {
135: INSERT, UPDATE
136: }
137:
138: ///////////////////////////
139:
140: public DRecordMeta getRecordMeta() {
141: return recordMeta;
142: }
143: }
|