Skip to content

Commit 06b758a

Browse files
committed
Reduced use of JdbcTemlate
1 parent fd7726a commit 06b758a

38 files changed

+621
-290
lines changed

logicaldoc-core/src/main/java/com/logicaldoc/core/history/HibernatePersistentObjectDAO.java renamed to logicaldoc-core/src/main/java/com/logicaldoc/core/HibernatePersistentObjectDAO.java

Lines changed: 172 additions & 194 deletions
Large diffs are not rendered by default.
Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
package com.logicaldoc.core;
2+
3+
import java.sql.Connection;
4+
import java.sql.PreparedStatement;
5+
import java.sql.ResultSet;
6+
import java.sql.SQLException;
7+
import java.sql.Statement;
8+
import java.sql.Timestamp;
9+
import java.util.Date;
10+
import java.util.HashMap;
11+
import java.util.LinkedList;
12+
import java.util.List;
13+
import java.util.Map;
14+
15+
/**
16+
* This class wraps around a {@link PreparedStatement} and allows the programmer
17+
* to set parameters by name instead of by index. This eliminates any confusion
18+
* as to which parameter index represents what. This also means that rearranging
19+
* the SQL statement or adding a parameter doesn't involve renumbering your
20+
* indices. Code such as this:
21+
*
22+
*
23+
* Connection con=getConnection(); String query="select * from my_table where
24+
* name=? or address=?"; PreparedStatement p=con.prepareStatement(query);
25+
* p.setString(1, "bob"); p.setString(2, "123 terrace ct"); ResultSet
26+
* rs=p.executeQuery();
27+
*
28+
*
29+
* can be replaced with:
30+
*
31+
*
32+
* Connection con=getConnection(); String query="select * from my_table where
33+
* name=:name or address=:address"; NamedParameterStatement p=new
34+
* NamedParameterStatement(con, query); p.setString("name", "bob");
35+
* p.setString("address", "123 terrace ct"); ResultSet rs=p.executeQuery();
36+
*
37+
*/
38+
public class NamedParameterStatement implements AutoCloseable {
39+
40+
/** The statement this object is wrapping. */
41+
private final PreparedStatement statement;
42+
43+
/**
44+
* Maps parameter names to arrays of ints which are the parameter indices.
45+
*/
46+
private final Map<String, List<Integer>> indexMap;
47+
48+
/**
49+
* Creates a NamedParameterStatement. Wraps a call to
50+
* <code>c.{@link Connection#prepareStatement(java.lang.String) prepareStatement}</code>.
51+
*
52+
* @param connection the database connection
53+
* @param query the parameterized query
54+
* @param parameters the map of parameter values
55+
*
56+
* @throws SQLException if the statement could not be created
57+
*/
58+
public NamedParameterStatement(Connection connection, String query, Map<String, Object> parameters)
59+
throws SQLException {
60+
this(connection, query, parameters, null);
61+
}
62+
63+
/**
64+
* Creates a NamedParameterStatement. Wraps a call to
65+
* <code>c.{@link Connection#prepareStatement(java.lang.String) prepareStatement}</code>.
66+
*
67+
* @param connection the database connection
68+
* @param query the parameterized query
69+
* @param parameters the map of parameter values
70+
* @param maxRows maximum number of records to return
71+
*
72+
* @throws SQLException if the statement could not be created
73+
*/
74+
public NamedParameterStatement(Connection connection, String query, Map<String, Object> parameters, Integer maxRows)
75+
throws SQLException {
76+
indexMap = new HashMap<>();
77+
78+
// remove those parameters not really referenced in the query
79+
Map<String, Object> usedParameters=new HashMap<>();
80+
if (parameters != null)
81+
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
82+
if(query.contains(":"+entry.getKey()))
83+
usedParameters.put(entry.getKey(), entry.getValue());
84+
}
85+
86+
String parsedQuery = parse(query, indexMap);
87+
statement = connection.prepareStatement(parsedQuery);
88+
if (!usedParameters.isEmpty()) {
89+
setParameters(usedParameters);
90+
}
91+
if (maxRows != null)
92+
statement.setMaxRows(maxRows);
93+
}
94+
95+
/**
96+
* Parses a query with named parameters. The parameter-index mappings are
97+
* put into the map, and the parsed query is returned. <b>DO NOT CALL FROM
98+
* CLIENT CODE.</b> This method is non-private so JUnit code can test it.
99+
*
100+
* @param query query to parse
101+
* @param paramMap map to hold parameter-index mappings
102+
* @return the parsed query
103+
*/
104+
static final String parse(String query, Map<String, List<Integer>> paramMap) {
105+
// I was originally using regular expressions, but they didn't work well
106+
// for ignoring parameter-like strings inside quotes.
107+
int length = query.length();
108+
StringBuffer parsedQuery = new StringBuffer(length);
109+
boolean inSingleQuote = false;
110+
boolean inDoubleQuote = false;
111+
int index = 1;
112+
113+
for (int i = 0; i < length; i++) {
114+
char c = query.charAt(i);
115+
if (inSingleQuote) {
116+
if (c == '\'') {
117+
inSingleQuote = false;
118+
}
119+
} else if (inDoubleQuote) {
120+
if (c == '"') {
121+
inDoubleQuote = false;
122+
}
123+
} else {
124+
if (c == '\'') {
125+
inSingleQuote = true;
126+
} else if (c == '"') {
127+
inDoubleQuote = true;
128+
} else if (c == ':' && i + 1 < length && Character.isJavaIdentifierStart(query.charAt(i + 1))) {
129+
int j = i + 2;
130+
while (j < length && Character.isJavaIdentifierPart(query.charAt(j))) {
131+
j++;
132+
}
133+
String name = query.substring(i + 1, j);
134+
c = '?'; // replace the parameter with a question mark
135+
i += name.length(); // skip past the end if the parameter
136+
137+
List<Integer> indexList = paramMap.get(name);
138+
if (indexList == null) {
139+
indexList = new LinkedList<>();
140+
paramMap.put(name, indexList);
141+
}
142+
indexList.add(Integer.valueOf(index));
143+
144+
index++;
145+
}
146+
}
147+
parsedQuery.append(c);
148+
}
149+
150+
return parsedQuery.toString();
151+
}
152+
153+
/**
154+
* Returns the indexes for a parameter.
155+
*
156+
* @param name parameter name
157+
* @return parameter indexes
158+
* @throws IllegalArgumentException if the parameter does not exist
159+
*/
160+
private Integer[] getIndexes(String name) {
161+
Integer[] indexes = indexMap.get(name).toArray(new Integer[0]);
162+
if (indexes == null)
163+
throw new IllegalArgumentException("Parameter not found: " + name);
164+
return indexes;
165+
}
166+
167+
public void setParameters(Map<String, Object> parameters) throws SQLException {
168+
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
169+
if (entry.getValue() instanceof String str)
170+
setString(entry.getKey(), str);
171+
else if (entry.getValue() instanceof Integer intg)
172+
setInt(entry.getKey(), intg);
173+
else if (entry.getValue() instanceof Long lng)
174+
setLong(entry.getKey(), lng);
175+
else if (entry.getValue() instanceof Timestamp timestamp)
176+
setTimestamp(entry.getKey(), timestamp);
177+
else if (entry.getValue() instanceof Date date)
178+
setTimestamp(entry.getKey(), new Timestamp(date.getTime()));
179+
else
180+
setObject(entry.getKey(), entry.getValue());
181+
}
182+
}
183+
184+
/**
185+
* Sets a parameter.
186+
*
187+
* @param name parameter name
188+
* @param value parameter value
189+
* @throws SQLException if an error occurred
190+
* @throws IllegalArgumentException if the parameter does not exist
191+
* @see PreparedStatement#setObject(int, java.lang.Object)
192+
*/
193+
public void setObject(String name, Object value) throws SQLException {
194+
Integer[] indexes = getIndexes(name);
195+
for (int i = 0; i < indexes.length; i++) {
196+
statement.setObject(indexes[i], value);
197+
}
198+
}
199+
200+
/**
201+
* Sets a parameter.
202+
*
203+
* @param name parameter name
204+
* @param value parameter value
205+
* @throws SQLException if an error occurred
206+
* @throws IllegalArgumentException if the parameter does not exist
207+
* @see PreparedStatement#setString(int, java.lang.String)
208+
*/
209+
public void setString(String name, String value) throws SQLException {
210+
Integer[] indexes = getIndexes(name);
211+
for (int i = 0; i < indexes.length; i++) {
212+
statement.setString(indexes[i], value);
213+
}
214+
}
215+
216+
/**
217+
* Sets a parameter.
218+
*
219+
* @param name parameter name
220+
* @param value parameter value
221+
* @throws SQLException if an error occurred
222+
* @throws IllegalArgumentException if the parameter does not exist
223+
* @see PreparedStatement#setInt(int, int)
224+
*/
225+
public void setInt(String name, int value) throws SQLException {
226+
Integer[] indexes = getIndexes(name);
227+
for (int i = 0; i < indexes.length; i++) {
228+
statement.setInt(indexes[i], value);
229+
}
230+
}
231+
232+
/**
233+
* Sets a parameter.
234+
*
235+
* @param name parameter name
236+
* @param value parameter value
237+
* @throws SQLException if an error occurred
238+
* @throws IllegalArgumentException if the parameter does not exist
239+
* @see PreparedStatement#setInt(int, int)
240+
*/
241+
public void setLong(String name, long value) throws SQLException {
242+
Integer[] indexes = getIndexes(name);
243+
for (int i = 0; i < indexes.length; i++) {
244+
statement.setLong(indexes[i], value);
245+
}
246+
}
247+
248+
/**
249+
* Sets a parameter.
250+
*
251+
* @param name parameter name
252+
* @param value parameter value
253+
* @throws SQLException if an error occurred
254+
* @throws IllegalArgumentException if the parameter does not exist
255+
* @see PreparedStatement#setTimestamp(int, java.sql.Timestamp)
256+
*/
257+
public void setTimestamp(String name, Timestamp value) throws SQLException {
258+
Integer[] indexes = getIndexes(name);
259+
for (int i = 0; i < indexes.length; i++) {
260+
statement.setTimestamp(indexes[i], value);
261+
}
262+
}
263+
264+
/**
265+
* Returns the underlying statement.
266+
*
267+
* @return the statement
268+
*/
269+
public PreparedStatement getStatement() {
270+
return statement;
271+
}
272+
273+
/**
274+
* Executes the statement.
275+
*
276+
* @return true if the first result is a {@link ResultSet}
277+
* @throws SQLException if an error occurred
278+
* @see PreparedStatement#execute()
279+
*/
280+
public boolean execute() throws SQLException {
281+
return statement.execute();
282+
}
283+
284+
/**
285+
* Executes the statement, which must be a query.
286+
*
287+
* @return the query results
288+
* @throws SQLException if an error occurred
289+
* @see PreparedStatement#executeQuery()
290+
*/
291+
public ResultSet executeQuery() throws SQLException {
292+
return statement.executeQuery();
293+
}
294+
295+
/**
296+
* Executes the statement, which must be an SQL INSERT, UPDATE or DELETE
297+
* statement; or an SQL statement that returns nothing, such as a DDL
298+
* statement.
299+
*
300+
* @return number of rows affected
301+
* @throws SQLException if an error occurred
302+
* @see PreparedStatement#executeUpdate()
303+
*/
304+
public int executeUpdate() throws SQLException {
305+
return statement.executeUpdate();
306+
}
307+
308+
/**
309+
* Closes the statement.
310+
*
311+
* @throws SQLException if an error occurred
312+
* @see Statement#close()
313+
*/
314+
@Override
315+
public void close() throws SQLException {
316+
statement.close();
317+
}
318+
319+
/**
320+
* Adds the current set of parameters as a batch entry.
321+
*
322+
* @throws SQLException if something went wrong
323+
*/
324+
public void addBatch() throws SQLException {
325+
statement.addBatch();
326+
}
327+
328+
/**
329+
* Executes all of the batched statements.
330+
*
331+
* See {@link Statement#executeBatch()} for details.
332+
*
333+
* @return update counts for each statement
334+
* @throws SQLException if something went wrong
335+
*/
336+
public int[] executeBatch() throws SQLException {
337+
return statement.executeBatch();
338+
}
339+
}

0 commit comments

Comments
 (0)