• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package ohos.devtools.views.distributed.util;
17 
18 import ohos.devtools.views.trace.DField;
19 import ohos.devtools.views.trace.Sql;
20 import ohos.devtools.views.trace.util.DataUtils;
21 import ohos.devtools.views.trace.util.Final;
22 import org.apache.commons.io.IOUtils;
23 
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.UnsupportedEncodingException;
27 import java.lang.reflect.Field;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.ParameterizedType;
30 import java.lang.reflect.Type;
31 import java.net.URL;
32 import java.net.URLClassLoader;
33 import java.nio.charset.Charset;
34 import java.sql.Blob;
35 import java.sql.Connection;
36 import java.sql.DriverManager;
37 import java.sql.ResultSet;
38 import java.sql.ResultSetMetaData;
39 import java.sql.SQLException;
40 import java.sql.Statement;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.Objects;
45 import java.util.Optional;
46 import java.util.concurrent.LinkedBlockingQueue;
47 
48 /**
49  * DistributedDBA
50  *
51  * @since 2021/08/10 16:53
52  */
53 public final class DistributedDB {
54     private static boolean isLocal;
55     private static volatile DistributedDB db = new DistributedDB();
56     private static String dbNameA = "";
57     private static String dbNameB = "";
58 
59     private LinkedBlockingQueue<Connection> poolA = new LinkedBlockingQueue();
60     private LinkedBlockingQueue<Connection> poolB = new LinkedBlockingQueue();
61 
DistributedDB()62     private DistributedDB() {
63     }
64 
65     /**
66      * Gets the value of dbName .
67      *
68      * @return the value of java.lang.String
69      */
getDbNameA()70     public static String getDbNameA() {
71         return dbNameA;
72     }
73 
74     /**
75      * Gets the value of dbName .
76      *
77      * @return the value of java.lang.String
78      */
getDbNameB()79     public static String getDbNameB() {
80         return dbNameB;
81     }
82 
83     /**
84      * Sets the dbName .You can use getDbName() to get the value of dbName
85      *
86      * @param dbNameA dbName
87      * @param dbNameB dbNameB
88      */
setDbName(final String dbNameA, final String dbNameB)89     public static void setDbName(final String dbNameA, final String dbNameB) {
90         DistributedDB.dbNameA = dbNameA;
91         DistributedDB.dbNameB = dbNameB;
92     }
93 
94     /**
95      * Load the database file according to the file location variable
96      *
97      * @param isLocal isLocal
98      */
load(final boolean isLocal)99     public static void load(final boolean isLocal) {
100         DistributedDB.isLocal = isLocal;
101         try {
102             Class.forName("org.sqlite.JDBC");
103             for (Connection connection : db.poolA) {
104                 connection.close();
105             }
106             for (Connection connection : db.poolB) {
107                 connection.close();
108             }
109             db.poolA.clear();
110             db.poolB.clear();
111             final int maxConnNum = 4;
112             for (int size = 0; size < maxConnNum; size++) {
113                 db.newConnA().ifPresent(connection -> {
114                     try {
115                         db.poolA.put(connection);
116                     } catch (InterruptedException interruptedException) {
117                         interruptedException.printStackTrace();
118                     }
119                 });
120                 db.newConnB().ifPresent(connection -> {
121                     try {
122                         db.poolB.put(connection);
123                     } catch (InterruptedException interruptedException) {
124                         interruptedException.printStackTrace();
125                     }
126                 });
127             }
128             db.newConnA().ifPresent(DistributedDB::excuteConnection);
129             db.newConnB().ifPresent(DistributedDB::excuteConnection);
130         } catch (SQLException | ClassNotFoundException throwables) {
131             throwables.printStackTrace();
132         }
133     }
134 
excuteConnection(Connection connection)135     private static void excuteConnection(Connection connection) {
136         try {
137             Statement statement = connection.createStatement();
138             String views = getSql("DistributedCpuViews");
139             String[] split = views.split(";");
140             for (String str : split) {
141                 statement.execute(str);
142             }
143             statement.close();
144             connection.close();
145         } catch (SQLException exception) {
146             exception.printStackTrace();
147         }
148     }
149 
150     /**
151      * Get the current current db object
152      *
153      * @return Db db
154      */
getInstance()155     public static DistributedDB getInstance() {
156         if (db == null) {
157             db = new DistributedDB();
158         }
159         return db;
160     }
161 
162     /**
163      * Read the sql directory under resource
164      *
165      * @param sqlName sqlName
166      * @return String sql
167      */
getSql(String sqlName)168     public static String getSql(String sqlName) {
169         String tmp = Final.IS_RESOURCE_SQL ? "-self/" : "/";
170         String path = "sql" + tmp + sqlName + ".sql";
171         try (InputStream STREAM = DataUtils.class.getClassLoader().getResourceAsStream(path)) {
172             return IOUtils.toString(STREAM, Charset.forName("UTF-8")).replaceAll("/\\*[\\s\\S]*?\\*/", "");
173         } catch (UnsupportedEncodingException exception) {
174             exception.printStackTrace();
175         } catch (IOException ioException) {
176             ioException.printStackTrace();
177         }
178         return "";
179     }
180 
181     /**
182      * Get database connection
183      *
184      * @return Connection
185      */
getConnA()186     public Connection getConnA() {
187         Connection connection = null;
188         try {
189             connection = poolA.take();
190         } catch (InterruptedException exception) {
191             exception.printStackTrace();
192         }
193         return connection;
194     }
195 
196     /**
197      * Get database connection
198      *
199      * @return Connection
200      */
getConnB()201     public Connection getConnB() {
202         Connection connection = null;
203         try {
204             connection = poolB.take();
205         } catch (InterruptedException exception) {
206             exception.printStackTrace();
207         }
208         return connection;
209     }
210 
211     /**
212      * Return the connection to the database connection pool after use
213      *
214      * @param conn conn
215      */
freeA(final Connection conn)216     public void freeA(final Connection conn) {
217         try {
218             poolA.put(conn);
219         } catch (InterruptedException exception) {
220             exception.printStackTrace();
221         }
222     }
223 
224     /**
225      * Return the connection to the database connection pool after use
226      *
227      * @param conn conn
228      */
freeB(final Connection conn)229     public void freeB(final Connection conn) {
230         try {
231             poolB.put(conn);
232         } catch (InterruptedException exception) {
233             exception.printStackTrace();
234         }
235     }
236 
newConnA()237     private Optional<Connection> newConnA() {
238         URL path = URLClassLoader.getSystemClassLoader().getResource(dbNameA);
239         Connection conn = null;
240         try {
241             if (isLocal) {
242                 conn = DriverManager.getConnection("jdbc:sqlite:" + dbNameA);
243             } else {
244                 conn = DriverManager.getConnection("jdbc:sqlite::resource:" + path);
245             }
246         } catch (SQLException exception) {
247             exception.printStackTrace();
248         }
249         return Optional.ofNullable(conn);
250     }
251 
newConnB()252     private Optional<Connection> newConnB() {
253         URL path = URLClassLoader.getSystemClassLoader().getResource(dbNameB);
254         Connection conn = null;
255         try {
256             if (isLocal) {
257                 conn = DriverManager.getConnection("jdbc:sqlite:" + dbNameB);
258             } else {
259                 conn = DriverManager.getConnection("jdbc:sqlite::resource:" + path);
260             }
261         } catch (SQLException exception) {
262             exception.printStackTrace();
263         }
264         return Optional.ofNullable(conn);
265     }
266 
267     /**
268      * Read the sql directory under resource
269      *
270      * @param em em
271      * @param res res
272      * @param args args
273      * @param <T> return type
274      */
queryA(Sql em, List<T> res, Object... args)275     public <T> void queryA(Sql em, List<T> res, Object... args) {
276         String sql = String.format(Locale.ENGLISH, getSql(em.getName()), args);
277         queryA(sql, res);
278     }
279 
280     /**
281      * Read the sql directory under resource
282      *
283      * @param em em
284      * @param res res
285      * @param args args
286      * @param <T> return type
287      */
queryB(Sql em, List<T> res, Object... args)288     public <T> void queryB(Sql em, List<T> res, Object... args) {
289         String sql = String.format(Locale.ENGLISH, getSql(em.getName()), args);
290         queryB(sql, res);
291     }
292 
293     /**
294      * query sql count
295      *
296      * @param em em
297      * @param args args
298      * @return int int
299      */
queryCountA(Sql em, Object... args)300     public int queryCountA(Sql em, Object... args) {
301         String sql = String.format(Locale.ENGLISH, getSql(em.getName()), args);
302         return queryCountA(sql);
303     }
304 
305     /**
306      * query sql count
307      *
308      * @param em em
309      * @param args args
310      * @return int int
311      */
queryCountB(Sql em, Object... args)312     public int queryCountB(Sql em, Object... args) {
313         String sql = String.format(Locale.ENGLISH, getSql(em.getName()), args);
314         return queryCountB(sql);
315     }
316 
317     /**
318      * query count from sql
319      *
320      * @param sql sql
321      * @return int int
322      */
queryCountA(String sql)323     public int queryCountA(String sql) {
324         Statement stat = null;
325         ResultSet rs = null;
326         int count = 0;
327         Connection conn = getConnA();
328         if (Objects.isNull(conn)) {
329             return 0;
330         }
331         try {
332             stat = conn.createStatement();
333             String tSql = sql.trim();
334             if (sql.trim().endsWith(";")) {
335                 tSql = sql.trim().substring(0, sql.trim().length() - 1);
336             }
337             rs = stat.executeQuery("select count(1) as count from (" + tSql + ");");
338             while (rs.next()) {
339                 count = rs.getInt("count");
340             }
341         } catch (SQLException exception) {
342             exception.printStackTrace();
343         } finally {
344             releaseA(rs, stat, conn);
345         }
346         return count;
347     }
348 
349     /**
350      * query count from sql
351      *
352      * @param sql sql
353      * @return int int
354      */
queryCountB(String sql)355     public int queryCountB(String sql) {
356         Statement stat = null;
357         ResultSet rs = null;
358         int count = 0;
359         Connection conn = getConnB();
360         if (Objects.isNull(conn)) {
361             return 0;
362         }
363         try {
364             stat = conn.createStatement();
365             String tSql = sql.trim();
366             if (sql.trim().endsWith(";")) {
367                 tSql = sql.trim().substring(0, sql.trim().length() - 1);
368             }
369             rs = stat.executeQuery("select count(1) as count from (" + tSql + ");");
370             while (rs.next()) {
371                 count = rs.getInt("count");
372             }
373         } catch (SQLException exception) {
374             exception.printStackTrace();
375         } finally {
376             releaseB(rs, stat, conn);
377         }
378         return count;
379     }
380 
381     /**
382      * Read the sql directory under resource
383      *
384      * @param res res
385      * @param sql sql
386      * @param <T> return type
387      */
queryA(String sql, List<T> res)388     public <T> void queryA(String sql, List<T> res) {
389         Statement stat = null;
390         ResultSet rs = null;
391         Connection conn = getConnA();
392         if (Objects.isNull(conn)) {
393             return;
394         }
395         Type argument = getType(res);
396         try {
397             Class<T> aClass = (Class<T>) Class.forName(argument.getTypeName());
398             stat = conn.createStatement();
399             rs = stat.executeQuery(sql);
400             ArrayList<String> columnList = new ArrayList<>();
401             ResultSetMetaData rsMeta = rs.getMetaData();
402             int columnCount = rsMeta.getColumnCount();
403             for (int index = 1; index <= columnCount; index++) {
404                 columnList.add(rsMeta.getColumnName(index));
405             }
406             while (rs.next()) {
407                 T data = aClass.getConstructor().newInstance();
408                 for (Field declaredField : aClass.getDeclaredFields()) {
409                     declaredField.setAccessible(true);
410                     DField annotation = declaredField.getAnnotation(DField.class);
411                     if (Objects.nonNull(annotation) && columnList.contains(annotation.name())) {
412                         setData(declaredField, data, rs, annotation);
413                     }
414                 }
415                 res.add(data);
416             }
417         } catch (ClassNotFoundException | SQLException | InstantiationException | IllegalAccessException
418             | InvocationTargetException | NoSuchMethodException exception) {
419             exception.printStackTrace();
420         } finally {
421             releaseA(rs, stat, conn);
422         }
423     }
424 
425     /**
426      * Read the sql directory under resource
427      *
428      * @param res res
429      * @param sql sql
430      * @param <T> return type
431      */
queryB(String sql, List<T> res)432     public <T> void queryB(String sql, List<T> res) {
433         Statement stat = null;
434         ResultSet rs = null;
435         Connection conn = getConnB();
436         if (Objects.isNull(conn)) {
437             return;
438         }
439         Type argument = getType(res);
440         try {
441             Class<T> aClass = (Class<T>) Class.forName(argument.getTypeName());
442             stat = conn.createStatement();
443             rs = stat.executeQuery(sql);
444             ArrayList<String> columnList = new ArrayList<>();
445             ResultSetMetaData rsMeta = rs.getMetaData();
446             int columnCount = rsMeta.getColumnCount();
447             for (int index = 1; index <= columnCount; index++) {
448                 columnList.add(rsMeta.getColumnName(index));
449             }
450             while (rs.next()) {
451                 T data = aClass.getConstructor().newInstance();
452                 for (Field declaredField : aClass.getDeclaredFields()) {
453                     declaredField.setAccessible(true);
454                     DField annotation = declaredField.getAnnotation(DField.class);
455                     if (Objects.nonNull(annotation) && columnList.contains(annotation.name())) {
456                         setData(declaredField, data, rs, annotation);
457                     }
458                 }
459                 res.add(data);
460             }
461         } catch (ClassNotFoundException | SQLException | InstantiationException | IllegalAccessException
462             | InvocationTargetException | NoSuchMethodException exception) {
463             exception.printStackTrace();
464         } finally {
465             releaseB(rs, stat, conn);
466         }
467     }
468 
setData(Field declaredField, T data, ResultSet rs, DField annotation)469     private <T> void setData(Field declaredField, T data, ResultSet rs, DField annotation)
470         throws SQLException, IllegalAccessException {
471         if (declaredField.getType() == Long.class || declaredField.getType() == long.class) {
472             declaredField.set(data, rs.getLong(annotation.name()));
473         } else if (declaredField.getType() == Integer.class || declaredField.getType() == int.class) {
474             declaredField.set(data, rs.getInt(annotation.name()));
475         } else if (declaredField.getType() == Double.class || declaredField.getType() == double.class) {
476             declaredField.set(data, rs.getDouble(annotation.name()));
477         } else if (declaredField.getType() == Float.class || declaredField.getType() == float.class) {
478             declaredField.set(data, rs.getFloat(annotation.name()));
479         } else if (declaredField.getType() == Boolean.class || declaredField.getType() == boolean.class) {
480             declaredField.set(data, rs.getBoolean(annotation.name()));
481         } else if (declaredField.getType() == Blob.class) {
482             declaredField.set(data, rs.getBlob(annotation.name()));
483         } else if (declaredField.getType() == String.class) {
484             declaredField.set(data, rs.getString(annotation.name()));
485         } else {
486             declaredField.set(data, rs.getObject(annotation.name()));
487         }
488     }
489 
getType(List<T> res)490     private <T> Type getType(List<T> res) {
491         Type clazz = res.getClass().getGenericSuperclass();
492         ParameterizedType pt = null;
493         if (clazz instanceof ParameterizedType) {
494             pt = (ParameterizedType) clazz;
495         }
496         if (pt == null) {
497             return clazz;
498         }
499         return pt.getActualTypeArguments()[0];
500     }
501 
releaseA(ResultSet rs, Statement stat, Connection conn)502     private void releaseA(ResultSet rs, Statement stat, Connection conn) {
503         try {
504             if (Objects.nonNull(rs)) {
505                 rs.close();
506             }
507             if (Objects.nonNull(stat)) {
508                 stat.close();
509             }
510             if (Objects.nonNull(conn)) {
511                 freeA(conn);
512             }
513         } catch (SQLException exception) {
514             exception.printStackTrace();
515         }
516     }
517 
releaseB(ResultSet rs, Statement stat, Connection conn)518     private void releaseB(ResultSet rs, Statement stat, Connection conn) {
519         try {
520             if (Objects.nonNull(rs)) {
521                 rs.close();
522             }
523             if (Objects.nonNull(stat)) {
524                 stat.close();
525             }
526             if (Objects.nonNull(conn)) {
527                 freeB(conn);
528             }
529         } catch (SQLException exception) {
530             exception.printStackTrace();
531         }
532     }
533 
534     /**
535      * update a db
536      *
537      * @param em em
538      * @param args args
539      * @return update row count
540      */
updateA(Sql em, Object... args)541     public int updateA(Sql em, Object... args) {
542         String sql = String.format(Locale.ENGLISH, getSql(em.getName()), args);
543         return updateA(sql);
544     }
545 
546     /**
547      * update b db
548      *
549      * @param em em
550      * @param args args
551      * @return update row count
552      */
updateB(Sql em, Object... args)553     public int updateB(Sql em, Object... args) {
554         String sql = String.format(Locale.ENGLISH, getSql(em.getName()), args);
555         return updateB(sql);
556     }
557 
updateA(String sql)558     private int updateA(String sql) {
559         Connection conn = getConnA();
560         Statement stat = null;
561         try {
562             stat = conn.createStatement();
563             return stat.executeUpdate(sql);
564         } catch (SQLException exception) {
565             exception.printStackTrace();
566         } finally {
567             releaseA(null, stat, conn);
568         }
569         return 0;
570     }
571 
updateB(String sql)572     private int updateB(String sql) {
573         Connection conn = getConnB();
574         Statement stat = null;
575         try {
576             stat = conn.createStatement();
577             return stat.executeUpdate(sql);
578         } catch (SQLException exception) {
579             exception.printStackTrace();
580         } finally {
581             releaseB(null, stat, conn);
582         }
583         return 0;
584     }
585 }
586