001: /*
002: * hgcommons 7
003: * Hammurapi Group Common Library
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.sql.columns;
024:
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.sql.PreparedStatement;
028: import java.sql.ResultSet;
029: import java.sql.ResultSetMetaData;
030: import java.sql.SQLException;
031: import java.util.Collection;
032: import java.util.Collections;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.LinkedList;
036: import java.util.Map;
037:
038: import biz.hammurapi.config.Context;
039: import biz.hammurapi.convert.CompositeConverter;
040: import biz.hammurapi.sql.SQLExceptionEx;
041:
042: /**
043: * @author Pavel Vlasov
044: *
045: * @version $Revision: 1.13 $
046: */
047: public class ObjectColumn extends Column {
048: private Object value;
049:
050: // Original stuff
051: private Object originalValue;
052: private boolean isOriginalValueSet;
053:
054: public Object getOriginalValue() {
055: return isOriginalValueSet ? originalValue : value;
056: }
057:
058: public void parameterizeOriginal(PreparedStatement ps, int idx)
059: throws SQLException {
060: Object theOriginalValue = getOriginalValue();
061: if (theOriginalValue == null) {
062: ps.setNull(idx, sqlType == null ? java.sql.Types.NULL
063: : sqlType.intValue());
064: } else {
065: try {
066: Method setter = findSetter(theOriginalValue.getClass());
067: if ("setObject".equals(setter.getName())) {
068: if (sqlType == null) {
069: ps.setObject(idx, theOriginalValue);
070: } else {
071: ps.setObject(idx, theOriginalValue, sqlType
072: .intValue());
073: }
074: } else {
075: setter.invoke(ps, new Object[] { new Integer(idx),
076: theOriginalValue });
077: }
078: return;
079: } catch (IllegalArgumentException e) {
080: throw new SQLException("Caused by: " + e);
081: } catch (IllegalAccessException e) {
082: throw new SQLException("Caused by: " + e);
083: } catch (InvocationTargetException e) {
084: throw new SQLException("Caused by: " + e);
085: }
086: }
087: }
088:
089: public void setOriginal() {
090: originalValue = value;
091: isOriginalValueSet = true;
092: }
093:
094: // End of original stuff
095:
096: private static final Collection ALL_SETTERS;
097:
098: private Integer sqlType;
099:
100: static {
101: Collection allSetters = new LinkedList();
102: for (int i = 0, mc = PreparedStatement.class.getMethods().length; i < mc; i++) {
103: Method m = PreparedStatement.class.getMethods()[i];
104: if (m.getParameterTypes().length == 2
105: && m.getParameterTypes()[0].equals(int.class)
106: && m.getName().startsWith("set")) {
107: allSetters.add(m);
108: }
109: }
110: ALL_SETTERS = Collections.unmodifiableCollection(allSetters);
111: }
112:
113: /**
114: * @return Returns the value.
115: */
116: public Object getValue() {
117: return value;
118: }
119:
120: /**
121: * @param value The value to set.
122: */
123: public void setValue(Object value) {
124: if (force
125: || (this .value != value && (this .value == null || !this .value
126: .equals(value)))) {
127: if (clazz != null && value != null
128: && !clazz.isInstance(value)) {
129: throw new ClassCastException("Invalid class "
130: + value.getClass().getName() + ", expected "
131: + clazz.getName());
132: }
133: this .value = value;
134: onChange();
135: }
136: }
137:
138: public void setSqlType(int sqlType) {
139: this .sqlType = new Integer(sqlType);
140: }
141:
142: /**
143: * @param name
144: * @param clazz Column class, can be null.
145: * @param isPrimaryKey
146: */
147: public ObjectColumn(String name, Class clazz, boolean isPrimaryKey) {
148: super (name, isPrimaryKey);
149: this .clazz = clazz;
150: }
151:
152: public ObjectColumn(String name, Class clazz, boolean isPrimaryKey,
153: Object value) {
154: super (name, isPrimaryKey);
155: this .clazz = clazz;
156: if (clazz != null && value != null && !clazz.isInstance(value)) {
157: throw new ClassCastException("Invalid class "
158: + value.getClass().getName() + ", expected "
159: + clazz.getName());
160: }
161: this .value = value;
162: }
163:
164: public ObjectColumn(String name, Class clazz, boolean isPrimaryKey,
165: ResultSet rs) throws SQLException {
166: super (name, isPrimaryKey);
167: this .clazz = clazz;
168: ResultSetMetaData metaData = rs.getMetaData();
169: for (int i = 1, c = metaData.getColumnCount(); i <= c; i++) {
170: if (name.equals(metaData.getColumnName(i))) {
171: Object value = rs.getObject(i);
172: if (clazz != null && value != null
173: && !clazz.isInstance(value)) {
174: throw new ClassCastException("Invalid class "
175: + value.getClass().getName()
176: + ", expected " + clazz.getName());
177: }
178: this .value = value;
179: break;
180: }
181: }
182: }
183:
184: private static Map setterMap = new HashMap();
185:
186: private static Method findSetter(Class type) {
187: synchronized (setterMap) {
188: String typeName = type.getName();
189: Method ret = (Method) setterMap.get(typeName);
190: if (ret == null) {
191: int dotIdx = typeName.lastIndexOf('.');
192: String shortName = typeName.substring(dotIdx + 1,
193: dotIdx + 2).toUpperCase()
194: + typeName.substring(dotIdx + 2);
195:
196: // Name match
197: Iterator it = ALL_SETTERS.iterator();
198: while (it.hasNext()) {
199: Method m = (Method) it.next();
200: if (m.getName().equals("set" + shortName)
201: && m.getParameterTypes()[1].getName()
202: .equals(typeName)) {
203: setterMap.put(typeName, m);
204: return m;
205: }
206: }
207:
208: Method candidate = null;
209: // Parameter match
210: it = ALL_SETTERS.iterator();
211: while (it.hasNext()) {
212: Method m = (Method) it.next();
213: if (m.getParameterTypes()[1].isAssignableFrom(type)) {
214: if (candidate == null
215: || candidate.getParameterTypes()[1]
216: .isAssignableFrom(m
217: .getParameterTypes()[1])) {
218: candidate = m;
219: }
220: }
221: }
222:
223: setterMap.put(typeName, candidate);
224: return candidate;
225: }
226:
227: return ret;
228: }
229: }
230:
231: /* (non-Javadoc)
232: * @see biz.hammurapi.sql.columns.Column#parameterize(java.sql.PreparedStatement, int)
233: */
234: protected void parameterizeInternal(PreparedStatement ps, int idx)
235: throws SQLException {
236: try {
237: if (value == null) {
238: ps.setNull(idx, sqlType == null ? java.sql.Types.NULL
239: : sqlType.intValue());
240: } else {
241: try {
242: Method setter = findSetter(value.getClass());
243: if ("setObject".equals(setter.getName())) {
244: if (sqlType == null) {
245: ps.setObject(idx, value);
246: } else {
247: ps
248: .setObject(idx, value, sqlType
249: .intValue());
250: }
251: } else {
252: setter.invoke(ps, new Object[] {
253: new Integer(idx), value });
254: }
255: return;
256: } catch (IllegalArgumentException e) {
257: throw new SQLExceptionEx("Could not parameterize "
258: + getName() + ": " + e, e);
259: } catch (IllegalAccessException e) {
260: throw new SQLExceptionEx("Could not parameterize "
261: + getName() + ": " + e, e);
262: } catch (InvocationTargetException e) {
263: throw new SQLExceptionEx("Could not parameterize "
264: + getName() + ": " + e, e);
265: }
266: }
267: } catch (SQLException e) {
268: throw new SQLExceptionEx("Cannot parameterize. Value: "
269: + value + ", SQL Type: " + sqlType + ", Cause: "
270: + e, e);
271: }
272: }
273:
274: /**
275: * Parameterizes prepared statement. Automatically finds proper setter.
276: * @param ps
277: * @param value
278: * @param idx
279: * @throws SQLException
280: */
281: public static void parameterize(PreparedStatement ps, Object value,
282: int idx) throws SQLException {
283: try {
284: if (value == null) {
285: ps.setNull(idx, java.sql.Types.NULL);
286: } else {
287: try {
288: Method setter = findSetter(value.getClass());
289: if ("setObject".equals(setter.getName())) {
290: ps.setObject(idx, value);
291: } else {
292: setter.invoke(ps, new Object[] {
293: new Integer(idx), value });
294: }
295: return;
296: } catch (IllegalArgumentException e) {
297: throw new SQLExceptionEx("Could not parameterize: "
298: + e, e);
299: } catch (IllegalAccessException e) {
300: throw new SQLExceptionEx("Could not parameterize: "
301: + e, e);
302: } catch (InvocationTargetException e) {
303: throw new SQLExceptionEx("Could not parameterize: "
304: + e, e);
305: }
306: }
307: } catch (SQLException e) {
308: throw new SQLExceptionEx("Cannot parameterize. Value: "
309: + value + ", Cause: " + e, e);
310: }
311: }
312:
313: public Object getObjectValue(boolean ov) {
314: if (ov) {
315: return isOriginalValueSet ? originalValue : null;
316: }
317: return value;
318: }
319:
320: public String toString() {
321: return getName() + (isModified() ? "*" : "") + "("
322: + (value == null ? "N/A" : value.getClass().getName())
323: + ")=" + value;
324: }
325:
326: public boolean equals(Object otherColumn) {
327: if (!(otherColumn instanceof ObjectColumn)) {
328: return false;
329: }
330:
331: Object otherValue = ((ObjectColumn) otherColumn).value;
332: if (value == null) {
333: return otherValue == null;
334: }
335:
336: if (otherValue == null) {
337: return false;
338: }
339:
340: return value.equals(otherValue);
341: }
342:
343: public int hashCode() {
344: return getName().hashCode()
345: ^ (value == null ? 0 : value.hashCode());
346: }
347:
348: public void load(String textValue) {
349: if (clazz == null || textValue == null) {
350: setValue(textValue);
351: } else {
352: setValue(CompositeConverter.getDefaultConverter().convert(
353: textValue, clazz, false));
354: }
355: }
356:
357: public void clear() {
358: setValue(null);
359: clearModified();
360: }
361:
362: private Class clazz;
363:
364: public void configure(Context context, CompositeConverter converter) {
365: Object o = context.get(getName());
366: if (o != null) {
367: setValue(clazz == null ? o : converter.convert(o, clazz,
368: false));
369: }
370: }
371:
372: protected String getType() {
373: return clazz == null ? "java.lang.Object" : clazz.getName();
374: }
375:
376: public void set(Column source) {
377: setValue(((ObjectColumn) source).getValue());
378: }
379:
380: /**
381: * Clears modified flag and sets original value to current value.
382: */
383: public void clearModified() {
384: super.clearModified();
385: originalValue = value;
386: }
387: }
|