001: package net.sourceforge.orbroker;
002:
003: import java.lang.reflect.Modifier;
004: import java.util.HashMap;
005: import java.util.Map;
006:
007: /*
008: * Created on Mar 9, 2004
009: */
010:
011: /**
012: * @author Nils Kilden-Pedersen
013: */
014: final class ResultObjectDefinition {
015: private final Broker broker;
016: private Map delegateToResultObjects;
017: private Column discriminatorColumn;
018: private final String extendsId;
019: private final String id;
020: private ResultObjectInstantiator instantiator;
021:
022: private ResultKeyDef keyDefinition;
023: private final SetterList setterList = new SetterList();
024:
025: private final Class type;
026:
027: ResultObjectDefinition(String id, Class type, String extendsId,
028: ResultKeyDef keyDef, Broker broker) {
029: this .type = type;
030: this .id = id;
031: if (isInstantiable() && keyDef == null && extendsId == null) {
032: String msg = "No key columns are defined for '" + id + "'";
033: throw new ConfigurationException(msg);
034: }
035: this .extendsId = extendsId;
036: this .keyDefinition = keyDef;
037: this .broker = broker;
038: }
039:
040: void addDynamicResultObject(ResultObjectDefinition resultObjectDef,
041: String onValue) {
042: assert this .discriminatorColumn != null;
043: this .delegateToResultObjects.put(onValue, resultObjectDef);
044: }
045:
046: void addSetter(Setter setter) {
047: this .setterList.add(setter);
048: }
049:
050: /**
051: * Builds the result object.
052: * @param row
053: * @return result object
054: * @see net.sourceforge.orbroker.ValueType#getValue(net.sourceforge.orbroker.ResultRow)
055: */
056: Object buildObject(ResultRow row) {
057: assert this .instantiator != null : "Constructor or factory method has not been defined for '"
058: + this .id + "'.";
059:
060: ResultKey key = this .keyDefinition.getResultKey(row);
061: if (key == null) {
062: /*
063: * Key columns can be null if the columns
064: * are from an OUTER JOIN, so return null, since
065: * object cannot be created.
066: */
067: return null;
068: }
069: Object resultObject = null;
070: if (key.isValidKey()) {
071: resultObject = row.getCachedResultObject(key);
072: }
073: if (resultObject == null) {
074: resultObject = this .instantiator.newInstance(row);
075: row.cacheResultObject(key, resultObject);
076: setValues(resultObject, row);
077: }
078: return resultObject;
079: }
080:
081: /**
082: * Close object for further modification.
083: */
084: void close() {
085: assert (isInstantiable() && (this .keyDefinition != null || this .extendsId != null))
086: || !isInstantiable() : "Result object '" + getId()
087: + "' has no key definition";
088: assert (isInstantiable() && hasInstantiator())
089: || !isInstantiable() : "Result object '" + getId()
090: + "' has no constructor";
091:
092: this .setterList.close();
093: }
094:
095: Broker getBroker() {
096: return this .broker;
097: }
098:
099: /**
100: * @return Returns the extendsId.
101: */
102: String getExtendsId() {
103: return this .extendsId;
104: }
105:
106: /**
107: * @return Returns the id.
108: */
109: String getId() {
110: return this .id;
111: }
112:
113: ResultObjectDefinition getRuntimeResultObjectDef(ResultRow row)
114: throws ConfigurationException {
115: if (this .discriminatorColumn == null || row == null) {
116: return this ;
117: }
118: String columnValue = (String) this .discriminatorColumn
119: .getValue(row);
120: ResultObjectDefinition dynamicFactory = (ResultObjectDefinition) this .delegateToResultObjects
121: .get(columnValue);
122: if (dynamicFactory == null) {
123: return this ;
124: }
125: return dynamicFactory;
126: }
127:
128: /**
129: * @return Returns type.
130: */
131: Class getType() {
132: return this .type;
133: }
134:
135: boolean hasInstantiator() {
136: return this .instantiator != null;
137: }
138:
139: /**
140: * Initialize this builder with the super builder it extends.
141: * @param parentFactory
142: */
143: void initializeWith(ResultObjectDefinition parentFactory) {
144: assert parentFactory != null : "Result object to extend from is null.";
145: assert !parentFactory.id.equals(this .id) : "Result object has same id as parent.";
146:
147: if (parentFactory.hasInstantiator()) {
148: this .instantiator = parentFactory.instantiator
149: .copy(this .type);
150: }
151: this .keyDefinition = parentFactory.keyDefinition;
152: SetterList super Setters = parentFactory.setterList;
153: for (int i = 0; i < super Setters.size(); i++) {
154: this .addSetter(super Setters.getSetter(i));
155: }
156: }
157:
158: boolean isClosed() {
159: return this .setterList.isClosed();
160: }
161:
162: /**
163: * Is type instantiable? That means it cannot be interface or abstract class.
164: * @return true, if instantiable
165: */
166: boolean isInstantiable() {
167: return !Modifier.isAbstract(this .type.getModifiers());
168: }
169:
170: /**
171: * @param discriminatorColumn The discriminatorColumn to set.
172: */
173: void setDiscriminatorColumn(Column discriminatorColumn) {
174: assert this .discriminatorColumn == null;
175: this .discriminatorColumn = discriminatorColumn;
176: this .delegateToResultObjects = new HashMap();
177: }
178:
179: /**
180: * @param instantiator The instantiator to set.
181: */
182: void setInstantiator(ResultObjectInstantiator instantiator) {
183: this .instantiator = instantiator;
184: }
185:
186: /**
187: * Set the values on an already created result object
188: * @param resultObject
189: * @param row
190: */
191: void setValues(Object resultObject, ResultRow row) {
192: for (int i = 0; i < this .setterList.size(); i++) {
193: this .setterList.getSetter(i).setValue(resultObject, row);
194: }
195: }
196:
197: /**
198: * @inheritDoc
199: * @see java.lang.Object#equals(java.lang.Object)
200: */
201: public boolean equals(Object obj) {
202: if (ResultObjectDefinition.class == obj.getClass()) {
203: ResultObjectDefinition comp = (ResultObjectDefinition) obj;
204: return this .id.equals(comp.id)
205: && this .broker.equals(comp.broker);
206: }
207: return false;
208: }
209:
210: /**
211: * @inheritDoc
212: * @see java.lang.Object#hashCode()
213: */
214: public int hashCode() {
215: return this .id.hashCode();
216: }
217:
218: /**
219: * @see java.lang.Object#toString()
220: */
221: public String toString() {
222: return "Result object: " + this.id;
223: }
224:
225: }
|