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 }