View Javadoc
1   /*
2    *    Copyright 2009-2021 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.logging.jdbc;
17  
18  import java.lang.reflect.Method;
19  import java.sql.Array;
20  import java.sql.PreparedStatement;
21  import java.sql.SQLException;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.stream.Collectors;
30  
31  import org.apache.ibatis.builder.SqlSourceBuilder;
32  import org.apache.ibatis.logging.Log;
33  import org.apache.ibatis.reflection.ArrayUtil;
34  
35  /**
36   * Base class for proxies to do logging.
37   *
38   * @author Clinton Begin
39   * @author Eduardo Macarron
40   */
41  public abstract class BaseJdbcLogger {
42  
43    protected static final Set<String> SET_METHODS;
44    protected static final Set<String> EXECUTE_METHODS = new HashSet<>();
45  
46    private final Map<Object, Object> columnMap = new HashMap<>();
47  
48    private final List<Object> columnNames = new ArrayList<>();
49    private final List<Object> columnValues = new ArrayList<>();
50  
51    protected final Log statementLog;
52    protected final int queryStack;
53  
54    /*
55     * Default constructor
56     */
57    public BaseJdbcLogger(Log log, int queryStack) {
58      this.statementLog = log;
59      if (queryStack == 0) {
60        this.queryStack = 1;
61      } else {
62        this.queryStack = queryStack;
63      }
64    }
65  
66    static {
67      SET_METHODS = Arrays.stream(PreparedStatement.class.getDeclaredMethods())
68              .filter(method -> method.getName().startsWith("set"))
69              .filter(method -> method.getParameterCount() > 1)
70              .map(Method::getName)
71              .collect(Collectors.toSet());
72  
73      EXECUTE_METHODS.add("execute");
74      EXECUTE_METHODS.add("executeUpdate");
75      EXECUTE_METHODS.add("executeQuery");
76      EXECUTE_METHODS.add("addBatch");
77    }
78  
79    protected void setColumn(Object key, Object value) {
80      columnMap.put(key, value);
81      columnNames.add(key);
82      columnValues.add(value);
83    }
84  
85    protected Object getColumn(Object key) {
86      return columnMap.get(key);
87    }
88  
89    protected String getParameterValueString() {
90      List<Object> typeList = new ArrayList<>(columnValues.size());
91      for (Object value : columnValues) {
92        if (value == null) {
93          typeList.add("null");
94        } else {
95          typeList.add(objectValueString(value) + "(" + value.getClass().getSimpleName() + ")");
96        }
97      }
98      final String parameters = typeList.toString();
99      return parameters.substring(1, parameters.length() - 1);
100   }
101 
102   protected String objectValueString(Object value) {
103     if (value instanceof Array) {
104       try {
105         return ArrayUtil.toString(((Array) value).getArray());
106       } catch (SQLException e) {
107         return value.toString();
108       }
109     }
110     return value.toString();
111   }
112 
113   protected String getColumnString() {
114     return columnNames.toString();
115   }
116 
117   protected void clearColumnInfo() {
118     columnMap.clear();
119     columnNames.clear();
120     columnValues.clear();
121   }
122 
123   protected String removeExtraWhitespace(String original) {
124     return SqlSourceBuilder.removeExtraWhitespaces(original);
125   }
126 
127   protected boolean isDebugEnabled() {
128     return statementLog.isDebugEnabled();
129   }
130 
131   protected boolean isTraceEnabled() {
132     return statementLog.isTraceEnabled();
133   }
134 
135   protected void debug(String text, boolean input) {
136     if (statementLog.isDebugEnabled()) {
137       statementLog.debug(prefix(input) + text);
138     }
139   }
140 
141   protected void trace(String text, boolean input) {
142     if (statementLog.isTraceEnabled()) {
143       statementLog.trace(prefix(input) + text);
144     }
145   }
146 
147   private String prefix(boolean isInput) {
148     char[] buffer = new char[queryStack * 2 + 2];
149     Arrays.fill(buffer, '=');
150     buffer[queryStack * 2 + 1] = ' ';
151     if (isInput) {
152       buffer[queryStack * 2] = '>';
153     } else {
154       buffer[0] = '<';
155     }
156     return new String(buffer);
157   }
158 
159 }