-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Search for conf/application.conf and conf/routes from classpath (#198) #202
Search for conf/application.conf and conf/routes from classpath (#198) #202
Conversation
Hi @asolntsev, here is my naive try for fixing #198. 😅 About the protected methods in About the solution: as you can see the pattern is the following. Those startup files are resolved against Could we improve something about this pattern? How about extending |
a1edc32
to
8b9dbef
Compare
It would be nice , but no tests added. 😅 |
framework/src/play/Play.java
Outdated
@@ -158,6 +153,13 @@ public void init(String id) { | |||
setupApplicationMode(); | |||
VirtualFile appRoot = setupAppRoot(); | |||
routes = appRoot.child("conf/routes"); | |||
if (!routes.exists()) { | |||
try { | |||
routes = VirtualFile.open(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource("conf/routes")).getFile()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is better?
......getContextLoader().getResource()
+ relative path:conf/...
, orgetClass().getResource()
+ absolute path:/conf/...
?
Both works. 🤷♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure, but it seems to me reasonable to use getContextLoader()
because it allows users to use some custom classloader (for whatever reason).
} | ||
|
||
protected final VirtualFile resolveFileNameWithClasspath(String filename) { | ||
return VirtualFile.open(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource("conf/" + filename)).getPath()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VirtualFile
needs more love: it doesn't know jars. 😕
Exception in thread "main" play.exceptions.UnexpectedException: Failed to read /file:/app/classpath/app.jar!/conf/application.conf
at play.vfs.VirtualFile.inputstream(VirtualFile.java:106)
at play.libs.IO.readUtf8Properties(IO.java:17)
at play.PropertiesConfLoader.readOneConfigurationFile(PropertiesConfLoader.java:63)
at play.PropertiesConfLoader.readOneConfigurationFile(PropertiesConfLoader.java:34)
at play.PropertiesConfLoader.readOneConfigurationFile(PropertiesConfLoader.java:29)
at play.PropertiesConfLoader.readConfiguration(PropertiesConfLoader.java:25)
at play.Play.readConfiguration(Play.java:260)
at play.Play.init(Play.java:149)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another breaking point:
Exception in thread "main" play.exceptions.UnexpectedException: Failed to read /file:/app/classpath/app.jar!/conf/routes
at play.vfs.VirtualFile.contentAsString(VirtualFile.java:185)
at play.mvc.routing.RoutesParser.parse(RoutesParser.java:28)
at play.mvc.routing.RoutesParser.parse(RoutesParser.java:17)
at play.mvc.Router.loadRoutesFromFile(Router.java:69)
at play.mvc.Router.detectChanges(Router.java:131)
at play.Play.start(Play.java:280)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xabolcs Yes, initially in Play! framework VirtualFile
intention was to resolve files from the project itself and its modules
. It was not intended to find files in classpath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@asolntsev, thanks for replying.
Yeah, these exceptions suggest that too.
How could we continue? For me it would be the best that the Framework could work with jar
s and classpath also ... without breaking VirtualFile
's Play! 1 compatibility.
Of course the easiest way is to document these limitations for the RePlay App developers.
Of course, there are solutions in between too, like the current state! 🙂
Yeah, as in the log4j.properties
PR, I use and pack my App's conf
folder as a resource folder (becasuse my Idea hides a few folder if "they are too overlapping")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xabolcs I started reviewing the PR. Sorry for a long delay.
I have lots of doubts at the moment...
- When you call
openWithEntryName
, you always pass the same name twice its parameters. Duplication. - this change actually breaks
VirtualFile
API in that sense that many its methods will not work anymore.
@Test
void broken() {
File file = new File(Thread.currentThread().getContextClassLoader().getResource("org/opentest4j/AssertionFailedError.class").getFile());
VirtualFile virtualFile = VirtualFile.openWithEntryName(file, "org/opentest4j/AssertionFailedError.class");
virtualFile.child("some.txt"); // ?
virtualFile.length(); // 0
virtualFile.hashCode(); // ?
virtualFile.lastModified(); // 0
virtualFile.exists(); // FALSE!
virtualFile.list(); // null ?
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway, I'll try to incorporate this failing test and try to not break it with the first commit. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xabolcs The more I think about it, the more I come to a conclusion that VirtualFile
is an alternative for classpath. Either you find a file from classpath, or from VirtualFile
.
So my suggestion is:
- It's generally a good idea to find resources from classpath, but
- Let's try to find them from two sources: classpath and
VirtualFile
.
2.1. I mean, method for searching in classpath should be outside ofVirtualFile
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, and we are back to my first comment:
About the solution: as you can see the pattern is the following. Those startup files are resolved against
Play.applicationPath
which defined as the current dir (System.getProperty("user.dir")
) and if doesn't exists I try to resolve them against Classpath.
If they not found on the Classpath I leave the workflow intact - theVirtualFile
'sUnexpectedException
is more descriptive.Could we improve something about this pattern? How about extending
VirtualFile
? One resolves the files againstPlay.applicationPath
the other uses Classpath. 🙂
As I'm just a Java copy-paster and not a developer, I don't have solid thoughts how to achieve this "try to resolve the file first by VirtualFile
then search it on the Classpath" thing.
How about extracting VirtualFile
's methods of read-only functionality (as I don't want to write files on the classpath) to an interface and create an AbstractFileResolver
which resolves to VirtualFile
or ClasspathFile
? 😀 Or just create a parent class for VirtualFile
and the other class?
Sure there are other and better solution to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was thinking something similar.
But maybe it's even more simpler. Currently you only need to find one file (e.g. conf/routes
) - either from classpath or from VirtualFile.
Maybe we could just add a static method to VirtualFile
? Say, find
:
public static URL routes;
...
routes = appRoot.find("conf/routes");
class VirtualFile {
public static URL find(String name) {
URL result = // find from classpath
if (result == null) {
result = // find from VirtualFile as previously
}
return result;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! I'll go that way and see what happens!
Thanks for the hint!
5b092aa
to
ac7f441
Compare
ac7f441
to
948c809
Compare
014c7a7
to
5e8cbca
Compare
5e8cbca
to
22bf47b
Compare
@asolntsev, thanks for the hint about introducing Just to note, there is a Would you mind adding some tests?
As I wrote in the first commit, this change doesn't help with files found in
Sure, I don't want to fix it right here, but as an improvement it would be nice to see as fixed once. |
22bf47b
to
b681919
Compare
For example it helps containerizing, as it is able to find files on classpath, not just relative to working directory. While it improves compatibility with files found on classpath, VirtualFile still doesn't support files inside jars, e.g.: Caused by: java.io.FileNotFoundException: file:/app/classpath/my-replay-app.jar!/conf/application.conf (No such file or directory) at java.base/java.io.FileInputStream.open0(Native Method) at java.base/java.io.FileInputStream.open(FileInputStream.java:219) at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157) at play.vfs.VirtualFile.inputstream(VirtualFile.java:106) ... 8 more
…-framework#198) in case they don't exists in the working directory. Running RePlay apps in a distributed form (zip, tar, docker) the conf/ directory doesn't always exists in the working directory, but in the classpath. Fixes: replay-framework#198
b681919
to
3389a45
Compare
@xabolcs Hi. I finally looked at this PR with fresh eyes, and realised that RePlay replaced this mechanism with old good Gradle/Maven dependencies. Replay doesn't create So we can just replace all usages of I can prepare a pull request. |
🤔 Interesting news, but cleaning up the things is always better!
That would be nice! Thanks! Wouldn't be it a big boom to nuke th |
This would help on #64 a little bit. 👌 |
Closing in favor of #291. |
in case they don't exists in the working directory.
Running RePlay apps in a distributed form (zip, tar, docker) the
conf/
directory doesn't always exists in the working directory, but in the classpath.Fixes: #198