001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.audit;
017
018import com.mybatisflex.core.mybatis.TypeHandlerObject;
019import com.mybatisflex.core.util.ClassUtil;
020import com.mybatisflex.core.util.SqlUtil;
021
022import java.io.Serializable;
023import java.lang.reflect.Array;
024import java.lang.reflect.Proxy;
025import java.sql.PreparedStatement;
026import java.sql.SQLException;
027import java.sql.Statement;
028import java.util.ArrayList;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033/**
034 * SQL 审计详细消息。
035 */
036public class AuditMessage implements Serializable {
037
038    /**
039     * 平台,或者是运行的应用。
040     */
041    private String platform;
042
043    /**
044     * 应用模块。
045     */
046    private String module;
047
048    /**
049     * 执行这个 SQL 涉及的 URL 地址。
050     */
051    private String url;
052
053    /**
054     * 自定义业务 ID。
055     */
056    private String bizId;
057
058    /**
059     * 执行这个 SQL 涉及的平台用户。
060     */
061    private String user;
062
063    /**
064     * 执行这个 SQL 的平台用户 IP 地址。
065     */
066    private String userIp;
067
068    /**
069     * 执行这个 SQL 的服务器 IP 地址。
070     */
071    private String hostIp;
072
073    /**
074     * SQL 内容。
075     */
076    private String query;
077
078    /**
079     * SQL 参数。
080     */
081    private List<Object> queryParams;
082
083    /**
084     * SQL 查询出来数据的数量。
085     */
086    private int queryCount;
087
088    /**
089     * SQL 执行的时间点(当前时间,毫秒)。
090     */
091    private long queryTime;
092
093    /**
094     * SQL 执行的消耗时间(毫秒)。
095     */
096    private long elapsedTime;
097
098    /**
099     * 其他扩展元信息。
100     */
101    private Map<String, Object> metas;
102
103    public String getPlatform() {
104        return platform;
105    }
106
107    public void setPlatform(String platform) {
108        this.platform = platform;
109    }
110
111    public String getModule() {
112        return module;
113    }
114
115    public void setModule(String module) {
116        this.module = module;
117    }
118
119    public String getUrl() {
120        return url;
121    }
122
123    public void setUrl(String url) {
124        this.url = url;
125    }
126
127    public String getBizId() {
128        return bizId;
129    }
130
131    public void setBizId(String bizId) {
132        this.bizId = bizId;
133    }
134
135    public String getUser() {
136        return user;
137    }
138
139    public void setUser(String user) {
140        this.user = user;
141    }
142
143    public String getUserIp() {
144        return userIp;
145    }
146
147    public void setUserIp(String userIp) {
148        this.userIp = userIp;
149    }
150
151    public String getHostIp() {
152        return hostIp;
153    }
154
155    public void setHostIp(String hostIp) {
156        this.hostIp = hostIp;
157    }
158
159    public String getQuery() {
160        return query;
161    }
162
163    public void setQuery(String query) {
164        this.query = query;
165    }
166
167    public List<Object> getQueryParams() {
168        return queryParams;
169    }
170
171    public void setQueryParams(List<Object> queryParams) {
172        this.queryParams = queryParams;
173    }
174
175    public void addParams(Statement statement, Object... objects) {
176        if (queryParams == null) {
177            queryParams = new ArrayList<>();
178        }
179
180        for (Object object : objects) {
181            if (object != null && ClassUtil.isArray(object.getClass())) {
182                for (int i = 0; i < Array.getLength(object); i++) {
183                    doAddParam(statement, Array.get(object, i));
184                }
185            } else {
186                doAddParam(statement, object);
187            }
188        }
189    }
190
191    private void doAddParam(Statement statement, Object object) {
192        try {
193            if (object instanceof TypeHandlerObject) {
194                ((TypeHandlerObject) object).setParameter(createPreparedStatement(statement), 0);
195            } else if (object instanceof java.sql.Array) {
196                Object array = ((java.sql.Array) object).getArray();
197                queryParams.add(array);
198            } else {
199                queryParams.add(object);
200            }
201        } catch (SQLException e) {
202            //ignore
203        }
204    }
205
206    public String getFullSql() {
207        List<Object> queryParams = getQueryParams();
208        return SqlUtil.replaceSqlParams(getQuery(), queryParams == null ? null : queryParams.toArray());
209    }
210
211    private PreparedStatement createPreparedStatement(Statement statement) {
212        return (PreparedStatement) Proxy.newProxyInstance(
213            AuditMessage.class.getClassLoader(),
214            new Class[]{PreparedStatement.class}, (proxy, method, args) -> {
215                if (args != null && (args.length == 2 || args.length == 3)) {
216                    doAddParam(statement, args[1]);
217                } else if ("getConnection".equals(method.getName())) {
218                    return statement.getConnection();
219                }
220                return null;
221            });
222    }
223
224    public int getQueryCount() {
225        return queryCount;
226    }
227
228    public void setQueryCount(int queryCount) {
229        this.queryCount = queryCount;
230    }
231
232    public long getQueryTime() {
233        return queryTime;
234    }
235
236    public void setQueryTime(long queryTime) {
237        this.queryTime = queryTime;
238    }
239
240    public long getElapsedTime() {
241        return elapsedTime;
242    }
243
244    public void setElapsedTime(long elapsedTime) {
245        this.elapsedTime = elapsedTime;
246    }
247
248    public Map<String, Object> getMetas() {
249        return metas;
250    }
251
252    public void setMetas(Map<String, Object> metas) {
253        this.metas = metas;
254    }
255
256    public void addMeta(String key, Object value) {
257        if (metas == null) {
258            metas = new HashMap<>();
259        }
260        metas.put(key, value);
261    }
262
263    @Override
264    public String toString() {
265        return "AuditMessage{" +
266            "platform='" + platform + '\'' +
267            ", module='" + module + '\'' +
268            ", url='" + url + '\'' +
269            ", bizId='" + bizId + '\'' +
270            ", user='" + user + '\'' +
271            ", userIp='" + userIp + '\'' +
272            ", hostIp='" + hostIp + '\'' +
273            ", query='" + query + '\'' +
274            ", queryParams=" + queryParams +
275            ", queryCount=" + queryCount +
276            ", queryTime=" + queryTime +
277            ", elapsedTime=" + elapsedTime +
278            ", metas=" + metas +
279            '}';
280    }
281
282}