001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.sql; 005 006 import java.io.Serializable; 007 import java.lang.reflect.InvocationHandler; 008 import java.lang.reflect.Method; 009 import java.lang.reflect.Proxy; 010 import java.sql.ResultSet; 011 import java.sql.SQLException; 012 import java.util.ArrayList; 013 import java.util.Collections; 014 import java.util.HashMap; 015 import java.util.Iterator; 016 import java.util.List; 017 import java.util.Map; 018 import java.util.Map.Entry; 019 020 import org.w3c.dom.Element; 021 022 import biz.hammurapi.convert.CompositeConverter; 023 024 /** 025 * @author Pavel Vlasov 026 * @version $Revision: 1.5 $ 027 */ 028 public class InterfaceProjector extends BaseReflectionProjector implements Projector { 029 private Class theInterface; 030 private Object delegate; 031 032 /** 033 * @param typeMap 034 * @param theInterface Iterface projected object should implement. 035 */ 036 public InterfaceProjector(Class theInterface, Map typeMap) { 037 super(typeMap); 038 this.theInterface=theInterface; 039 } 040 041 /** 042 * @param typeMap 043 * @param delegate Object to delegate unmatched calls to. 044 * @param theInterface Iterface projected object should implement. 045 */ 046 public InterfaceProjector(Class theInterface, Object delegate, Map typeMap) { 047 super(typeMap); 048 this.theInterface=theInterface; 049 this.delegate=delegate; 050 } 051 052 private static Map primitivesMap=new HashMap(); 053 054 static { 055 primitivesMap.put(int.class, java.lang.Integer.class); 056 primitivesMap.put(boolean.class, java.lang.Boolean.class); 057 primitivesMap.put(byte.class, java.lang.Byte.class); 058 primitivesMap.put(char.class, java.lang.Character.class); 059 primitivesMap.put(double.class, java.lang.Double.class); 060 primitivesMap.put(float.class, java.lang.Float.class); 061 primitivesMap.put(long.class, java.lang.Long.class); 062 primitivesMap.put(short.class, java.lang.Short.class); 063 } 064 065 class ResultSetInvocationHandler implements InvocationHandler, Serializable { 066 /** 067 * Comment for <code>serialVersionUID</code> 068 */ 069 private static final long serialVersionUID = -971624963614852201L; 070 Map fieldMap; 071 072 public ResultSetInvocationHandler(Map fieldMap) { 073 this.fieldMap=fieldMap; 074 } 075 076 077 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 078 if (method.getName().length()>3) { 079 String key = method.getName().substring(3); 080 if (method.getName().startsWith("get") && method.getParameterTypes().length==0 && fieldMap.containsKey(key)) { 081 Class prt=(Class) primitivesMap.get(method.getReturnType()); 082 Object value = fieldMap.get(key); 083 if (value==null) { 084 if (prt==null) { 085 return null; 086 } 087 088 throw new IllegalArgumentException("Cannot convert 'null' to "+method.getReturnType()); 089 } 090 091 Object ret = CompositeConverter.getDefaultConverter().convert(value, method.getReturnType(), false); 092 if (ret==null && prt!=null) { 093 ret = CompositeConverter.getDefaultConverter().convert(value, prt, false); 094 } 095 096 if (ret==null) { 097 throw new IllegalArgumentException( 098 "Cannot convert " + 099 (value==null ? "null" : value.getClass()+" '"+value+"'") + 100 " to " + 101 method.getReturnType().getName()); 102 } 103 104 return ret; 105 } else if (method.getName().startsWith("set") && method.getParameterTypes().length==1 && fieldMap.containsKey(key)) { 106 fieldMap.put(key, args[0]); 107 return null; 108 } 109 } 110 111 if ("toString".equals(method.getName()) && method.getParameterTypes().length==0) { 112 StringBuffer ret=new StringBuffer(theInterface.getName()); 113 ret.append(" ["); 114 List fields=new ArrayList(fieldMap.keySet()); 115 Collections.sort(fields); 116 Iterator it=fields.iterator(); 117 while (it.hasNext()) { 118 ret.append(" "); 119 String key=(String) it.next(); 120 ret.append(key); 121 ret.append(" = "); 122 ret.append(fieldMap.get(key)); 123 if (it.hasNext()) { 124 ret.append(";"); 125 } 126 } 127 return ret.append(" ]").toString(); 128 } 129 130 if ("toDom".equals(method.getName()) && method.getParameterTypes().length==1 && Element.class.isAssignableFrom(method.getParameterTypes()[0])) { 131 Element holder=(Element) args[0]; 132 Iterator it=fieldMap.entrySet().iterator(); 133 while (it.hasNext()) { 134 Map.Entry entry=(Entry) it.next(); 135 Element fieldElement=holder.getOwnerDocument().createElement((String) entry.getKey()); 136 holder.appendChild(fieldElement); 137 if (entry.getValue()!=null) { 138 fieldElement.setAttribute("type", entry.getValue().getClass().getName()); 139 fieldElement.appendChild(fieldElement.getOwnerDocument().createTextNode(entry.getValue().toString())); 140 } 141 } 142 } 143 144 return (delegate==null ? fieldMap : delegate).getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(delegate, args); 145 } 146 147 } 148 149 public Object project(ResultSet rs) throws SQLException { 150 final Map fieldMap=new HashMap(); 151 for (int i=1, c=rs.getMetaData().getColumnCount(); i<=c; i++) { 152 fieldMap.put(accessorName(rs.getMetaData().getColumnName(i)).substring(3), rs.getObject(i)); 153 } 154 155 return Proxy.newProxyInstance(theInterface.getClassLoader(), new Class[] {theInterface}, new ResultSetInvocationHandler(fieldMap)); 156 } 157 }