001: package org.julp;
002:
003: import java.beans.*;
004: import java.util.*;
005: import java.lang.reflect.*;
006:
007: /**
008: * Normally to make your object able to persist you need to extend this object
009: * If you can't or don't want to extend, just make your class
010: * implement org.julp.DomainObject interface and copy and paste members
011: * and methods from org.julp.AbstractDomainObject into your class.
012: */
013:
014: public abstract class AbstractDomainObject implements DomainObject,
015: java.io.Serializable, Cloneable {
016:
017: protected DataHolder originalValues = null;
018: protected int objectId = 0;
019: protected char persistentState = UNDEFINED;
020: protected boolean loaded = false;
021: protected boolean loading = false;
022: protected boolean modified = false;
023: protected Map displayValues;
024: protected static Object[] EMPTY_READ_ARG = new Object[0];
025: protected long domainFactoryId = -1;
026: protected String charset = "UTF-8";
027:
028: public String toString() {
029: StringBuffer sb = new StringBuffer();
030: Object value = null;
031: Method[] methods = getClass().getMethods();
032: for (int i = 0; i < methods.length; i++) {
033: String methodName = methods[i].getName();
034: if (methodName.equals("getValuesAsHtml")
035: || methodName.equals("getClass")) {
036: continue;
037: }
038: if ((methodName.startsWith("get") || methodName
039: .startsWith("is"))
040: && methods[i].getParameterTypes().length == 0) {
041: try {
042: value = readValue(methods[i]);
043: } catch (Throwable t) {
044: continue;
045: }
046: String fieldFirstChar = "";
047: if (methodName.startsWith("is")) {
048: fieldFirstChar = methodName.substring(2, 3)
049: .toLowerCase();
050: sb.append(fieldFirstChar);
051: sb.append(methodName.substring(3));
052: } else if (methodName.startsWith("get")) {
053: fieldFirstChar = methodName.substring(3, 4)
054: .toLowerCase();
055: sb.append(fieldFirstChar);
056: sb.append(methodName.substring(4));
057: }
058: sb.append("=");
059: sb.append((value == null) ? "" : value);
060: sb.append("&");
061: }
062: }
063: sb.append("displayValues="
064: + (displayValues == null ? "" : displayValues
065: .toString()));
066: return sb.toString();
067: }
068:
069: public void setOriginalValues(DataHolder originalValues) {
070: this .originalValues = originalValues;
071: }
072:
073: public DataHolder getOriginalValues() {
074: return this .originalValues;
075: }
076:
077: public void setOriginalValue(String fieldName, Object value) {
078: if (originalValues == null) {
079: throw new IllegalArgumentException(
080: "setOriginalValue: DataHolder not set");
081: }
082: originalValues.setObject(fieldName, value);
083: }
084:
085: public Object getOriginalValue(String fieldName) {
086: Object value = (originalValues == null) ? null : originalValues
087: .getObject(fieldName);
088: return value;
089: }
090:
091: public char getPersistentState() {
092: return persistentState;
093: }
094:
095: public void setPersistentState(char persistentState) {
096: this .persistentState = persistentState;
097: }
098:
099: /** Getter for property objectId.
100: * @return Value of property objectId.
101: *
102: */
103: public int getObjectId() {
104: return objectId;
105: }
106:
107: /**
108: * Every time DomainObjectFactory is loaded this object it assigned objectId
109: * which is valid only for the same DomainObjectFactory (see domainFactoryId)
110: * if DomainObject's objectId used with other DomainObjectFactory it gets new objectId
111: * when used with DomainObjectFactory.[setObject(...), load(), create(), store(), remove()
112: */
113:
114: public void setObjectId(int objectId) {
115: this .objectId = objectId;
116: }
117:
118: // just mark for data modification, actual modification done in DomainObjectFactory -> DataWriter
119: // normally this methods called from DomainObjectFactory.[create(DomainObject), store(DomainObject), remove(DomainObject)]
120: public boolean store() {
121: if (originalValues != null
122: && originalValues.getFieldCount() > 0) {
123: setPersistentState(STORED);
124: return true;
125: }
126: return false;
127: }
128:
129: public boolean remove() {
130: if (originalValues != null
131: && originalValues.getFieldCount() > 0) {
132: setPersistentState(REMOVED);
133: return true;
134: }
135: return false;
136: }
137:
138: public boolean create() {
139: if (originalValues == null
140: || originalValues.getFieldCount() < 1) {
141: setPersistentState(CREATED);
142: return true;
143: }
144: return false;
145: }
146:
147: // populate originalValues with values from DomainObject.
148: public boolean syncOriginal() {
149: boolean sync = false;
150: if (originalValues != null
151: && originalValues.getFieldCount() > 0) {
152: try {
153: setPersistentState(ORIGINAL);
154: for (int fieldIndex = 1; fieldIndex <= originalValues
155: .getFieldCount(); fieldIndex++) {
156: String fieldName = originalValues
157: .getFieldName(fieldIndex);
158: PropertyDescriptor pd = new PropertyDescriptor(
159: fieldName, this .getClass());
160: Object value = readValue(pd.getReadMethod());
161: originalValues.setObject(fieldIndex, value);
162: }
163: sync = true;
164: setModified(false);
165: } catch (Throwable t) {
166: throw new RuntimeException(t);
167: }
168: }
169: return sync;
170: }
171:
172: // populate DomainObject with values from originalValues.
173: public boolean load() {
174: setLoading(true);
175: if (originalValues != null
176: && originalValues.getFieldCount() > 0) {
177: try {
178: List param = new ArrayList(1);
179: for (int fieldIndex = 1; fieldIndex <= originalValues
180: .getFieldCount(); fieldIndex++) {
181: param.clear();
182: String fieldName = originalValues
183: .getFieldName(fieldIndex);
184: Object value = originalValues.getObject(fieldIndex);
185: PropertyDescriptor pd = new PropertyDescriptor(
186: fieldName, this .getClass());
187: param.add(value);
188: writeValue(pd.getWriteMethod(), param.toArray());
189: }
190: } catch (Throwable t) {
191: throw new RuntimeException(t);
192: }
193: setLoading(false);
194: setLoaded(true);
195: setModified(false);
196: return true;
197: }
198: setLoading(false);
199: return false;
200: }
201:
202: /** Getter for property loaded.
203: * @return Value of property loaded.
204: *
205: */
206: public boolean isLoaded() {
207: return loaded;
208: }
209:
210: /** Setter for property loaded.
211: * @param loaded New value of property loaded.
212: *
213: */
214: public void setLoaded(boolean loaded) {
215: this .setPersistentState(ORIGINAL);
216: this .loaded = loaded;
217: }
218:
219: /**
220: * This is convinient method to use with JSP.
221: * Make sure not to call this method from another method
222: * of this object (or subclass) started with "get",
223: * or you will get endless loop
224: */
225:
226: public java.lang.String getValuesAsHtml() {
227: StringBuffer sb = new StringBuffer();
228: Object value = null;
229: Method[] methods = getClass().getMethods();
230: for (int i = 0; i < methods.length; i++) {
231: String methodName = methods[i].getName();
232: if (methodName.equals("getValuesAsHtml")
233: || methodName.equals("getClass")) {
234: continue;
235: }
236: if ((methodName.startsWith("get") || methodName
237: .startsWith("is"))
238: && methods[i].getParameterTypes().length == 0) {
239: try {
240: value = readValue(methods[i]);
241: } catch (Throwable t) {
242: continue;
243: }
244: String fieldFirstChar = "";
245: if (methodName.startsWith("is")) {
246: fieldFirstChar = methodName.substring(2, 3)
247: .toLowerCase();
248: sb.append(fieldFirstChar);
249: sb.append(methodName.substring(3));
250: } else if (methodName.startsWith("get")) {
251: fieldFirstChar = methodName.substring(3, 4)
252: .toLowerCase();
253: sb.append(fieldFirstChar);
254: sb.append(methodName.substring(4));
255: }
256: sb.append("=");
257: if (value == null) {
258: sb.append("");
259: } else {
260: try {
261: sb.append(java.net.URLEncoder.encode(value
262: .toString(), charset));
263: } catch (java.io.UnsupportedEncodingException uee) {
264: throw new RuntimeException(uee);
265: }
266: }
267: sb.append("&");
268: }
269: }
270: sb.deleteCharAt(sb.length() - 1);
271: return sb.toString();
272: }
273:
274: /**
275: * Indicator that this object in proccess of loading with values from database
276: */
277:
278: public boolean isLoading() {
279: return this .loading;
280: }
281:
282: public void setLoading(boolean loading) {
283: this .loading = loading;
284: }
285:
286: /**
287: * Indicator that this object is modified. You have to call it yourself
288: *
289: */
290: public boolean isModified() {
291: return this .modified;
292: }
293:
294: public void setModified(boolean modified) {
295: this .modified = modified;
296: }
297:
298: /**
299: * Display value for given field. Example:
300: * field value is "123" but display must be "XYZ"
301: */
302: public void setDisplayValue(String field, Object displayValue) {
303: if (displayValues == null)
304: displayValues = new HashMap();
305: displayValues.put(field, displayValue);
306: }
307:
308: public Object getDisplayValue(String fieldName) {
309: Object display;
310: try {
311: if (displayValues == null) {
312: PropertyDescriptor pDesc = new PropertyDescriptor(
313: fieldName, this .getClass());
314: display = readValue(pDesc.getReadMethod());
315: } else {
316: display = displayValues.get(fieldName);
317: }
318: } catch (Throwable t) {
319: throw new RuntimeException(t);
320: }
321: return display;
322: }
323:
324: public void setDomainFactoryId(long domainFactoryId) {
325: this .domainFactoryId = domainFactoryId;
326: }
327:
328: public long getDomainFactoryId() {
329: return this .domainFactoryId;
330: }
331:
332: protected void writeValue(Method method, Object[] value)
333: throws Throwable {
334: try {
335: method.invoke(this , value);
336: } catch (Throwable t) {
337: if (t instanceof InvocationTargetException) {
338: throw ((InvocationTargetException) t)
339: .getTargetException();
340: } else {
341: throw t;
342: }
343: }
344: }
345:
346: protected Object readValue(Method method) throws Throwable {
347: Object value = null;
348: try {
349: value = method.invoke(this , EMPTY_READ_ARG);
350: } catch (Throwable t) {
351: if (t instanceof InvocationTargetException) {
352: throw ((InvocationTargetException) t)
353: .getTargetException();
354: } else {
355: throw t;
356: }
357: }
358: return value;
359: }
360: }
|