1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.james.ai.classic;
21
22 import java.io.File;
23 import java.io.InputStream;
24 import java.sql.Connection;
25 import java.sql.SQLException;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.regex.Pattern;
29
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32
33 import org.w3c.dom.Attr;
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Element;
36 import org.w3c.dom.NamedNodeMap;
37 import org.w3c.dom.NodeList;
38
39
40
41
42
43
44
45
46
47 class SqlResources {
48
49 private Map<String, String> m_sql = new HashMap<String, String>();
50
51
52 private Map<String, String> m_dbOptions = new HashMap<String, String>();
53
54
55 static private Map<String, String> stringTable = java.util.Collections.synchronizedMap(new HashMap<String, String>());
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public void init(File sqlFile, String sqlDefsSection, Connection conn, Map<String, String> configParameters) throws Exception {
82
83 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
84 DocumentBuilder builder = factory.newDocumentBuilder();
85 Document sqlDoc = builder.parse(sqlFile);
86
87 init(sqlDoc, sqlDefsSection, conn, configParameters);
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 public void init(InputStream input, String sqlDefsSection, Connection conn, Map<String, String> configParameters) throws Exception {
116
117 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
118 DocumentBuilder builder = factory.newDocumentBuilder();
119 Document sqlDoc = builder.parse(input);
120
121 init(sqlDoc, sqlDefsSection, conn, configParameters);
122 }
123
124
125
126
127
128
129
130
131
132
133 protected void init(Document sqlDoc, String sqlDefsSection, Connection conn, Map<String, String> configParameters) throws SQLException {
134
135
136 Element dbMatcherElement = (Element) (sqlDoc.getElementsByTagName("dbMatchers").item(0));
137 String dbProduct = null;
138 if (dbMatcherElement != null) {
139 dbProduct = matchDbConnection(conn, dbMatcherElement);
140 }
141
142
143 Element dbOptionsElement = (Element) (sqlDoc.getElementsByTagName("dbOptions").item(0));
144 if (dbOptionsElement != null) {
145
146 populateDbOptions("", dbOptionsElement, m_dbOptions);
147
148 if (dbProduct != null) {
149 populateDbOptions(dbProduct, dbOptionsElement, m_dbOptions);
150 }
151 }
152
153
154 NodeList sections = sqlDoc.getElementsByTagName("sqlDefs");
155 int sectionsCount = sections.getLength();
156 Element sectionElement = null;
157 boolean found = false;
158 for (int i = 0; i < sectionsCount; i++) {
159 sectionElement = (Element) (sections.item(i));
160 String sectionName = sectionElement.getAttribute("name");
161 if (sectionName != null && sectionName.equals(sqlDefsSection)) {
162 found = true;
163 break;
164 }
165
166 }
167 if (!found) {
168 StringBuilder exceptionBuffer = new StringBuilder(64).append("Error loading sql definition file. ").append("The element named \'").append(sqlDefsSection).append("\' does not exist.");
169 throw new RuntimeException(exceptionBuffer.toString());
170 }
171
172
173
174 Map<String, String> parameters = new HashMap<String, String>();
175
176 Element parametersElement = (Element) (sectionElement.getElementsByTagName("parameters").item(0));
177 if (parametersElement != null) {
178 NamedNodeMap params = parametersElement.getAttributes();
179 int paramCount = params.getLength();
180 for (int i = 0; i < paramCount; i++) {
181 Attr param = (Attr) params.item(i);
182 String paramName = param.getName();
183 String paramValue = param.getValue();
184 parameters.put(paramName, paramValue);
185 }
186 }
187
188 parameters.putAll(configParameters);
189
190
191
192
193 Map<String, String> defaultSqlStatements = new HashMap<String, String>();
194 Map<String, String> dbProductSqlStatements = new HashMap<String, String>();
195
196
197
198 NodeList sqlDefs = sectionElement.getElementsByTagName("sql");
199 int sqlCount = sqlDefs.getLength();
200 for (int i = 0; i < sqlCount; i++) {
201
202
203 Element sqlElement = (Element) (sqlDefs.item(i));
204 String sqlDb = sqlElement.getAttribute("db");
205 Map<String, String> sqlMap;
206 if (sqlDb.equals("")) {
207
208 sqlMap = defaultSqlStatements;
209 } else if (sqlDb.equals(dbProduct)) {
210
211 sqlMap = dbProductSqlStatements;
212 } else {
213
214 continue;
215 }
216
217
218 String sqlKey = sqlElement.getAttribute("name");
219 if (sqlKey == null) {
220
221 continue;
222 }
223 String sqlString = sqlElement.getFirstChild().getNodeValue();
224
225
226 StringBuilder replaceBuffer = new StringBuilder(64);
227 for (Map.Entry<String, String> entry : parameters.entrySet()) {
228 replaceBuffer.setLength(0);
229 replaceBuffer.append("${").append(entry.getKey()).append("}");
230 sqlString = substituteSubString(sqlString, replaceBuffer.toString(), entry.getValue());
231 }
232
233
234 String shared = stringTable.get(sqlString);
235
236 if (shared == null) {
237 stringTable.put(sqlString, sqlString);
238 } else {
239 sqlString = shared;
240 }
241
242
243 sqlMap.put(sqlKey, sqlString);
244 }
245
246
247 m_sql.putAll(defaultSqlStatements);
248 m_sql.putAll(dbProductSqlStatements);
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266 private String matchDbConnection(Connection conn, Element dbMatchersElement) throws SQLException {
267 String dbProductName = conn.getMetaData().getDatabaseProductName();
268
269 NodeList dbMatchers = dbMatchersElement.getElementsByTagName("dbMatcher");
270 for (int i = 0; i < dbMatchers.getLength(); i++) {
271
272 Element dbMatcher = (Element) dbMatchers.item(i);
273 String dbMatchName = dbMatcher.getAttribute("db");
274 Pattern dbProductPattern = Pattern.compile(dbMatcher.getAttribute("databaseProductName"), Pattern.CASE_INSENSITIVE);
275
276
277
278 if (dbProductPattern.matcher(dbProductName).find()) {
279 return dbMatchName;
280 }
281 }
282 return null;
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297 private void populateDbOptions(String dbProduct, Element dbOptionsElement, Map<String, String> dbOptionsMap) {
298 NodeList dbOptions = dbOptionsElement.getElementsByTagName("dbOption");
299 for (int i = 0; i < dbOptions.getLength(); i++) {
300
301 Element dbOption = (Element) dbOptions.item(i);
302
303
304 if (!dbProduct.equalsIgnoreCase(dbOption.getAttribute("db"))) {
305 continue;
306 }
307
308 dbOptionsMap.put(dbOption.getAttribute("name"), dbOption.getAttribute("value"));
309 }
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324 private String substituteSubString(String input, String find, String replace) {
325 int find_length = find.length();
326 int replace_length = replace.length();
327
328 StringBuilder output = new StringBuilder(input);
329 int index = input.indexOf(find);
330 int outputOffset = 0;
331
332 while (index > -1) {
333 output.replace(index + outputOffset, index + outputOffset + find_length, replace);
334 outputOffset = outputOffset + (replace_length - find_length);
335
336 index = input.indexOf(find, index + find_length);
337 }
338
339 String result = output.toString();
340 return result;
341 }
342
343
344
345
346
347
348
349
350
351 public String getSqlString(String name) {
352 return (String) m_sql.get(name);
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 public String getSqlString(String name, boolean required) {
369 String sql = getSqlString(name);
370
371 if (sql == null && required) {
372 StringBuilder exceptionBuffer = new StringBuilder(64).append("Required SQL resource: '").append(name).append("' was not found.");
373 throw new RuntimeException(exceptionBuffer.toString());
374 }
375 return sql;
376 }
377
378
379
380
381
382
383
384
385 public String getDbOption(String name) {
386 return (String) m_dbOptions.get(name);
387 }
388
389 }