View Javadoc
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 }