From 35f6ef3103237c66146a29dccd9afd81efea8892 Mon Sep 17 00:00:00 2001 From: Hideki Sugimoto Date: Mon, 23 Sep 2024 16:17:52 +0900 Subject: [PATCH] Remove change detection from SqlResourceManager and Add SqlResourceLoader --- REPL/repl.properties | 1 - .../co/future/uroborosql/client/SqlREPL.java | 3 +- .../co/future/uroborosql/store/SqlInfo.java | 79 ++ .../uroborosql/store/SqlResourceLoader.java | 90 ++ .../store/SqlResourceLoaderImpl.java | 288 ++++++ .../uroborosql/store/SqlResourceManager.java | 14 + .../store/SqlResourceManagerImpl.java | 842 +++++------------- .../co/future/uroborosql/UroboroSQLTest.java | 8 +- .../client/command/ListCommandTest.java | 6 +- .../client/command/ParseCommandTest.java | 6 +- .../client/command/QueryCommandTest.java | 6 +- .../client/command/UpdateCommandTest.java | 6 +- .../client/command/ViewCommandTest.java | 6 +- .../completer/BindParamCompleterTest.java | 5 +- .../completer/SqlNameCompleterTest.java | 2 +- .../store/SqlResourceManagerTest.java | 482 +--------- 16 files changed, 738 insertions(+), 1106 deletions(-) create mode 100644 src/main/java/jp/co/future/uroborosql/store/SqlInfo.java create mode 100644 src/main/java/jp/co/future/uroborosql/store/SqlResourceLoader.java create mode 100644 src/main/java/jp/co/future/uroborosql/store/SqlResourceLoaderImpl.java diff --git a/REPL/repl.properties b/REPL/repl.properties index f874fff7..7d07cf99 100644 --- a/REPL/repl.properties +++ b/REPL/repl.properties @@ -8,7 +8,6 @@ sql.versionColumnName=lock_no sql.optimisticLockSupplier=jp.co.future.uroborosql.mapping.FieldIncrementOptimisticLockSupplier #sql.loadPath=sql #sql.fileExtension=.sql -#sql.detectChanges=true executionContextProvider.constantClassNames=jp.co.future.uroborosql.context.test.TestConsts executionContextProvider.enumConstantPackageNames=jp.co.future.uroborosql.context.test diff --git a/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java b/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java index 046f8988..4b9b1d48 100644 --- a/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java +++ b/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java @@ -228,11 +228,10 @@ private void initialize(final Terminal terminal) throws Exception { var loadPath = p("sql.loadPath", "sql"); var fileExtension = p("sql.fileExtension", ".sql"); var charset = Charset.forName(p("sql.encoding", "UTF-8")); - var detectChanges = Boolean.parseBoolean(p("sql.detectChanges", "true")); // config sqlConfig = UroboroSQL.builder(url, user, password, schema) - .setSqlResourceManager(new SqlResourceManagerImpl(loadPath, fileExtension, charset, detectChanges)) + .setSqlResourceManager(new SqlResourceManagerImpl(loadPath, fileExtension, charset, true)) .build(); sqlConfig.getEventListenerHolder().addEventSubscriber(new DumpResultEventSubscriber()); diff --git a/src/main/java/jp/co/future/uroborosql/store/SqlInfo.java b/src/main/java/jp/co/future/uroborosql/store/SqlInfo.java new file mode 100644 index 00000000..e227cbc3 --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/store/SqlInfo.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.store; + +import java.nio.file.Path; + +/** + * SQLファイルの情報を保持するオブジェクト + */ +public class SqlInfo { + /** zip, jar内のファイルのscheme */ + public static final String SCHEME_JAR = "jar"; + + /** ファイルシステム上のファイルのscheme */ + public static final String SCHEME_FILE = "file"; + + /** sqlNameに対応するPath. */ + private final Path path; + + /** 読み込みを行ったSQLルートパス */ + private final Path rootPath; + + /** 読み込んだファイルのscheme */ + private final String scheme; + + /** SQLファイルの内容.*/ + private final String sqlBody; + + /** + * コンストラクタ + * @param path Path + * @param rootPath 読み込みを行ったSQLルートパス + * @param scheme 読み込んだファイルのscheme + * @param sqlBody SqlBody + */ + public SqlInfo(final Path path, final Path rootPath, final String scheme, final String sqlBody) { + this.path = path; + this.rootPath = rootPath; + this.scheme = scheme; + this.sqlBody = sqlBody; + } + + /** + * sqlNameに対応するPath.を取得します. + * @return sqlNameに対応するPath. + */ + public Path getPath() { + return path; + } + + /** + * 読み込みを行ったSQLルートパスを取得します. + * @return 読み込みを行ったSQLルートパス + */ + public Path getRootPath() { + return rootPath; + } + + /** + * 読み込んだファイルのschemeを取得します. + * @return 読み込んだファイルのscheme + */ + public String getScheme() { + return scheme; + } + + /** + * SQLファイルの内容.を取得します. + * @return SQLファイルの内容. + */ + public String getSqlBody() { + return sqlBody; + } + +} \ No newline at end of file diff --git a/src/main/java/jp/co/future/uroborosql/store/SqlResourceLoader.java b/src/main/java/jp/co/future/uroborosql/store/SqlResourceLoader.java new file mode 100644 index 00000000..3eddbe95 --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/store/SqlResourceLoader.java @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.store; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.util.List; + +/** + * SQLリソースローダー インタフェース. + * + * @author H.Sugimoto + * @since v1.0.0 + */ +public interface SqlResourceLoader { + /** + * ファイル拡張子を取得します. + * @return ファイル拡張子 + */ + String getFileExtension(); + + /** + * ファイル拡張子を設定します. + * @param fileExtension ファイル拡張子 + */ + void setFileExtension(final String fileExtension); + + /** + * Charsetを取得します. + * @return Charset + */ + Charset getCharset(); + + /** + * Charsetを設定します. + * @param charset Charset + */ + void setCharset(final Charset charset); + + /** + * クラスローダーを取得します. + * @return クラスローダー + */ + ClassLoader getClassLoader(); + + /** + * 指定した名前に対するリソースのURLを取得します. + * @param name リソース名 + * @return リソースに対するURL + */ + URL getResource(String name); + + /** + * 指定した名前に対するリソースのURLを取得します. + * @param path リソースパス + * @return リソースに対するURL + */ + URL getResource(Path path); + + /** + * 指定したパス配下のSQLリソースをすべて取得します. + * @param rootPath SQLリソースのルートパス + * @return 取得したSQL情報のリスト + */ + List loadAllSql(final Path rootPath); + + /** + * 指定されたInputStreamからSQL本文を取得します. 引数のInputStreamは読み込み後クローズされます. + * @param is 対象のInputStream + * @return SQL本文 + * @throws IOException SQLの読み込みに失敗した場合 + */ + String loadSql(final InputStream is) throws IOException; + + /** + * 指定されたURLからSQL本文を取得します. 引数のURLから取得したInputStreamは読み込み後クローズされます. + * @param url 対象のURL + * @return SQL本文 + * @throws IOException SQLの読み込みに失敗した場合 + */ + String loadSql(final URL url) throws IOException; + +} diff --git a/src/main/java/jp/co/future/uroborosql/store/SqlResourceLoaderImpl.java b/src/main/java/jp/co/future/uroborosql/store/SqlResourceLoaderImpl.java new file mode 100644 index 00000000..c167af87 --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/store/SqlResourceLoaderImpl.java @@ -0,0 +1,288 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.store; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.JarURLConnection; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import jp.co.future.uroborosql.exception.UroborosqlRuntimeException; +import jp.co.future.uroborosql.log.support.ServiceLoggingSupport; +import jp.co.future.uroborosql.utils.ObjectUtils; + +/** + * SQLリソースローダーのデフォルト実装 + * + * @author H.Sugimoto + * @since v1.0.0 + */ +public class SqlResourceLoaderImpl implements SqlResourceLoader, ServiceLoggingSupport { + /** CharBufferのキャパシティ. */ + private static final int BUFFER_CAPACITY = 8 * 1024; + + /** SQLファイル拡張子 */ + private String fileExtension; + + /** SQLファイルエンコーディング */ + private Charset charset; + + /** + * コンストラクタ + */ + public SqlResourceLoaderImpl() { + this(".sql", Charset.forName(Charset.defaultCharset().displayName())); + } + + /** + * コンストラクタ + * @param fileExtension SQLファイル拡張子 + * @param charset SQLファイルエンコーディング + */ + public SqlResourceLoaderImpl(final String fileExtension, final Charset charset) { + this.fileExtension = fileExtension; + this.charset = charset; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#getFileExtension() + */ + @Override + public String getFileExtension() { + return fileExtension; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#setFileExtension(java.lang.String) + */ + @Override + public void setFileExtension(final String fileExtension) { + this.fileExtension = fileExtension; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#getCharset() + */ + @Override + public Charset getCharset() { + return charset; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#setCharset(java.nio.charset.Charset) + */ + @Override + public void setCharset(final Charset charset) { + this.charset = charset; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#getClassLoader() + */ + @Override + public ClassLoader getClassLoader() { + return Thread.currentThread().getContextClassLoader(); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#getResource(java.lang.String) + */ + @Override + public URL getResource(final String name) { + return getClassLoader().getResource(name); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#getResource(java.nio.file.Path) + */ + @Override + public URL getResource(final Path path) { + return getResource(path.toString()); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#loadAllSql(java.nio.file.Path) + */ + @Override + public List loadAllSql(final Path rootPath) { + return getClassLoader().resources(rootPath.toString().replace('\\', '/')) + .flatMap(url -> { + try { + var scheme = url.toURI().getScheme(); + if (SqlInfo.SCHEME_FILE.equalsIgnoreCase(scheme)) { + return traverseFile(url, rootPath).stream(); + } else if (SqlInfo.SCHEME_JAR.equalsIgnoreCase(scheme)) { + return traverseJar(url, rootPath).stream(); + } else { + warnWith(LOG) + .setMessage("Unsupported scheme. scheme : {}, url : {}") + .addArgument(scheme) + .addArgument(url) + .log(); + } + return null; + } catch (IOException | URISyntaxException ex) { + errorWith(LOG) + .setMessage("Can't load sql files.") + .setCause(ex) + .log(); + throw new UroborosqlRuntimeException("I/O error occurred.", ex); + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * 指定されたURL配下のファイルを順次追跡し、PathとSQL本文のMapを返却する. + * + * @param url 追跡を行うディレクトリ、またはファイルのURL + * @param rootPath 読み込みを行ったSQLルートパス + * @return PathとSQL本文を格納したMap + * @throws IOException SQLの読み込みに失敗した場合 + */ + private List traverseFile(final URL url, final Path rootPath) throws IOException { + traceWith(LOG) + .setMessage("traverseFile start. url : {}.") + .addArgument(url) + .log(); + try { + var path = Path.of(url.toURI()); + if (Files.notExists(path)) { + List.of(); + } + var sqlInfos = new ArrayList(); + if (Files.isDirectory(path)) { + try (var ds = Files.newDirectoryStream(path)) { + for (var child : ds) { + sqlInfos.addAll(traverseFile(child.toUri().toURL(), rootPath)); + } + } catch (IOException ex) { + throw new UroborosqlRuntimeException("I/O error occurred.", ex); + } + } else if (path.toString().endsWith(getFileExtension())) { + var sqlBody = loadSql(url.openStream()); + sqlInfos.add(new SqlInfo(path, rootPath, SqlInfo.SCHEME_FILE, sqlBody)); + } + return sqlInfos; + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + } + + /** + * 指定されたjarのURL配下のファイルを順次追跡し、PathとSQL本文のMapを返却する. + * + * @param url 追跡を行うディレクトリ、またはファイルのURL + * @param rootPath 読み込みを行ったSQLルートパス + * @return PathとSQL本文を格納したMap + * @throws IOException SQLの読み込みに失敗した場合 + */ + private List traverseJar(final URL url, final Path rootPath) throws IOException { + var conn = (JarURLConnection) url.openConnection(); + try (var jarFile = conn.getJarFile()) { + return jarFile.stream() + .map(jarEntry -> { + try { + var name = jarEntry.getName(); + if (!jarEntry.isDirectory() && name.endsWith(getFileExtension())) { + var path = Paths.get(name); + var sqlBody = loadSql(jarFile.getInputStream(jarEntry)); + return new SqlInfo(path, rootPath, SqlInfo.SCHEME_JAR, sqlBody); + } else if (jarEntry.isDirectory()) { + traceWith(LOG) + .setMessage("traverseJar start. name : {}.") + .addArgument(name) + .log(); + return null; + } else { + return null; + } + } catch (IOException ex) { + throw new UroborosqlRuntimeException("I/O error occurred.", ex); + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } catch (UroborosqlRuntimeException ex) { + throw (IOException) ex.getCause(); + } + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#loadSql(java.net.URL) + */ + @Override + public String loadSql(final URL url) throws IOException { + return loadSql(url.openStream()); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceLoader#loadSql(java.io.InputStream) + */ + @Override + public String loadSql(final InputStream is) throws IOException { + try (var reader = new BufferedReader(new InputStreamReader(is, getCharset()))) { + var builder = new StringBuilder(); + var charBuffer = CharBuffer.allocate(BUFFER_CAPACITY); + var numCharsRead = 0; + while ((numCharsRead = reader.read(charBuffer)) != -1) { + builder.append(charBuffer.array(), 0, numCharsRead); + charBuffer.clear(); + } + return formatSqlBody(builder.toString()); + } + } + + /** + * SQL文の不要な文字削除と末尾の改行文字付与を行う. + * + * @param sqlBody 元となるSQL文 + * @return 整形後のSQL文 + */ + private String formatSqlBody(final String sqlBody) { + var newBody = sqlBody.trim(); + if (newBody.endsWith("/") && !newBody.endsWith("*/")) { + newBody = ObjectUtils.removeEnd(newBody, "/"); + } else { + newBody = newBody + System.lineSeparator(); + } + return newBody; + } +} diff --git a/src/main/java/jp/co/future/uroborosql/store/SqlResourceManager.java b/src/main/java/jp/co/future/uroborosql/store/SqlResourceManager.java index e83896fd..d31d0ba3 100644 --- a/src/main/java/jp/co/future/uroborosql/store/SqlResourceManager.java +++ b/src/main/java/jp/co/future/uroborosql/store/SqlResourceManager.java @@ -18,6 +18,8 @@ * @author H.Sugimoto */ public interface SqlResourceManager extends ServiceLoggingSupport { + /** SQLファイルロードのデフォルトルートパス */ + String DEFAULT_LOAD_PATH = "sql"; /** * 初期化
@@ -124,4 +126,16 @@ public interface SqlResourceManager extends ServiceLoggingSupport { */ void setDialect(Dialect dialect); + /** + * SqlResourceLoaderの取得 + * @return SqlResourceLoader + */ + SqlResourceLoader getSqlResourceLoader(); + + /** + * SqlResourceLoaderの設定 + * @param sqlResourceLoader SqlResourceLoader + */ + void setSqlResourceLoader(SqlResourceLoader sqlResourceLoader); + } \ No newline at end of file diff --git a/src/main/java/jp/co/future/uroborosql/store/SqlResourceManagerImpl.java b/src/main/java/jp/co/future/uroborosql/store/SqlResourceManagerImpl.java index ef52b99a..2751fab8 100644 --- a/src/main/java/jp/co/future/uroborosql/store/SqlResourceManagerImpl.java +++ b/src/main/java/jp/co/future/uroborosql/store/SqlResourceManagerImpl.java @@ -6,46 +6,24 @@ */ package jp.co.future.uroborosql.store; -import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; -import static java.nio.file.StandardWatchEventKinds.OVERFLOW; - -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.net.JarURLConnection; import java.net.URISyntaxException; -import java.net.URL; import java.nio.charset.Charset; -import java.nio.file.FileSystem; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.WatchEvent; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.nio.file.attribute.FileTime; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import jp.co.future.uroborosql.dialect.Dialect; import jp.co.future.uroborosql.exception.UroborosqlRuntimeException; -import jp.co.future.uroborosql.log.support.ServiceLoggingSupport; -import jp.co.future.uroborosql.utils.ObjectUtils; /** * SQLリソース管理実装クラス @@ -53,14 +31,6 @@ * @author H.Sugimoto */ public class SqlResourceManagerImpl implements SqlResourceManager { - /** zip, jar内のファイルのscheme */ - private static final String SCHEME_JAR = "jar"; - /** ファイルシステム上のファイルのscheme */ - private static final String SCHEME_FILE = "file"; - - /** SQLファイルロードのデフォルトルートパス */ - private static final String DEFAULT_LOAD_PATH = "sql"; - /** 有効なDialectのSet */ private static final Set dialects = StreamSupport .stream(ServiceLoader.load(Dialect.class).spliterator(), false) @@ -79,38 +49,31 @@ public class SqlResourceManagerImpl implements SqlResourceManager { /** SQLファイルエンコーディング */ private final Charset charset; - /** SQLファイルの変更を検知するかどうか */ - private final boolean detectChanges; + /** 初期化時にSQLを全件ロードするかどうか */ + private final boolean loadAllOnInitialize; /** Dialect */ private Dialect dialect; - /** SQLファイル監視サービス */ - private WatchService watcher; - - /** SQLファイル監視サービスの実行サービス */ - private ExecutorService es; - /** sqlNameとそれに対するSqlInfoの紐付きを持つMap */ protected final ConcurrentHashMap sqlInfos = new ConcurrentHashMap<>(); - /** WatchKeyに対するディレクトリPathを取得するためのMap */ - protected final ConcurrentHashMap watchDirs = new ConcurrentHashMap<>(); + /** SQLリソースローダー */ + private SqlResourceLoader sqlResourceLoader; /** * コンストラクタ */ public SqlResourceManagerImpl() { - this(DEFAULT_LOAD_PATH); + this(DEFAULT_LOAD_PATH, false); } /** * コンストラクタ - * - * @param detectChanges SQLファイルの変更を検知するかどうか + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか */ - public SqlResourceManagerImpl(final boolean detectChanges) { - this(DEFAULT_LOAD_PATH, null, null, detectChanges); + public SqlResourceManagerImpl(final boolean loadAllOnInitialize) { + this(DEFAULT_LOAD_PATH, loadAllOnInitialize); } /** @@ -119,7 +82,17 @@ public SqlResourceManagerImpl(final boolean detectChanges) { * @param loadPath SQLファイルをロードするルートパス */ public SqlResourceManagerImpl(final String loadPath) { - this(loadPath, null); + this(loadPath, null, false); + } + + /** + * コンストラクタ + * + * @param loadPath SQLファイルをロードするルートパス + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか + */ + public SqlResourceManagerImpl(final String loadPath, final boolean loadAllOnInitialize) { + this(loadPath, null, loadAllOnInitialize); } /** @@ -132,6 +105,18 @@ public SqlResourceManagerImpl(final String loadPath, final String fileExtension) this(loadPath, fileExtension, null); } + /** + * コンストラクタ + * + * @param loadPath SQLファイルをロードするルートパス + * @param fileExtension SQLファイル拡張子 + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか + */ + public SqlResourceManagerImpl(final String loadPath, final String fileExtension, + final boolean loadAllOnInitialize) { + this(loadPath, fileExtension, null, loadAllOnInitialize); + } + /** * コンストラクタ * @@ -140,7 +125,7 @@ public SqlResourceManagerImpl(final String loadPath, final String fileExtension) * @param charset SQLファイルエンコーディング */ public SqlResourceManagerImpl(final String loadPath, final String fileExtension, final Charset charset) { - this(loadPath, fileExtension, charset, false); + this(List.of(loadPath), fileExtension, charset, false); } /** @@ -149,11 +134,11 @@ public SqlResourceManagerImpl(final String loadPath, final String fileExtension, * @param loadPath SQLファイルをロードするルートパス * @param fileExtension SQLファイル拡張子 * @param charset SQLファイルエンコーディング - * @param detectChanges SQLファイルの変更を検知するかどうか + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか */ public SqlResourceManagerImpl(final String loadPath, final String fileExtension, final Charset charset, - final boolean detectChanges) { - this(List.of(loadPath), fileExtension, charset, detectChanges); + final boolean loadAllOnInitialize) { + this(List.of(loadPath), fileExtension, charset, loadAllOnInitialize); } /** @@ -165,6 +150,16 @@ public SqlResourceManagerImpl(final List loadPaths) { this(loadPaths, null); } + /** + * コンストラクタ + * + * @param loadPaths SQLファイルをロードするルートパスのリスト + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか + */ + public SqlResourceManagerImpl(final List loadPaths, final boolean loadAllOnInitialize) { + this(loadPaths, null, loadAllOnInitialize); + } + /** * コンストラクタ * @@ -175,12 +170,26 @@ public SqlResourceManagerImpl(final List loadPaths, final String fileExt this(loadPaths, fileExtension, null); } + /** + * コンストラクタ + * + * @param loadPaths SQLファイルをロードするルートパスのリスト + * @param fileExtension SQLファイル拡張子 + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか + */ + public SqlResourceManagerImpl(final List loadPaths, final String fileExtension, + final boolean loadAllOnInitialize) { + this(loadPaths, fileExtension, null, loadAllOnInitialize); + } + /** * コンストラクタ * * @param loadPaths SQLファイルをロードするルートパスのリスト * @param fileExtension SQLファイル拡張子 * @param charset SQLファイルエンコーディング + * + * @throws IllegalArgumentException loadPathsにnullが含まれる場合 */ public SqlResourceManagerImpl(final List loadPaths, final String fileExtension, final Charset charset) { this(loadPaths, fileExtension, charset, false); @@ -192,30 +201,25 @@ public SqlResourceManagerImpl(final List loadPaths, final String fileExt * @param loadPaths SQLファイルをロードするルートパスのリスト * @param fileExtension SQLファイル拡張子 * @param charset SQLファイルエンコーディング - * @param detectChanges SQLファイルの変更を検知するかどうか + * @param loadAllOnInitialize 初期化時にSQLを全件ロードするかどうか * * @throws IllegalArgumentException loadPathsにnullが含まれる場合 */ public SqlResourceManagerImpl(final List loadPaths, final String fileExtension, final Charset charset, - final boolean detectChanges) { - this.loadPaths = new ArrayList<>(); - for (var loadPath : loadPaths) { - if (loadPath == null) { - throw new IllegalArgumentException("loadPath is required."); - } - this.loadPaths.add(Paths.get(loadPath)); - } - this.loadPathPartsList = new ArrayList<>(); - for (var loadPath : this.loadPaths) { - var pathList = new ArrayList(); - for (var part : loadPath) { - pathList.add(part.toString()); - } - this.loadPathPartsList.add(pathList.toArray(new String[pathList.size()])); - } + final boolean loadAllOnInitialize) { + this.loadPaths = loadPaths.stream() + .filter(Objects::nonNull) + .map(Paths::get) + .collect(Collectors.toList()); + this.loadPathPartsList = this.loadPaths.stream() + .map(path -> StreamSupport.stream(path.spliterator(), false) + .map(Path::toString) + .toArray(String[]::new)) + .collect(Collectors.toList()); this.fileExtension = fileExtension != null ? fileExtension : ".sql"; this.charset = charset != null ? charset : Charset.forName(Charset.defaultCharset().displayName()); - this.detectChanges = detectChanges; + this.loadAllOnInitialize = loadAllOnInitialize; + this.sqlResourceLoader = new SqlResourceLoaderImpl(this.fileExtension, this.charset); } /** @@ -225,24 +229,8 @@ public SqlResourceManagerImpl(final List loadPaths, final String fileExt */ @Override public void initialize() { - if (detectChanges) { - try { - watcher = FileSystems.getDefault().newWatchService(); - } catch (IOException ex) { - errorWith(LOG) - .setMessage("Can't start watcher service.") - .setCause(ex) - .log(); - return; - } - } - - generateSqlInfos(); - - if (detectChanges) { - // Path監視用のスレッド実行 - es = Executors.newSingleThreadExecutor(); - es.execute(this::watchPath); + if (loadAllOnInitialize) { + generateAllSqlInfos(); } } @@ -253,83 +241,7 @@ public void initialize() { */ @Override public void shutdown() { - if (detectChanges) { - es.shutdown(); - try { - if (!es.awaitTermination(1000, TimeUnit.MILLISECONDS)) { - es.shutdownNow(); - } - } catch (InterruptedException ex) { - es.shutdownNow(); - } - } - } - - /** - * Pathの監視 - */ - private void watchPath() { - for (;;) { - //監視キーの送信を待機 - WatchKey key; - try { - key = watcher.take(); - } catch (InterruptedException ex) { - debugWith(LOG) - .log("WatchService caught InterruptedException."); - break; - } catch (Throwable ex) { - errorWith(LOG) - .setMessage("Unexpected exception occurred.") - .setCause(ex) - .log(); - break; - } - - for (var event : key.pollEvents()) { - var kind = event.kind(); - - if (kind == OVERFLOW) { - continue; - } - - //ファイル名はイベントのコンテキストです。 - @SuppressWarnings("unchecked") - var evt = (WatchEvent) event; - var dir = watchDirs.get(key); - var path = dir.resolve(evt.context()); - - debugWith(LOG) - .setMessage("file changed.({}). path={}") - .addArgument(kind.name()) - .addArgument(path) - .log(); - var isSqlFile = path.toString().endsWith(fileExtension); - if (Files.isDirectory(path) || !isSqlFile) { - // ENTRY_DELETEの時はFiles.isDirectory()がfalseになるので拡張子での判定も行う - if (kind == ENTRY_CREATE) { - traverseFile(path, true, false); - } else if (kind == ENTRY_DELETE) { - key.cancel(); - watchDirs.remove(key); - continue; - } - } else if (isSqlFile) { - if (kind == ENTRY_CREATE) { - traverseFile(path, true, false); - } else if (kind == ENTRY_MODIFY || kind == ENTRY_DELETE) { - var sqlName = getSqlName(path); - sqlInfos.computeIfPresent(sqlName, (k, v) -> v.computePath(path, kind == ENTRY_DELETE)); - } - } - } - key.reset(); - } - try { - watcher.close(); - } catch (IOException ex) { - // do nothing - } + this.sqlInfos.clear(); } /** @@ -373,6 +285,26 @@ public List getSqlPathList() { return list; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceManager#getSqlResourceLoader() + */ + @Override + public SqlResourceLoader getSqlResourceLoader() { + return sqlResourceLoader; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.store.SqlResourceManager#setSqlResourceLoader(jp.co.future.uroborosql.store.SqlResourceLoader) + */ + @Override + public void setSqlResourceLoader(final SqlResourceLoader sqlResourceLoader) { + this.sqlResourceLoader = sqlResourceLoader; + } + /** * {@inheritDoc} * @@ -393,41 +325,120 @@ public String getSql(final String sqlName) { if (existSql(sqlName)) { return sqlInfos.get(sqlName).getSqlBody(); } else { - throw new UroborosqlRuntimeException("sql file not found. sqlName : " + sqlName); + try { + if (generateSqlInfo(sqlName)) { + return sqlInfos.get(sqlName).getSqlBody(); + } else { + throw new UroborosqlRuntimeException("sql file not found. sqlName : " + sqlName); + } + } catch (IOException ex) { + throw new UroborosqlRuntimeException("I/O error occurred. sqName : " + sqlName, ex); + } } } /** - * sqlNameとそれに対するSqlInfoのMapを生成する - */ - protected void generateSqlInfos() { - try { - for (var loadPath : this.loadPaths) { - var loadPathSlash = loadPath.toString().replace('\\', '/'); - var root = Thread.currentThread().getContextClassLoader().getResources(loadPathSlash); - - while (root.hasMoreElements()) { - var url = root.nextElement(); - var scheme = url.toURI().getScheme(); - if (SCHEME_FILE.equalsIgnoreCase(scheme)) { - traverseFile(Paths.get(url.toURI()), detectChanges && true, false); - } else if (SCHEME_JAR.equalsIgnoreCase(scheme)) { - traverseJar(url, loadPathSlash); - } else { - warnWith(LOG) - .setMessage("Unsupported scheme. scheme : {}, url : {}") - .addArgument(scheme) - .addArgument(url) - .log(); - } + * sqlNameとそれに対するSqlInfoのMapを生成する. + */ + protected void generateAllSqlInfos() { + for (var loadPath : this.loadPaths) { + var sqls = sqlResourceLoader.loadAllSql(loadPath); + sqls.stream() + .forEach(sqlInfo -> { + var path = sqlInfo.getPath(); + if (validPath(path)) { + var sqlName = getSqlName(path); + this.sqlInfos.compute(sqlName, remappingSqlInfo(sqlInfo)); + } + }); + if (LOG.isTraceEnabled()) { + this.sqlInfos.forEach((sqlName, sqlInfo) -> { + traceWith(LOG) + .setMessage("SqlInfo - sqlName : {}, path : {}, rootPath : {}, scheme : {}, sqlBody : {}.") + .addArgument(sqlName) + .addArgument(sqlInfo.getPath()) + .addArgument(sqlInfo.getRootPath()) + .addArgument(sqlInfo.getScheme()) + .addArgument(sqlInfo.getSqlBody()) + .log(); + }); + } + } + + } + + /** + * sqlNameに対するSqlInfoを生成する. + * + * @param sqlName SQL名 + * @return 生成に成功した場合true + * @throws IOException SQLの読み込みに失敗した場合 + */ + protected boolean generateSqlInfo(final String sqlName) throws IOException { + var dialectName = dialect.getDatabaseType().toLowerCase(); + for (var loadPath : loadPaths) { + var path = loadPath.resolve(dialectName).resolve(sqlName + fileExtension); + var url = sqlResourceLoader.getResource(path); + if (url == null) { + path = loadPath.resolve(sqlName + fileExtension); + url = sqlResourceLoader.getResource(path); + } + if (url != null) { + try { + var scheme = url.toURI().getScheme().toLowerCase(); + var sqlBody = sqlResourceLoader.loadSql(url); + var sqlInfo = new SqlInfo(path, loadPath, scheme, sqlBody); + this.sqlInfos.compute(sqlName, remappingSqlInfo(sqlInfo)); + traceWith(LOG) + .setMessage("SqlInfo - sqlName : {}, path : {}, rootPath : {}, scheme : {}, sqlBody : {}.") + .addArgument(sqlName) + .addArgument(sqlInfo.getPath()) + .addArgument(sqlInfo.getRootPath()) + .addArgument(sqlInfo.getScheme()) + .addArgument(sqlInfo.getSqlBody()) + .log(); + return true; + } catch (URISyntaxException ex) { + throw new IOException(ex); } } - } catch (IOException | URISyntaxException ex) { - errorWith(LOG) - .setMessage("Can't load sql files.") - .setCause(ex) - .log(); } + return false; + } + + /** + * 優先度が高いSqlInfoが採用されるようにMapの再配置を行う. + *
+	 * 1. Dialect付Pathを優先
+	 * 2. schemeはjarよりもfileを優先
+	 * 3. rootPathがloadPathsの並び順で前にいるものを優先
+	 * 
+ * @param sqlInfo + * + * @return 優先度判定を行った結果優先となったインスタンスを返すBiFunction + */ + private BiFunction remappingSqlInfo(final SqlInfo sqlInfo) { + return (k, v) -> { + if (v == null) { + // sqlNameに対するインスタンスがなければ追加 + return sqlInfo; + } else { + // Dialect付Pathを優先 + if (isDialectPath(sqlInfo.getPath()) && !isDialectPath(v.getPath())) { + return sqlInfo; + } + // schemeはjarよりもfileを優先 + if (SqlInfo.SCHEME_FILE.equals(sqlInfo.getScheme()) && SqlInfo.SCHEME_JAR.equals(v.getScheme())) { + return sqlInfo; + } + // ロードパスの並び順が先の方を優先 + if (loadPaths.indexOf(sqlInfo.getRootPath()) < loadPaths.indexOf(v.getRootPath())) { + return sqlInfo; + } + // それ以外の場合は現在のインスタンスを適用 + return v; + } + }; } /** @@ -467,7 +478,15 @@ public Path getSqlPath(final String sqlName) { if (existSql(sqlName)) { return sqlInfos.get(sqlName).getPath(); } else { - throw new UroborosqlRuntimeException("sql file not found. sqlName : " + sqlName); + try { + if (generateSqlInfo(sqlName)) { + return sqlInfos.get(sqlName).getPath(); + } else { + throw new UroborosqlRuntimeException("sql file not found. sqlName : " + sqlName); + } + } catch (IOException ex) { + throw new UroborosqlRuntimeException("I/O error occurred. sqName : " + sqlName, ex); + } } } @@ -478,11 +497,9 @@ public Path getSqlPath(final String sqlName) { * @param path 相対パスを取得する元のパス * @return 相対パス */ - private Path relativePath(final Path path) { - var pathList = new ArrayList(); - for (var part : path) { - pathList.add(part); - } + protected Path relativePath(final Path path) { + var pathList = StreamSupport.stream(path.spliterator(), false) + .collect(Collectors.toList()); for (var loadPathParts : this.loadPathPartsList) { var loadPathSize = loadPathParts.length; @@ -518,433 +535,28 @@ private Path relativePath(final Path path) { * @param path 検査対象のPath * @return 妥当なPathの場合true */ - private boolean validPath(final Path path) { + protected boolean validPath(final Path path) { var relativePath = relativePath(path); if (relativePath.equals(path)) { return true; } - var d = relativePath.getName(0).toString().toLowerCase(); + var dialectName = relativePath.getName(0).toString().toLowerCase(); // loadPathの直下が現在のdialect以外と一致する場合は無効なパスと判定する - return !dialects.contains(d) || this.dialect.getDatabaseType().equals(d); - - } - - /** - * 指定されたPath配下のファイルを順次追跡し、sqlInfosに格納、または削除を行う。
- * また、監視対象指定があり、Pathがディレクトリの場合は、監視サービスに登録する。 - * - * @param path 追跡を行うディレクトリ、またはファイルのPath - * @param watch 監視対象指定。trueの場合監視対象 - * @param remove 削除指定。trueの場合、指定のPathを除外する。falseの場合は格納する - */ - private void traverseFile(final Path path, final boolean watch, final boolean remove) { - traceWith(LOG) - .setMessage("traverseFile start. path : {}, watch : {}, remove : {}.") - .addArgument(path) - .addArgument(watch) - .addArgument(remove) - .log(); - if (Files.notExists(path)) { - return; - } - if (Files.isDirectory(path)) { - if (validPath(path)) { - try (var ds = Files.newDirectoryStream(path)) { - if (watch) { - var key = path.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); - watchDirs.put(key, path); - } - for (var child : ds) { - traverseFile(child, watch, remove); - } - } catch (IOException ex) { - throw new UroborosqlRuntimeException("I/O error occurred.", ex); - } - } - } else if (path.toString().endsWith(fileExtension)) { - var sqlName = getSqlName(path); - this.sqlInfos.compute(sqlName, (k, v) -> v == null ? new SqlInfo(sqlName, path, loadPaths, dialect, charset) - : v.computePath(path, remove)); - } + return !dialects.contains(dialectName) || isDialectPath(relativePath); } /** - * 指定されたjarのURL配下のファイルを順次追跡し、sqlInfosに格納を行う。
- * - * @param url 追跡を行うディレクトリ、またはファイルのURL - * @param loadPath SQLファイルをロードするパス + * Dialect配下のPathかどうかを判定する. + * @param path 対象となるPath + * @return Dialect配下のPathの場合true */ - @SuppressWarnings("resource") - private void traverseJar(final URL url, final String loadPath) { - traceWith(LOG) - .setMessage("traverseJar start. url : {}, loadPath : {}.") - .addArgument(url) - .addArgument(loadPath) - .log(); - FileSystem fs = null; - try { - var uri = url.toURI(); - try { - fs = FileSystems.getFileSystem(uri); - } catch (FileSystemNotFoundException ex) { - fs = FileSystems.newFileSystem(uri, Map.of("create", "false")); - } - - var conn = (JarURLConnection) url.openConnection(); - try (var jarFile = conn.getJarFile()) { - var jarEntries = jarFile.entries(); - while (jarEntries.hasMoreElements()) { - var jarEntry = jarEntries.nextElement(); - var name = jarEntry.getName(); - if (!jarEntry.isDirectory() && name.startsWith(loadPath) && name.endsWith(fileExtension)) { - var path = fs.getPath(name); - var sqlName = getSqlName(path); - this.sqlInfos.compute(sqlName, (k, v) -> v == null - ? new SqlInfo(sqlName, path, loadPaths, dialect, charset) - : v.computePath(path, false)); - } - } - } - } catch (IOException | URISyntaxException ex) { - throw new UroborosqlRuntimeException("I/O error occurred.", ex); - } finally { - if (fs != null) { - try { - fs.close(); - } catch (IOException ex) { - throw new UroborosqlRuntimeException("I/O error occurred.", ex); - } - } - } - } - - /** - * SQLファイルの情報を保持するオブジェクト - */ - public static class SqlInfo implements ServiceLoggingSupport { - /** キーとなるsqlName */ - private final String sqlName; - /** 対象のDialect */ - private final Dialect dialect; - /** Sqlファイルの文字コード */ - private final Charset charset; - /** sqlNameに対応するPathのList. ソートされて優先度が高いものから順に並んでいる. 適用されるのは先頭のPathになる. */ - private final List pathList = new ArrayList<>(); - /** SQLファイルをロードするルートパスのリスト */ - private final List loadPaths; - /** SQLファイルの内容. nullの場合、getSqlBody()が呼び出された段階でロードして格納する. */ - private String sqlBody; - /** 適用されたPathの最終更新日時。SQLファイルが更新されたかどうかの判定に利用する */ - private FileTime lastModified; - - /** - * コンストラクタ - * @param sqlName sqlName - * @param path path - * @param dialect dialect - * @param charset charset - */ - SqlInfo(final String sqlName, - final Path path, - final List loadPaths, - final Dialect dialect, - final Charset charset) { - traceWith(LOG) - .setMessage("SqlInfo - sqlName : {}, path : {}, dialect : {}, charset : {}.") - .addArgument(sqlName) - .addArgument(path) - .addArgument(dialect) - .addArgument(charset) - .log(); - this.sqlName = sqlName; - this.dialect = dialect; - this.charset = charset; - this.pathList.add(path); - this.loadPaths = loadPaths; - this.lastModified = getLastModifiedTime(path); - this.sqlBody = null; - } - - /** - * 指定されたPathの最終更新日時を取得する - * @param path 対象のPath - * @return 最終更新日時 - */ - private FileTime getLastModifiedTime(final Path path) { - if (SCHEME_FILE.equalsIgnoreCase(path.toUri().getScheme())) { - try { - return Files.getLastModifiedTime(path); - } catch (IOException ex) { - warnWith(LOG) - .setMessage("Can't get lastModifiedTime. path:{}") - .addArgument(path) - .setCause(ex) - .log(); - } - } - return FileTime.fromMillis(0L); - } - - /** - * 指定されたPathがDialect指定のPathかどうかを判定する - * @param path 判定対象Path - * @return Dialect指定Pathの場合true - */ - private boolean hasDialect(final Path path) { - for (var p : path) { - if (this.dialect.getDatabaseType().equals(p.toString())) { - return true; - } - } - return false; - } - - /** - * sqlName を取得します。 - * - * @return sqlName - */ - public String getSqlName() { - return sqlName; - } - - /** - * 現在有効な path を取得します。 - * - * @return path 現在有効なPath - */ - public Path getPath() { - return pathList.get(0); - } - - /** - * sql文字列を取得します。 - * sqlBodyがnullの場合、現在有効なPathからファイルの内容をロードし、sqlBodyに格納したうえ返却します。 - * - * @return sqlBody sql文字列 - */ - private String getSqlBody() { - if (sqlBody == null) { - var path = getPath(); - var scheme = path.toUri().getScheme(); - - if (SCHEME_FILE.equalsIgnoreCase(scheme)) { - // ファイルパスの場合 - if (Files.notExists(path)) { - throw new UroborosqlRuntimeException("SQL template could not found.[" - + path.toAbsolutePath().toString() + "]"); - } - synchronized (sqlName) { - try { - var body = new String(Files.readAllBytes(path), charset); - sqlBody = formatSqlBody(body); - debugWith(LOG) - .setMessage("Loaded SQL template.[{}]") - .addArgument(path) - .log(); - } catch (IOException ex) { - throw new UroborosqlRuntimeException("Failed to load SQL template[" - + path.toAbsolutePath().toString() + "].", ex); - } - } - } else { - // jarパスの場合 - var url = Thread.currentThread().getContextClassLoader().getResource(getResourcePath(path)); - if (url == null) { - throw new UroborosqlRuntimeException("SQL template could not found.[" - + path.toAbsolutePath().toString() + "]"); - } - synchronized (sqlName) { - try { - var conn = url.openConnection(); - try (var reader = new BufferedReader( - new InputStreamReader(conn.getInputStream(), charset))) { - var body = reader.lines() - .collect(Collectors.joining(System.lineSeparator())); - sqlBody = formatSqlBody(body); - debugWith(LOG) - .setMessage("Loaded SQL template.[{}]") - .addArgument(path) - .log(); - } - } catch (IOException ex) { - throw new UroborosqlRuntimeException("Failed to load SQL template[" - + path.toAbsolutePath().toString() + "].", ex); - } - } - } - } - return sqlBody; - } - - /** - * SQL文の不要な文字削除と末尾の改行文字付与を行う. - * - * @param sqlBody 元となるSQL文 - * @return 整形後のSQL文 - */ - protected String formatSqlBody(final String sqlBody) { - var newBody = sqlBody.trim(); - if (newBody.endsWith("/") && !newBody.endsWith("*/")) { - newBody = ObjectUtils.removeEnd(newBody, "/"); - } else { - newBody = newBody + System.lineSeparator(); - } - return newBody; - } - - /** - * 同じSqlNameになるPathの優先度判定を行い、優先度が高いPathが指定された場合保持しているPathの置き換えを行う - * - * @param newPath 判定用Path - * @param remove 指定した判定用Pathを削除する場合にtrueを指定 - * - * @return 判定後のSqlInfo - */ - private SqlInfo computePath(final Path newPath, final boolean remove) { - synchronized (sqlName) { - // 変更前の有効Pathを保持しておく - var oldPath = getPath(); - - // 引数で渡された判定用PathをpathListへ追加、またはpathListから削除する - if (!pathList.contains(newPath)) { - if (!remove) { - pathList.add(newPath); - } - } else { - if (remove) { - pathList.remove(newPath); - if (pathList.isEmpty()) { - // pathListが空になった場合はこのSqlInfoをsqlInfosから除外するためにnullを返す - return null; - } - } - } - - if (pathList.size() > 1) { - // 優先度が高いPathが先頭に来るようにソートを行う - // 1. Dialect付Pathを優先 - // 2. file を jar よりも優先 - // 3. Path同士のcompare - pathList.sort((p1, p2) -> { - if (p1 == null && p2 == null) { - return 0; - } else if (p1 != null && p2 == null) { - return -1; - } else if (p1 == null && p2 != null) { - return 1; - } - - // DialectPathの比較 - var p1HasDialect = hasDialect(p1); - var p2HasDialect = hasDialect(p2); - - if (p1HasDialect && !p2HasDialect) { - return -1; - } else if (!p1HasDialect && p2HasDialect) { - return 1; - } - - // schemeの比較 - var p1Scheme = p1.toUri().getScheme(); - var p2Scheme = p2.toUri().getScheme(); - - if (!p1Scheme.equals(p2Scheme)) { - if (SCHEME_FILE.equals(p1Scheme)) { - return -1; - } else { - return 1; - } - } - - // LoadPathsの並び順にソート - var p1Pos = 0; - var p2Pos = 0; - for (var pos = 0; pos < this.loadPaths.size(); pos++) { - var loadPath = this.loadPaths.get(pos); - var loadPathSize = loadPath.getNameCount(); - - for (var i = 0; i < p1.getNameCount() - loadPathSize; i++) { - var p1SubPath = p1.subpath(i, i + loadPathSize); - if (p1SubPath.equals(loadPath)) { - p1Pos = pos + 1; - break; - } - } - for (var i = 0; i < p2.getNameCount() - loadPathSize; i++) { - var p2SubPath = p2.subpath(i, i + loadPathSize); - if (p2SubPath.equals(loadPath)) { - p2Pos = pos + 1; - break; - } - } - if (p1Pos > 0 && p2Pos > 0) { - break; - } - } - if (p1Pos != p2Pos) { - return p1Pos - p2Pos; - } - - return p1.compareTo(p2); - }); - } - - var replaceFlag = false; - // ソートによる再計算後の有効Pathを取得する - var currentPath = getPath(); - var currentTimeStamp = getLastModifiedTime(currentPath); - if (!oldPath.equals(currentPath)) { - replaceFlag = true; - debugWith(LOG) - .setMessage("sql file switched. sqlName={}, oldPath={}, newPath={}, lastModified={}") - .addArgument(sqlName) - .addArgument(oldPath) - .addArgument(currentPath) - .addArgument(currentTimeStamp) - .log(); - } else { - if (!this.lastModified.equals(currentTimeStamp)) { - replaceFlag = true; - debugWith(LOG) - .setMessage("sql file changed. sqlName={}, path={}, lastModified={}") - .addArgument(sqlName) - .addArgument(currentPath) - .addArgument(currentTimeStamp) - .log(); - } - } - - if (replaceFlag) { - this.lastModified = currentTimeStamp; - this.sqlBody = null; - } - return this; - } - } - - /** - * クラスローダーから取得する際のリソースパス(loadPathで始まるパス)を取得する.
- * loadPathと一致する部分がなかった場合は、引数のpathの値をそのまま返却する - * - * @param path 計算対象のパス - * @return クラスローダーから取得する際のリソースパス - */ - private String getResourcePath(final Path path) { - var pathSize = path.getNameCount(); - - for (var loadPath : this.loadPaths) { - var loadPathSize = loadPath.getNameCount(); - - for (var i = 0; i < pathSize - loadPathSize; i++) { - var subPath = path.subpath(i, i + loadPathSize); - if (loadPath.equals(subPath)) { - return path.subpath(i, pathSize).toString(); - } - } + protected boolean isDialectPath(final Path path) { + for (var p : path) { + if (this.dialect.getDatabaseType().equals(p.toString().toLowerCase())) { + return true; } - return path.toString(); // loadPathと一致しなかった場合はパスをそのまま返却する。 } + return false; } } diff --git a/src/test/java/jp/co/future/uroborosql/UroboroSQLTest.java b/src/test/java/jp/co/future/uroborosql/UroboroSQLTest.java index 45ca061e..a1807ea9 100644 --- a/src/test/java/jp/co/future/uroborosql/UroboroSQLTest.java +++ b/src/test/java/jp/co/future/uroborosql/UroboroSQLTest.java @@ -36,7 +36,6 @@ import jp.co.future.uroborosql.dialect.H2Dialect; import jp.co.future.uroborosql.enums.InsertsType; import jp.co.future.uroborosql.event.EventListenerHolder; -import jp.co.future.uroborosql.store.SqlResourceManagerImpl; import jp.co.future.uroborosql.utils.CaseFormat; import jp.co.future.uroborosql.utils.ObjectUtils; @@ -168,8 +167,7 @@ void builderSetUrlMultiConnection() throws Exception { @Test void builderSetSqlResourceManager() throws Exception { - var config = UroboroSQL.builder("jdbc:h2:mem:" + this.getClass().getSimpleName(), "", "", null) - .setSqlResourceManager(new SqlResourceManagerImpl(false)).build(); + var config = UroboroSQL.builder("jdbc:h2:mem:" + this.getClass().getSimpleName(), "", "", null).build(); try (var agent = config.agent()) { var sqls = new String(Files.readAllBytes(Paths.get("src/test/resources/sql/ddl/create_tables.sql")), StandardCharsets.UTF_8).split(";"); @@ -183,7 +181,7 @@ void builderSetSqlResourceManager() throws Exception { agent.rollback(); } - assertEquals(true, config.getSqlResourceManager().existSql("ddl/create_tables")); + assertEquals(true, config.getSqlResourceManager().existSql("example/insert_product")); } @Test @@ -205,7 +203,7 @@ void builderSetEventListenerHolder() throws Exception { agent.rollback(); } - assertEquals(true, config.getSqlResourceManager().existSql("ddl/create_tables")); + assertEquals(true, config.getSqlResourceManager().existSql("example/insert_product")); } @Test diff --git a/src/test/java/jp/co/future/uroborosql/client/command/ListCommandTest.java b/src/test/java/jp/co/future/uroborosql/client/command/ListCommandTest.java index 8af2ee66..b526242f 100644 --- a/src/test/java/jp/co/future/uroborosql/client/command/ListCommandTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/command/ListCommandTest.java @@ -20,6 +20,7 @@ import jp.co.future.uroborosql.client.ReaderTestSupport; import jp.co.future.uroborosql.client.completer.ReplCommandCompleter; import jp.co.future.uroborosql.config.SqlConfig; +import jp.co.future.uroborosql.store.SqlResourceManagerImpl; import jp.co.future.uroborosql.utils.ObjectUtils; public class ListCommandTest extends ReaderTestSupport { @@ -34,7 +35,10 @@ public class ListCommandTest extends ReaderTestSupport { public void setUp() throws Exception { super.setUp(); - sqlConfig = UroboroSQL.builder(DriverManager.getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + sqlConfig = UroboroSQL + .builder(DriverManager + .getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + .setSqlResourceManager(new SqlResourceManagerImpl(true)) .build(); agent = sqlConfig.agent(); diff --git a/src/test/java/jp/co/future/uroborosql/client/command/ParseCommandTest.java b/src/test/java/jp/co/future/uroborosql/client/command/ParseCommandTest.java index 17dca49a..51fd796a 100644 --- a/src/test/java/jp/co/future/uroborosql/client/command/ParseCommandTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/command/ParseCommandTest.java @@ -27,11 +27,13 @@ public class ParseCommandTest extends ReaderTestSupport { public void setUp() throws Exception { super.setUp(); - sqlConfig = UroboroSQL.builder(DriverManager.getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + sqlConfig = UroboroSQL + .builder(DriverManager + .getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) .setExecutionContextProvider(new ExecutionContextProviderImpl() .setConstantClassNames(List.of("jp.co.future.uroborosql.context.test.TestConsts")) .setEnumConstantPackageNames(List.of("jp.co.future.uroborosql.context.test"))) - .setSqlResourceManager(new SqlResourceManagerImpl()) + .setSqlResourceManager(new SqlResourceManagerImpl(true)) .build(); command = new ParseCommand(); diff --git a/src/test/java/jp/co/future/uroborosql/client/command/QueryCommandTest.java b/src/test/java/jp/co/future/uroborosql/client/command/QueryCommandTest.java index 64ea6096..962e000b 100644 --- a/src/test/java/jp/co/future/uroborosql/client/command/QueryCommandTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/command/QueryCommandTest.java @@ -22,6 +22,7 @@ import jp.co.future.uroborosql.client.completer.ReplCommandCompleter; import jp.co.future.uroborosql.client.completer.SqlNameCompleter; import jp.co.future.uroborosql.config.SqlConfig; +import jp.co.future.uroborosql.store.SqlResourceManagerImpl; import jp.co.future.uroborosql.utils.ObjectUtils; public class QueryCommandTest extends ReaderTestSupport { @@ -36,7 +37,10 @@ public class QueryCommandTest extends ReaderTestSupport { public void setUp() throws Exception { super.setUp(); - sqlConfig = UroboroSQL.builder(DriverManager.getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + sqlConfig = UroboroSQL + .builder(DriverManager + .getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + .setSqlResourceManager(new SqlResourceManagerImpl(true)) .build(); agent = sqlConfig.agent(); diff --git a/src/test/java/jp/co/future/uroborosql/client/command/UpdateCommandTest.java b/src/test/java/jp/co/future/uroborosql/client/command/UpdateCommandTest.java index 5e29d945..4fc20080 100644 --- a/src/test/java/jp/co/future/uroborosql/client/command/UpdateCommandTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/command/UpdateCommandTest.java @@ -22,6 +22,7 @@ import jp.co.future.uroborosql.client.completer.ReplCommandCompleter; import jp.co.future.uroborosql.client.completer.SqlNameCompleter; import jp.co.future.uroborosql.config.SqlConfig; +import jp.co.future.uroborosql.store.SqlResourceManagerImpl; import jp.co.future.uroborosql.utils.ObjectUtils; public class UpdateCommandTest extends ReaderTestSupport { @@ -36,7 +37,10 @@ public class UpdateCommandTest extends ReaderTestSupport { public void setUp() throws Exception { super.setUp(); - sqlConfig = UroboroSQL.builder(DriverManager.getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + sqlConfig = UroboroSQL + .builder(DriverManager + .getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + .setSqlResourceManager(new SqlResourceManagerImpl(true)) .build(); agent = sqlConfig.agent(); diff --git a/src/test/java/jp/co/future/uroborosql/client/command/ViewCommandTest.java b/src/test/java/jp/co/future/uroborosql/client/command/ViewCommandTest.java index f30e6d41..0dff6208 100644 --- a/src/test/java/jp/co/future/uroborosql/client/command/ViewCommandTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/command/ViewCommandTest.java @@ -21,6 +21,7 @@ import jp.co.future.uroborosql.client.completer.ReplCommandCompleter; import jp.co.future.uroborosql.client.completer.SqlNameCompleter; import jp.co.future.uroborosql.config.SqlConfig; +import jp.co.future.uroborosql.store.SqlResourceManagerImpl; import jp.co.future.uroborosql.utils.ObjectUtils; public class ViewCommandTest extends ReaderTestSupport { @@ -35,7 +36,10 @@ public class ViewCommandTest extends ReaderTestSupport { public void setUp() throws Exception { super.setUp(); - sqlConfig = UroboroSQL.builder(DriverManager.getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + sqlConfig = UroboroSQL + .builder(DriverManager + .getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + .setSqlResourceManager(new SqlResourceManagerImpl(true)) .build(); agent = sqlConfig.agent(); diff --git a/src/test/java/jp/co/future/uroborosql/client/completer/BindParamCompleterTest.java b/src/test/java/jp/co/future/uroborosql/client/completer/BindParamCompleterTest.java index e286b4b9..d6b5537a 100644 --- a/src/test/java/jp/co/future/uroborosql/client/completer/BindParamCompleterTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/completer/BindParamCompleterTest.java @@ -33,8 +33,9 @@ public static void setUpClass() throws Exception { @BeforeEach public void setUp() throws Exception { super.setUp(); - sqlConfig = UroboroSQL.builder(DriverManager.getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) - .setSqlResourceManager(new SqlResourceManagerImpl(false)) + sqlConfig = UroboroSQL.builder(DriverManager + .getConnection("jdbc:h2:mem:" + this.getClass().getSimpleName() + ";DB_CLOSE_DELAY=-1")) + .setSqlResourceManager(new SqlResourceManagerImpl()) .setDialect(new DefaultDialect()) .build(); } diff --git a/src/test/java/jp/co/future/uroborosql/client/completer/SqlNameCompleterTest.java b/src/test/java/jp/co/future/uroborosql/client/completer/SqlNameCompleterTest.java index eddbc0c6..2c8962ea 100644 --- a/src/test/java/jp/co/future/uroborosql/client/completer/SqlNameCompleterTest.java +++ b/src/test/java/jp/co/future/uroborosql/client/completer/SqlNameCompleterTest.java @@ -25,7 +25,7 @@ public static void setUpClass() throws Exception { commands.add(command); } - sqlManager = new SqlResourceManagerImpl(false); + sqlManager = new SqlResourceManagerImpl(true); sqlManager.setDialect(new DefaultDialect()); sqlManager.initialize(); } diff --git a/src/test/java/jp/co/future/uroborosql/store/SqlResourceManagerTest.java b/src/test/java/jp/co/future/uroborosql/store/SqlResourceManagerTest.java index 7fc3de69..f244aa5c 100644 --- a/src/test/java/jp/co/future/uroborosql/store/SqlResourceManagerTest.java +++ b/src/test/java/jp/co/future/uroborosql/store/SqlResourceManagerTest.java @@ -4,15 +4,12 @@ import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assumptions.assumeFalse; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; @@ -52,18 +49,11 @@ void testConstructorMultiSqlPaths() throws Exception { assertThat(manager.getDialect(), is(dialect)); } - @Test - void testConstructorMultiSqlPathsNull() throws Exception { - assertThrows(IllegalArgumentException.class, () -> { - new SqlResourceManagerImpl(Arrays.asList(null, "secondary_sql")); - }); - } - @Test void testGetSqlPathList() throws Exception { assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - var manager = new SqlResourceManagerImpl(); + var manager = new SqlResourceManagerImpl(true); manager.setDialect(new H2Dialect()); manager.initialize(); @@ -150,7 +140,7 @@ void testGetSqlWithMultiSqlPathsReverse() throws Exception { void testGetSqlH2() throws Exception { assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - var manager = new SqlResourceManagerImpl(); + var manager = new SqlResourceManagerImpl(true); manager.setDialect(new H2Dialect()); manager.initialize(); @@ -176,7 +166,7 @@ void testGetSqlH2() throws Exception { void testGetSqlPostgresql() throws Exception { assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - var manager = new SqlResourceManagerImpl(); + var manager = new SqlResourceManagerImpl(true); manager.setDialect(new PostgresqlDialect()); manager.initialize(); @@ -198,42 +188,6 @@ void testGetSqlPostgresql() throws Exception { } } - @Test - void testGetSqlWithWatcher() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "test/ADD_WATCH"; - var newFilePath = Paths.get(TARGET_TEST_CLASSES_SQL1, sqlName + ".sql"); - Files.deleteIfExists(newFilePath); - - var manager = new SqlResourceManagerImpl(true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - assertThat(manager.existSql(sqlName), is(false)); - - Thread.sleep(WAIT_TIME); - - Files.write(newFilePath, List.of("select * from ADD_WATCH")); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(newFilePath); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - } finally { - manager.shutdown(); - } - - } - @Test void testGetSqlWithNoWatcher() throws Exception { @@ -241,7 +195,7 @@ void testGetSqlWithNoWatcher() throws Exception { var newFilePath = Paths.get(TARGET_TEST_CLASSES_SQL1, sqlName + ".sql"); Files.deleteIfExists(newFilePath); - var manager = new SqlResourceManagerImpl(); + var manager = new SqlResourceManagerImpl(true); manager.setDialect(new Oracle10Dialect()); manager.initialize(); @@ -264,196 +218,6 @@ void testGetSqlWithNoWatcher() throws Exception { } } - @Test - void testAddDialectSqlFolder() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "example/select_test"; - var dir = Paths.get(TARGET_TEST_CLASSES_SQL1, "oracle", "example"); - var newFilePath = dir.resolve("select_test.sql"); - Files.deleteIfExists(newFilePath); - Files.deleteIfExists(dir); - - var manager = new SqlResourceManagerImpl(true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); - - Thread.sleep(WAIT_TIME); - - Files.createDirectories(dir); - - var sql = "select * from test -- oracle"; - Files.write(newFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(newFilePath); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); - - Files.deleteIfExists(dir); - } finally { - manager.shutdown(); - } - } - - @Test - void testAddDefaultFolderAndDialectFolder() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "unit_test/select_test"; - var defaultDir = Paths.get(TARGET_TEST_CLASSES_SQL1, "unit_test"); - var dialectDir = Paths.get(TARGET_TEST_CLASSES_SQL1, "oracle", "unit_test"); - var defaultFilePath = defaultDir.resolve("select_test.sql"); - var dialectFilePath = dialectDir.resolve("select_test.sql"); - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - var manager = new SqlResourceManagerImpl(true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - - Thread.sleep(WAIT_TIME); - - // defaultから先に作る場合 - Files.createDirectories(defaultDir); - - var sql = "select * from test -- default"; - Files.write(defaultFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); - - Thread.sleep(WAIT_TIME); - - Files.createDirectories(dialectDir); - - sql = "select * from test -- oracle"; - Files.write(dialectFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - } finally { - manager.shutdown(); - } - } - - @Test - void testAddDialectFolderAndDefaultFolder() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "unit_test/select_test"; - var defaultDir = Paths.get(TARGET_TEST_CLASSES_SQL1, "unit_test"); - var dialectDir = Paths.get(TARGET_TEST_CLASSES_SQL1, "oracle", "unit_test"); - var defaultFilePath = defaultDir.resolve("select_test.sql"); - var dialectFilePath = dialectDir.resolve("select_test.sql"); - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - var manager = new SqlResourceManagerImpl(true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - - Thread.sleep(WAIT_TIME); - - // dialectから先に作る場合 - Files.createDirectories(dialectDir); - - var sql = "select * from test -- oracle"; - Files.write(dialectFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Thread.sleep(WAIT_TIME); - - Files.createDirectories(defaultDir); - - sql = "select * from test -- default"; - Files.write(defaultFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); // default より dialectが優先される - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); // dialect が削除された段階でdefaultが有効になる - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - } finally { - manager.shutdown(); - } - } - @Test void testConstructorLoadPathHasChildDir() throws Exception { var manager = new SqlResourceManagerImpl("parent/child/sql", ".sql", @@ -472,7 +236,7 @@ void testConstructorLoadPathHasChildDir() throws Exception { void testGetSqlPathListLoadPathHasChildDir() throws Exception { assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - var manager = new SqlResourceManagerImpl("parent/child/sql"); + var manager = new SqlResourceManagerImpl("parent/child/sql", true); manager.setDialect(new H2Dialect()); manager.initialize(); @@ -507,7 +271,7 @@ void testGetSqlLoadPathHasChildDir() throws Exception { void testGetSqlH2LoadPathHasChildDir() throws Exception { assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - var manager = new SqlResourceManagerImpl("parent/child/sql"); + var manager = new SqlResourceManagerImpl("parent/child/sql", true); manager.setDialect(new H2Dialect()); manager.initialize(); @@ -533,7 +297,7 @@ void testGetSqlH2LoadPathHasChildDir() throws Exception { void testGetSqlPostgresqlLoadPathHasChildDir() throws Exception { assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - var manager = new SqlResourceManagerImpl("parent/child/sql"); + var manager = new SqlResourceManagerImpl("parent/child/sql", true); manager.setDialect(new PostgresqlDialect()); manager.initialize(); @@ -555,43 +319,6 @@ void testGetSqlPostgresqlLoadPathHasChildDir() throws Exception { } } - @Test - void testGetSqlWithWatcherLoadPathHasChildDir() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "test/ADD_WATCH"; - var newFilePath = Paths.get(TARGET_TEST_CLASSES_SQL2, sqlName + ".sql"); - Files.deleteIfExists(newFilePath); - - var manager = new SqlResourceManagerImpl("parent/child/sql", ".sql", StandardCharsets.UTF_8, - true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - assertThat(manager.existSql(sqlName), is(false)); - - Thread.sleep(WAIT_TIME); - - Files.write(newFilePath, List.of("select * from ADD_WATCH")); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(newFilePath); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - } finally { - manager.shutdown(); - } - - } - @Test void testGetSqlWithNoWatcherLoadPathHasChildDir() throws Exception { @@ -599,7 +326,7 @@ void testGetSqlWithNoWatcherLoadPathHasChildDir() throws Exception { var newFilePath = Paths.get(TARGET_TEST_CLASSES_SQL2, sqlName + ".sql"); Files.deleteIfExists(newFilePath); - var manager = new SqlResourceManagerImpl("parent/child/sql"); + var manager = new SqlResourceManagerImpl("parent/child/sql", true); manager.setDialect(new Oracle10Dialect()); manager.initialize(); @@ -622,197 +349,4 @@ void testGetSqlWithNoWatcherLoadPathHasChildDir() throws Exception { } } - @Test - void testAddDialectSqlFolderLoadPathHasChildDir() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "example/select_test"; - var dir = Paths.get(TARGET_TEST_CLASSES_SQL2, "oracle", "example"); - var newFilePath = dir.resolve("select_test.sql"); - Files.deleteIfExists(newFilePath); - Files.deleteIfExists(dir); - - var manager = new SqlResourceManagerImpl("parent/child/sql", ".sql", StandardCharsets.UTF_8, - true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); - - Thread.sleep(WAIT_TIME); - - Files.createDirectories(dir); - - var sql = "select * from test -- oracle"; - Files.write(newFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(newFilePath); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); - - Files.deleteIfExists(dir); - } finally { - manager.shutdown(); - } - } - - @Test - void testAddDefaultFolderAndDialectFolderLoadPathHasChildDir() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "unit_test/select_test"; - var defaultDir = Paths.get(TARGET_TEST_CLASSES_SQL2, "unit_test"); - var dialectDir = Paths.get(TARGET_TEST_CLASSES_SQL2, "oracle", "unit_test"); - var defaultFilePath = defaultDir.resolve("select_test.sql"); - var dialectFilePath = dialectDir.resolve("select_test.sql"); - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - var manager = new SqlResourceManagerImpl("parent/child/sql", ".sql", StandardCharsets.UTF_8, - true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - - Thread.sleep(WAIT_TIME); - - // defaultから先に作る場合 - Files.createDirectories(defaultDir); - - var sql = "select * from test -- default"; - Files.write(defaultFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); - - Thread.sleep(WAIT_TIME); - - Files.createDirectories(dialectDir); - - sql = "select * from test -- oracle"; - Files.write(dialectFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - } finally { - manager.shutdown(); - } - } - - @Test - void testAddDialectFolderAndDefaultFolderLoadPathHasChildDir() throws Exception { - assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("mac")); - - var sqlName = "unit_test/select_test"; - var defaultDir = Paths.get(TARGET_TEST_CLASSES_SQL2, "unit_test"); - var dialectDir = Paths.get(TARGET_TEST_CLASSES_SQL2, "oracle", "unit_test"); - var defaultFilePath = defaultDir.resolve("select_test.sql"); - var dialectFilePath = dialectDir.resolve("select_test.sql"); - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - var manager = new SqlResourceManagerImpl("parent/child/sql", ".sql", StandardCharsets.UTF_8, - true); - manager.setDialect(new Oracle10Dialect()); - manager.initialize(); - - try { - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - - Thread.sleep(WAIT_TIME); - - // dialectから先に作る場合 - Files.createDirectories(dialectDir); - - var sql = "select * from test -- oracle"; - Files.write(dialectFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); - - Thread.sleep(WAIT_TIME); - - Files.createDirectories(defaultDir); - - sql = "select * from test -- default"; - Files.write(defaultFilePath, List.of(sql)); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("oracle")); // default より dialectが優先される - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(dialectFilePath); - Files.deleteIfExists(dialectDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(true)); - assertThat(manager.getSql(sqlName), containsString("default")); // dialect が削除された段階でdefaultが有効になる - - Thread.sleep(WAIT_TIME); - - Files.deleteIfExists(defaultFilePath); - Files.deleteIfExists(defaultDir); - - Thread.sleep(WAIT_TIME); - - assertThat(manager.existSql(sqlName), is(false)); - } finally { - manager.shutdown(); - } - } - }