001: /*
002: * transformica 2
003: * Code generator
004: * Copyright (C) 2004 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.pavelvlasov.com/pv/content/menu.show@id=products.transformica.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.transformica.jdbc;
024:
025: import java.lang.reflect.InvocationHandler;
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Proxy;
028: import java.sql.ResultSet;
029: import java.sql.ResultSetMetaData;
030: import java.sql.SQLException;
031: import java.util.HashMap;
032: import java.util.Map;
033:
034: import org.apache.bcel.Constants;
035: import org.apache.bcel.generic.ClassGen;
036: import org.apache.bcel.generic.InstructionList;
037: import org.apache.bcel.generic.MethodGen;
038: import org.apache.bcel.generic.Type;
039: import org.apache.commons.jxpath.JXPathContext;
040: import org.apache.tools.ant.Project;
041: import org.apache.tools.ant.Task;
042:
043: import biz.hammurapi.config.Context;
044: import biz.hammurapi.util.Visitable;
045: import biz.hammurapi.util.Visitor;
046:
047: /**
048: * @author Pavel Vlasov
049: * @version $Revision: 1.1 $
050: */
051: public class ResultSetInvocationHandler implements InvocationHandler {
052: private ResultSet resultSet;
053: private static int[] counter = { 0 };
054: private static final String BASE_CLASS_NAME = "biz.hammurapi.transformica.jdbc.ResultSetWrapper_";
055: private Object proxy;
056: private JXPathContext jxPathContext;
057: private Task task;
058:
059: private String generateClassName() {
060: synchronized (counter) {
061: return BASE_CLASS_NAME + counter[0]++;
062: }
063: }
064:
065: public ResultSetInvocationHandler(ClassLoader classLoader,
066: ResultSet resultSet, Task task) throws SQLException {
067: super ();
068: this .resultSet = resultSet;
069: this .task = task;
070: ClassGen cg = new ClassGen(generateClassName(),
071: "java.lang.Object", "<generated>", Constants.ACC_PUBLIC
072: | Constants.ACC_INTERFACE, null);
073:
074: ResultSetMetaData metaData = resultSet.getMetaData();
075: int cc = metaData.getColumnCount();
076: for (int i = 1; i <= cc; i++) {
077: InstructionList emptyInstructionList = new InstructionList();
078: String columnName = formatColumnName(metaData
079: .getColumnName(i));
080: task.log("Column: " + columnName, Project.MSG_DEBUG);
081: MethodGen mg = new MethodGen(Constants.ACC_PUBLIC
082: | Constants.ACC_ABSTRACT, Type.STRING, null, null,
083: "get" + columnName, cg.getClassName(),
084: emptyInstructionList, cg.getConstantPool());
085:
086: cg.addMethod(mg.getMethod());
087: emptyInstructionList.dispose();
088: }
089:
090: InjectingClassLoader icl = new InjectingClassLoader(classLoader);
091: proxy = Proxy.newProxyInstance(icl, new Class[] {
092: Visitable.class, icl.defineClass(cg), Context.class },
093: this );
094:
095: jxPathContext = JXPathContext.newContext(proxy);
096: jxPathContext.setLenient(true);
097: }
098:
099: private boolean accept(Visitor visitor) {
100: try {
101: try {
102: int row = 0;
103: while (resultSet.next()) {
104: task.log("Row: " + row++, Project.MSG_DEBUG);
105: fieldCache.clear();
106: if (!visitor.visit((Visitable) proxy)) {
107: return false;
108: }
109: }
110: return true;
111: } finally {
112: resultSet.close();
113: }
114: } catch (SQLException e) {
115: e.printStackTrace();
116: return false;
117: }
118: }
119:
120: private String formatColumnName(String columnName) {
121: if (columnName == null) {
122: return columnName;
123: } else {
124: switch (columnName.length()) {
125: case 0:
126: return columnName;
127: case 1:
128: return columnName.toUpperCase();
129: default:
130: return columnName.substring(0, 1).toUpperCase()
131: + columnName.substring(1).toLowerCase();
132: }
133: }
134: }
135:
136: public Object invoke(Object proxy, Method method, Object[] args)
137: throws Throwable {
138: task.log("Invoke: " + method.toString(), Project.MSG_DEBUG);
139: try {
140: Object ret;
141: if ("accept".equals(method.getName())
142: && argCount(args) == 1
143: && args[0] instanceof Visitor) {
144: ret = accept((Visitor) args[0]) ? Boolean.TRUE
145: : Boolean.FALSE;
146: } else if (method.getName().startsWith("get")
147: && argCount(args) == 0) {
148: ret = getFieldValue(method);
149: } else if ("iterate".equals(method.getName())
150: && argCount(args) == 1 && args[0] instanceof String) {
151: ret = jxPathContext.iterate((String) args[0]);
152: } else if ("navigate".equals(method.getName())
153: && argCount(args) == 1 && args[0] instanceof String) {
154: ret = jxPathContext.getValue((String) args[0]);
155: } else {
156: ret = method.invoke(this , args); // Invoke Object's methods.
157: }
158: task.log("Return: " + ret, Project.MSG_DEBUG);
159: return ret;
160: } catch (Throwable th) {
161: th.printStackTrace();
162: throw th;
163: }
164: }
165:
166: private Map fieldCache = new HashMap();
167:
168: private String getFieldValue(Method method) throws SQLException {
169: String fieldName = method.getName().substring(3);
170: task.log("Reading field: " + fieldName, Project.MSG_DEBUG);
171: if (!fieldCache.containsKey(fieldName)) {
172: fieldCache.put(fieldName, resultSet.getString(fieldName));
173: }
174: return (String) fieldCache.get(fieldName);
175: }
176:
177: private int argCount(Object[] args) {
178: return args == null ? 0 : args.length;
179: }
180:
181: public Object getProxy() {
182: return proxy;
183: }
184: }
|