1 /*** 2 * License Agreement. 3 * 4 * JSPA (POJO-SP) 5 * 6 * Copyright (C) 2009 HRX Pty Ltd 7 * 8 * This file is part of JSPA. 9 * 10 * JSPA is free software: you can redistribute it and/or modify it under the 11 * terms of the GNU Lesser General Public License version 3 as published by the 12 * Free Software Foundation. 13 * 14 * JSPA is distributed in the hope that it will be useful, but WITHOUT ANY 15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 16 * A PARTICULAR PURPOSE. See the Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with JSPA. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 package com.hrx.rasp.util.dao.operation; 22 23 import java.lang.reflect.Field; 24 import java.sql.CallableStatement; 25 import java.sql.ResultSet; 26 import java.sql.SQLException; 27 import java.util.Collection; 28 import java.util.List; 29 30 import org.apache.log4j.Logger; 31 32 import com.hrx.rasp.util.dao.ResultSetProcessor; 33 import com.hrx.rasp.util.dao.StoredProcUtility; 34 import com.hrx.rasp.util.dao.annotations.OUT; 35 import com.hrx.rasp.util.dao.annotations.Secret; 36 import com.hrx.rasp.util.dao.exception.StoredProcedureProccessResultException; 37 import com.hrx.rasp.util.dao.metadata.MetadataHelper; 38 import com.hrx.rasp.util.dao.metadata.StoredProcField; 39 import com.hrx.rasp.util.dao.metadata.StoredProcMetaData; 40 import com.hrx.rasp.util.dao.metadata.StoredProcMetaDataImpl; 41 42 /*** 43 * 44 * The component parse a CallableStatement and convert the response of the 45 * database stored procedure or function into a Java DAO. It parse the 46 * CallableStatement, searching for all in OUT and INOUT parameters defined by 47 * the DAO using the (IN, OUT...) annotations and set the values of the DAO 48 * properties with the returned values. 49 * 50 * The DAO is expected to have public setters and getters for all OUT or INOUT 51 * parameters 52 * 53 * 54 * @author dan.stoica <dan.stoica@acslink.net.au> 55 * 56 */ 57 public class ResponseProcessor 58 { 59 60 private static Logger log = Logger.getLogger(ResponseProcessor.class); 61 62 protected static void processCallableStatement(Object dao, Object embeddedDAO, CallableStatement st, StoredProcMetaDataImpl metaData) 63 throws StoredProcedureProccessResultException 64 { 65 log.debug("DAO: Start Callable Statemen result processing..."); 66 processCallableStatement(dao, st, metaData); 67 if (metaData.isEmbeddedId()) 68 { 69 processCallableStatement(embeddedDAO, st, metaData.getEmbeddedIdMetaData()); 70 } 71 log.debug("DAO: End Callable Statemen Result processing."); 72 } 73 74 protected static void processCallableStatement(Object dao, CallableStatement st, StoredProcMetaData metaData) 75 throws StoredProcedureProccessResultException 76 { 77 Integer index = null; 78 String fieldName = null; 79 Class<?> fieldClass = null; 80 try 81 { 82 for (StoredProcField<OUT> parameter : metaData.getOutParameters()) 83 { 84 Object value = null; 85 OUT param = parameter.getParameter(); 86 Field field = parameter.getField(); 87 88 index = param.index(); 89 fieldClass = field.getType(); 90 value = StoredProcUtility.getCallableStatementObject(st, index, fieldClass); 91 if (value instanceof ResultSet && metaData instanceof StoredProcMetaDataImpl) 92 { 93 StoredProcMetaDataImpl mdSP = (StoredProcMetaDataImpl) metaData; 94 95 boolean isSecret = field.isAnnotationPresent(Secret.class); 96 97 value = processResultSetParameter((ResultSet) value, param, mdSP.getStartPosition(), mdSP.getMaxResult(), isSecret); 98 if (log.isDebugEnabled()) 99 { 100 log.debug("RESPONSE for " + dao.getClass().getSimpleName() + ". RowSet for field name:" + field.getName() + " contains:'" 101 + ((Collection<?>) value).size() + "' rows."); 102 } 103 } 104 105 if (log.isDebugEnabled()) 106 { 107 if (field.isAnnotationPresent(Secret.class)) 108 { 109 log.debug("RESPONSE for " + dao.getClass().getSimpleName() + ". Set field name:" + field.getName() + "; value ='*****'"); 110 } 111 else 112 { 113 log.debug("RESPONSE for " + dao.getClass().getSimpleName() + ". Set field name:" + field.getName() + "; value ='" + value 114 + "'"); 115 } 116 } 117 118 MetadataHelper.setPropertyValue(field, value, dao); 119 } 120 } 121 catch (StoredProcedureProccessResultException ex) 122 { 123 throw ex; 124 } 125 catch (Exception sqle) 126 { 127 try 128 { 129 log.error("DAO: SQLException getting ResultSet column# " + index + "( " + st.getMetaData().getColumnName(index) + ")" + " as " 130 + fieldClass + " for field " + fieldName); 131 } 132 catch (Throwable e) 133 { 134 log.error("DAO: SQLException getting Column name: 'rs.getMetaData().getColumnName(key)' type:" + fieldClass + " for field " 135 + fieldName); 136 } 137 138 throw new StoredProcedureProccessResultException(sqle); 139 } 140 } 141 142 /*** 143 * Process the CURSOR type parameters returned by Stored Procedure. 144 * 145 * It releases this <code>ResultSet</code> object's database resources 146 * immediately instead of waiting for this to happen when it is 147 * automatically closed. 148 * 149 * <P> 150 * The closing of a <code>ResultSet</code> object does <strong>not</strong> 151 * close the <code>Blob</code>, <code>Clob</code> or <code>NClob</code> 152 * objects created by the <code>ResultSet</code>. <code>Blob</code>, 153 * <code>Clob</code> or <code>NClob</code> objects remain valid for at least 154 * the duration of the transaction in which they are created, unless their 155 * <code>free</code> method is invoked. 156 * <p> 157 * 158 * @param startPosition 159 * @param maxResult 160 * 161 * 162 * @param st 163 * @param index 164 * @param cursorResponseBuilder 165 * @return 166 * @throws SQLException 167 * @throws StoredProcedureProccessResultException 168 */ 169 @SuppressWarnings("unchecked") 170 public static <E> Collection<E> processResultSetParameter(ResultSet rs, OUT param, int startPosition, int maxResult, boolean isSecret) 171 throws SQLException, StoredProcedureProccessResultException 172 { 173 long startTime = 0; 174 Collection<E> result = null; 175 try 176 { 177 Class<E> resultSetReturnClass = (Class<E>) param.collectionType(); 178 Class<ResultSetProcessor<E>> resultSetProcessorClass = (Class<ResultSetProcessor<E>>) param.resultSetProcessor(); 179 180 if (log.isTraceEnabled()) 181 { 182 startTime = System.currentTimeMillis(); 183 } 184 result = processResultSetParameter(rs, resultSetProcessorClass, resultSetReturnClass, startPosition, maxResult, isSecret); 185 return result; 186 } 187 catch (Exception e) 188 { 189 throw new StoredProcedureProccessResultException(e); 190 } 191 finally 192 { 193 rs.close(); 194 195 if (log.isTraceEnabled()) 196 { 197 String records = "?"; 198 if (result != null) 199 { 200 records = result.size() + ""; 201 } 202 log.trace("DAO: Result Set with " + records + " records, processed in :" + StoredProcUtility.duration(startTime) + " seconds."); 203 } 204 } 205 } 206 207 public static <E> List<E> processResultSetParameter(ResultSet rs, Class<ResultSetProcessor<E>> resultSetProcessorClass, 208 Class<E> resultSetReturnClass, int startPosition, int maxResult, boolean isSecret) throws SQLException, 209 StoredProcedureProccessResultException, InstantiationException, IllegalAccessException 210 { 211 212 ResultSetProcessor<E> processor; 213 processor = (ResultSetProcessor<E>) resultSetProcessorClass.newInstance(); 214 processor.setMaxResult(maxResult); 215 processor.setStartPosition(startPosition); 216 217 List<E> result = processor.create(rs, resultSetReturnClass, isSecret); 218 219 return result; 220 } 221 }