Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions api/src/main/java/dev/plex/module/PlexModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -163,7 +164,11 @@ public PlexCommand getCommand(String name)
}

/**
* Opens a resource from this module's class loader.
* Opens a resource owned by this module.
*
* <p>Plex module class loaders delegate to Plex's class loader. This method
* searches the module class loader itself first so common paths such as
* {@code config.yml} cannot resolve to a resource bundled by Plex.</p>
*
* @param filename resource path
* @return resource stream, or {@code null} when the resource cannot be opened
Expand All @@ -173,7 +178,10 @@ public InputStream getResource(@NotNull String filename)
{
try
{
URL url = this.getClass().getClassLoader().getResource(filename);
ClassLoader classLoader = this.getClass().getClassLoader();
URL url = classLoader instanceof URLClassLoader moduleClassLoader
? moduleClassLoader.findResource(filename)
: classLoader.getResource(filename);
if (url == null)
{
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void load()
{
try
{
ConfigDefaultsMerger.Result result = ConfigDefaultsMerger.merge(file, module.getClass().getResourceAsStream("/" + from), to);
ConfigDefaultsMerger.Result result = ConfigDefaultsMerger.merge(file, module.getResource(from), to);
if (!result.addedKeys().isEmpty())
{
PlexLog.log("Merged default key(s) into " + to + ": " + String.join(", ", result.addedKeys()));
Expand All @@ -57,7 +57,7 @@ private void saveDefault()
{
File parent = file.getParentFile();
if (parent != null) parent.mkdirs();
try (InputStream stream = module.getClass().getResourceAsStream("/" + from))
try (InputStream stream = module.getResource(from))
{
if (stream == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.PreparedStatement;
Expand Down Expand Up @@ -131,7 +128,7 @@ private String readCore(ClassLoader classLoader, String version) throws SQLExcep
private String readModule(PlexModule module, String resourceRoot, String version) throws SQLException
{
String resource = resourceRoot + "/" + storageType.dialect().migrationDirectory() + "/" + version + ".sql";
try (InputStream stream = openModuleResource(module, resource))
try (InputStream stream = module.getResource(resource))
{
if (stream == null)
{
Expand All @@ -145,32 +142,6 @@ private String readModule(PlexModule module, String resourceRoot, String version
}
}

/**
* Opens a migration resource from the module's own jar.
*
* <p>A module class loader is parent-first with the Plex class loader as its
* parent, and core ships migration scripts at the same
* {@code db/migration/<dialect>/<version>.sql} paths a module uses. A plain
* {@link PlexModule#getResource(String)} lookup therefore resolves to Plex's
* core script instead of the module's own. {@link URLClassLoader#findResource}
* searches only the module jar, so the module always reads its own migration.</p>
*/
private InputStream openModuleResource(PlexModule module, String resource) throws IOException
{
if (module.getClass().getClassLoader() instanceof URLClassLoader moduleClassLoader)
{
URL url = moduleClassLoader.findResource(resource);
if (url == null)
{
return null;
}
URLConnection connection = url.openConnection();
connection.setUseCaches(false);
return connection.getInputStream();
}
return module.getResource(resource);
}

private String replaceTableTokens(String script, Function<String, String> tableResolver) throws SQLException
{
Matcher matcher = TABLE_TOKEN_PATTERN.matcher(script);
Expand Down
Loading