1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.message; |
7 | |
8 | import java.math.BigDecimal; |
9 | import java.sql.SQLException; |
10 | import java.util.Map; |
11 | import org.h2.util.StringUtils; |
12 | |
13 | /** |
14 | * The base class for objects that can print trace information about themselves. |
15 | */ |
16 | public class TraceObject { |
17 | |
18 | /** |
19 | * The trace type id for callable statements. |
20 | */ |
21 | protected static final int CALLABLE_STATEMENT = 0; |
22 | |
23 | /** |
24 | * The trace type id for connections. |
25 | */ |
26 | protected static final int CONNECTION = 1; |
27 | |
28 | /** |
29 | * The trace type id for database meta data objects. |
30 | */ |
31 | protected static final int DATABASE_META_DATA = 2; |
32 | |
33 | /** |
34 | * The trace type id for prepared statements. |
35 | */ |
36 | protected static final int PREPARED_STATEMENT = 3; |
37 | |
38 | /** |
39 | * The trace type id for result sets. |
40 | */ |
41 | protected static final int RESULT_SET = 4; |
42 | |
43 | /** |
44 | * The trace type id for result set meta data objects. |
45 | */ |
46 | protected static final int RESULT_SET_META_DATA = 5; |
47 | |
48 | /** |
49 | * The trace type id for savepoint objects. |
50 | */ |
51 | protected static final int SAVEPOINT = 6; |
52 | |
53 | /** |
54 | * The trace type id for statements. |
55 | */ |
56 | protected static final int STATEMENT = 8; |
57 | |
58 | /** |
59 | * The trace type id for blobs. |
60 | */ |
61 | protected static final int BLOB = 9; |
62 | |
63 | /** |
64 | * The trace type id for clobs. |
65 | */ |
66 | protected static final int CLOB = 10; |
67 | |
68 | /** |
69 | * The trace type id for parameter meta data objects. |
70 | */ |
71 | protected static final int PARAMETER_META_DATA = 11; |
72 | |
73 | /** |
74 | * The trace type id for data sources. |
75 | */ |
76 | protected static final int DATA_SOURCE = 12; |
77 | |
78 | /** |
79 | * The trace type id for XA data sources. |
80 | */ |
81 | protected static final int XA_DATA_SOURCE = 13; |
82 | |
83 | /** |
84 | * The trace type id for transaction ids. |
85 | */ |
86 | protected static final int XID = 15; |
87 | |
88 | /** |
89 | * The trace type id for array objects. |
90 | */ |
91 | protected static final int ARRAY = 16; |
92 | |
93 | private static final int LAST = ARRAY + 1; |
94 | private static final int[] ID = new int[LAST]; |
95 | private static final String[] PREFIX = { "call", "conn", "dbMeta", "prep", |
96 | "rs", "rsMeta", "sp", "ex", "stat", "blob", "clob", "pMeta", "ds", |
97 | "xads", "xares", "xid", "ar" }; |
98 | |
99 | /** |
100 | * The trace module used by this object. |
101 | */ |
102 | protected Trace trace; |
103 | |
104 | private int traceType; |
105 | private int id; |
106 | |
107 | /** |
108 | * Set the options to use when writing trace message. |
109 | * |
110 | * @param trace the trace object |
111 | * @param type the trace object type |
112 | * @param id the trace object id |
113 | */ |
114 | protected void setTrace(Trace trace, int type, int id) { |
115 | this.trace = trace; |
116 | this.traceType = type; |
117 | this.id = id; |
118 | } |
119 | |
120 | /** |
121 | * INTERNAL |
122 | */ |
123 | public int getTraceId() { |
124 | return id; |
125 | } |
126 | |
127 | /** |
128 | * INTERNAL |
129 | */ |
130 | public String getTraceObjectName() { |
131 | return PREFIX[traceType] + id; |
132 | } |
133 | |
134 | /** |
135 | * Get the next trace object id for this object type. |
136 | * |
137 | * @param type the object type |
138 | * @return the new trace object id |
139 | */ |
140 | protected static int getNextId(int type) { |
141 | return ID[type]++; |
142 | } |
143 | |
144 | /** |
145 | * Check if the debug trace level is enabled. |
146 | * |
147 | * @return true if it is |
148 | */ |
149 | protected boolean isDebugEnabled() { |
150 | return trace.isDebugEnabled(); |
151 | } |
152 | |
153 | /** |
154 | * Check if info trace level is enabled. |
155 | * |
156 | * @return true if it is |
157 | */ |
158 | protected boolean isInfoEnabled() { |
159 | return trace.isInfoEnabled(); |
160 | } |
161 | |
162 | /** |
163 | * Write trace information as an assignment in the form |
164 | * className prefixId = objectName.value. |
165 | * |
166 | * @param className the class name of the result |
167 | * @param newType the prefix type |
168 | * @param newId the trace object id of the created object |
169 | * @param value the value to assign this new object to |
170 | */ |
171 | protected void debugCodeAssign(String className, int newType, int newId, |
172 | String value) { |
173 | if (trace.isDebugEnabled()) { |
174 | trace.debugCode(className + " " + PREFIX[newType] + |
175 | newId + " = " + getTraceObjectName() + "." + value + ";"); |
176 | } |
177 | } |
178 | |
179 | /** |
180 | * Write trace information as a method call in the form |
181 | * objectName.methodName(). |
182 | * |
183 | * @param methodName the method name |
184 | */ |
185 | protected void debugCodeCall(String methodName) { |
186 | if (trace.isDebugEnabled()) { |
187 | trace.debugCode(getTraceObjectName() + "." + methodName + "();"); |
188 | } |
189 | } |
190 | |
191 | /** |
192 | * Write trace information as a method call in the form |
193 | * objectName.methodName(param) where the parameter is formatted as a long |
194 | * value. |
195 | * |
196 | * @param methodName the method name |
197 | * @param param one single long parameter |
198 | */ |
199 | protected void debugCodeCall(String methodName, long param) { |
200 | if (trace.isDebugEnabled()) { |
201 | trace.debugCode(getTraceObjectName() + "." + |
202 | methodName + "(" + param + ");"); |
203 | } |
204 | } |
205 | |
206 | /** |
207 | * Write trace information as a method call in the form |
208 | * objectName.methodName(param) where the parameter is formatted as a Java |
209 | * string. |
210 | * |
211 | * @param methodName the method name |
212 | * @param param one single string parameter |
213 | */ |
214 | protected void debugCodeCall(String methodName, String param) { |
215 | if (trace.isDebugEnabled()) { |
216 | trace.debugCode(getTraceObjectName() + "." + |
217 | methodName + "(" + quote(param) + ");"); |
218 | } |
219 | } |
220 | |
221 | /** |
222 | * Write trace information in the form objectName.text. |
223 | * |
224 | * @param text the trace text |
225 | */ |
226 | protected void debugCode(String text) { |
227 | if (trace.isDebugEnabled()) { |
228 | trace.debugCode(getTraceObjectName() + "." + text); |
229 | } |
230 | } |
231 | |
232 | /** |
233 | * Format a string as a Java string literal. |
234 | * |
235 | * @param s the string to convert |
236 | * @return the Java string literal |
237 | */ |
238 | protected static String quote(String s) { |
239 | return StringUtils.quoteJavaString(s); |
240 | } |
241 | |
242 | /** |
243 | * Format a time to the Java source code that represents this object. |
244 | * |
245 | * @param x the time to convert |
246 | * @return the Java source code |
247 | */ |
248 | protected static String quoteTime(java.sql.Time x) { |
249 | if (x == null) { |
250 | return "null"; |
251 | } |
252 | return "Time.valueOf(\"" + x.toString() + "\")"; |
253 | } |
254 | |
255 | /** |
256 | * Format a timestamp to the Java source code that represents this object. |
257 | * |
258 | * @param x the timestamp to convert |
259 | * @return the Java source code |
260 | */ |
261 | protected static String quoteTimestamp(java.sql.Timestamp x) { |
262 | if (x == null) { |
263 | return "null"; |
264 | } |
265 | return "Timestamp.valueOf(\"" + x.toString() + "\")"; |
266 | } |
267 | |
268 | /** |
269 | * Format a date to the Java source code that represents this object. |
270 | * |
271 | * @param x the date to convert |
272 | * @return the Java source code |
273 | */ |
274 | protected static String quoteDate(java.sql.Date x) { |
275 | if (x == null) { |
276 | return "null"; |
277 | } |
278 | return "Date.valueOf(\"" + x.toString() + "\")"; |
279 | } |
280 | |
281 | /** |
282 | * Format a big decimal to the Java source code that represents this object. |
283 | * |
284 | * @param x the big decimal to convert |
285 | * @return the Java source code |
286 | */ |
287 | protected static String quoteBigDecimal(BigDecimal x) { |
288 | if (x == null) { |
289 | return "null"; |
290 | } |
291 | return "new BigDecimal(\"" + x.toString() + "\")"; |
292 | } |
293 | |
294 | /** |
295 | * Format a byte array to the Java source code that represents this object. |
296 | * |
297 | * @param x the byte array to convert |
298 | * @return the Java source code |
299 | */ |
300 | protected static String quoteBytes(byte[] x) { |
301 | if (x == null) { |
302 | return "null"; |
303 | } |
304 | return "org.h2.util.StringUtils.convertHexToBytes(\"" + |
305 | StringUtils.convertBytesToHex(x) + "\")"; |
306 | } |
307 | |
308 | /** |
309 | * Format a string array to the Java source code that represents this |
310 | * object. |
311 | * |
312 | * @param s the string array to convert |
313 | * @return the Java source code |
314 | */ |
315 | protected static String quoteArray(String[] s) { |
316 | return StringUtils.quoteJavaStringArray(s); |
317 | } |
318 | |
319 | /** |
320 | * Format an int array to the Java source code that represents this object. |
321 | * |
322 | * @param s the int array to convert |
323 | * @return the Java source code |
324 | */ |
325 | protected static String quoteIntArray(int[] s) { |
326 | return StringUtils.quoteJavaIntArray(s); |
327 | } |
328 | |
329 | /** |
330 | * Format a map to the Java source code that represents this object. |
331 | * |
332 | * @param map the map to convert |
333 | * @return the Java source code |
334 | */ |
335 | protected static String quoteMap(Map<String, Class<?>> map) { |
336 | if (map == null) { |
337 | return "null"; |
338 | } |
339 | if (map.size() == 0) { |
340 | return "new Map()"; |
341 | } |
342 | return "new Map() /* " + map.toString() + " */"; |
343 | } |
344 | |
345 | /** |
346 | * Log an exception and convert it to a SQL exception if required. |
347 | * |
348 | * @param ex the exception |
349 | * @return the SQL exception object |
350 | */ |
351 | protected SQLException logAndConvert(Exception ex) { |
352 | SQLException e = DbException.toSQLException(ex); |
353 | if (trace == null) { |
354 | DbException.traceThrowable(e); |
355 | } else { |
356 | int errorCode = e.getErrorCode(); |
357 | if (errorCode >= 23000 && errorCode < 24000) { |
358 | trace.info(e, "exception"); |
359 | } else { |
360 | trace.error(e, "exception"); |
361 | } |
362 | } |
363 | return e; |
364 | } |
365 | |
366 | /** |
367 | * Get and throw a SQL exception meaning this feature is not supported. |
368 | * |
369 | * @param message the message |
370 | * @return never returns normally |
371 | * @throws SQLException the exception |
372 | */ |
373 | protected SQLException unsupported(String message) throws SQLException { |
374 | try { |
375 | throw DbException.getUnsupportedException(message); |
376 | } catch (Exception e) { |
377 | return logAndConvert(e); |
378 | } |
379 | } |
380 | |
381 | } |