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