Reading a file from within App Engine module - java

I am trying to read a static file from within App Engine module that is placed inside WEB-INF directory.
...
File file = new File("WEB-INF/somestaticfile.ext);
...
It perfectly works in cloud environment, however, in development server it ends up with FileNotFoundException.
I build and run the app with the aid of maven and it seems that it is also needed to prepend a directory representing the module inside the project's EAR hierarchy so that the file would be found.
...
File file = new File("modulename.war/WEB-INF/somestaticfile.ext);
...
This works in local development server but not in cloud environment.
I believe that there is a way how to read a file that would work in both cloud and local environment. Any advice would be appreciated.

I have spent some time to figure it out and here are solutions I have found. If you have your resources placed on classpath then you can access them as follows from both cloud and local dev server.
getClass().getClassLoader().getResource("resourceName");
or
getClass().getClassLoader().getResourceAsStream("resourceName");
However, if your resources are place somewhere else (e.g. WEB-INF), the only way I have found is by means of javax.servlet.ServletContext#getResource(String) or javax.servlet.ServletContext#getResourceAsStream(String) that also work in both environments. This solution is perfectly OK if you access resources from web layer of your app but if you need to access them from other layers (e.g. service layer), it is not probably a good idea to introduce a dependency to Java Servlet API to that layer.
Since I am using Spring, I decided to load resources via org.springframework.core.io.ResourceLoader#getResource(String) that returns a resource abstraction whose concrete implementation depends on the application context type and a resource path prefix. For applications running in a web container, the actual implementation uses ServletContext methods under the hood but you are shielded from it.
If you do not use Spring, it should not be a big deal to implement your own resource abstraction based on ServletContext.
If anyone could provide other solutions, feel free to do so.

An excellent resource, as always, are the Google developer documents:
https://developers.google.com/appengine/docs/java/config/appconfig
That said, to help others in future, I will summarize some relevant points that I think generally relate to the question (since I can't see what is happening your specific environment).
App Engine serves static files from dedicated servers and caches that are separate from the application servers. Files that are accessible by the application code using the file system are called resource files. These files are stored on the application servers with the app.
By default, all files in the WAR are treated as both static files and resource files, except for JSP files, which are compiled into servlet classes and mapped to URL paths, and files in the WEB-INF/ directory, which are never served as static files and always available to the app as resource files. You can adjust which files are considered static files and which are considered resource files using elements in the appengine-web.xml file. The element specifies patterns that match file paths to include and exclude from the list of static files, overriding or amending the default behavior. Similarly, the element specifies which files are considered resource files.
You mentioned that there seemed to be a disconnect between the development server and deployment. Without diving into Maven, my first thought was to look at path patterns. As they note on the Google Developers documentation, path patterns are specified using zero or more and elements. In a pattern, * represents zero or more of any character in a file or directory name, and ** represents zero or more directories in a path. Files and directories matching patterns will not be uploaded when you deploy your app to App Engine. However, these files and directories will still be accessible to your application when running on the local Development Server. An element overrides the default behavior of including all files. An element applies after all patterns (as well as the default if no explicit is provided).
Hope that helps provide a general perspective. If you find a specific solution to the issue and can share it here, please do!

Related

On Android, how are the multiple results of Class.getResources() handled?

In Java VM, a classloader can have multiple domains, generally JAR files (which are similar to APK files). Each of these domains have a single namespace. That is, every resource has a unique name.
Calling ClassLoader.getResources("foo") can, therefore, return multiple URLs. However, looking at Android, the build seems to flatten the resource namespace, overwriting resources with the same path. This wreaks havoc with mechanisms like the Java ServiceLoader. It also seems to void any use of the META-INF/MANIFEST.MF.
For example, if I use liba.jar and libb.jar, and both have a resource OSGI-OPT/com.example.Foo, then only one seems to end up in the APK.
Are the rules around these class resources documented somewhere?
Are the rules around these class resources documented somewhere?
The Android build behavior when creating APKs is described in the Add app resources section of the user guide. Look for the heading on Resource merging.
You are correct that all of the sources are combined into a single namespace. The idea is that resource merging makes the resulting APK smaller1.
Android is not constrained to be Java(tm) compliant, and they have made different design decisions.
1 - An APK is just like a fat JAR or uberJAR in the classic Java world. You would not expect multiple copies of a resource in a fat JAR. The getResources API would only give you a single resource for any name in that context as well.

Can a JAR shared by two web applications log to the same file in Tomcat?

Let's say we have two web applications and a Tomcat instance loading shared JARs (depedencies for both applications) from an external directory (via the means of shared.loader defined in catalina.properties). Therefore, these dependencies are not packaged into the WAR files.
Let's also say that:
Both web applications depend on a particular shared JAR file, which uses a logging framework (log4j2 at the moment but that's not required).
Both web applications use a logging framework of their own (we don't care whether they are identical or not, as long as things work as expected), and different logging configurations.
What we would like to achieve is for the shared JAR to reliably log to the same file, regardless of which web application its methods are called. To our understanding, both web applications have different logging contexts and having two such contexts log to the same file is either not possible or at least dangerous. If that's not true or doesn't have to be true, please elaborate.
The question: is it possible to achieve the above scenario with a single logging context? If so, could you please provide an example to make it working (the crucial bits will perfectly suffice), using lo4j2 or logback? Are there any catches?
Please note that we would like to avoid setting up a special servlet in one of the web applications for this (so the other web application would call it instead of logging directly to a file). Using (e.g.) syslog instead might be a solution perhaps but still, let's keep this question focused on the described scenario please.
After some research, trial and error, we managed to satisfy our requirements:
Each web application logs to its own files.
The shared JAR always logs to its own file too.
At least with Log4j2, the problem appears to revolve around class loaders. In our case, classes from the shared JAR file, and all of its dependencies, were always loaded using a class loader dedicated to (shared.loader). This means that Log4j2's JAR files need to be there beside the shared JAR file and if we tried to remove them, we would see ClassNotFoundExceptions.
Now, we can move to the web applications:
If a web application DOESN'T package Log4j2 for its own use, its loggers are also loaded using the class loader for shared.loader (as a fallback), and the web application's logging configuration overwrites the configuration applied previously (in our case, we had to call explicit initialization or reconfiguration, so that's why). It wouldn't work as expected.
If a web application DOES package Log4j2 for its own use, its loggers are loaded using the class loader for the web application (since dependencies packaged within WEB-INF take precedence), which is a completely different 'context' (class loader) than in approach #1, and the web application's logging configuration does NOT overwrite previously applied configurations (since the shared JAR and all web applications have their own 'context').
That is the behaviour we observed. During approach #1, each web application overwrote logging configuration for the applications initialized/started previously, because the Log4j2 'context' (class loader) was shared. During approach #2, the shared JAR's Log4j2 context was initialized by the web application that called its initialization (only one of them), and the configuration was not touched ever since. In our case, the configuration file was provided by the web application (it was not packaged within the shared JAR). Note that in practice, one of the web applications will always have to initialize the shared JAR, either implicitly or explicitly.
For absolute certainty, we listed open file descriptors to the shared JAR's log files and with approach #2, there was indeed only one. With approach #2, there can still be multiple descriptors open if some of the web applications' configuration files also reference the shared JAR's log files (configuration duplicity). That is precisely the sort of situation you'd normally want to avoid.
Pitfalls that we discovered:
Notice that the shared JAR's Log4j2 context was initialized by the web application that called its initialization (only one of them) remark is a bit tedious. Unless we copy or include the shared JAR's configuration within configuration of each web application (and for the above stated reasons, we want to avoid that), some of the logging messages may end up elsewhere or get lost during servlet container's start. In general, it may not be possible to guarantee the order in which web applications are started. I may be wrong but from what I saw in Tomcat logs, Tomcat starts the web applications (WAR files) in alphabetic order.
If the shared JAR and any of the web applications happen to share some more dependencies (beside the logging framework), these dependencies must, also, be placed within shared.loader. But, if the shared JAR's logging configuration redirects logging messages of any of those dependencies into its own logs, they can not end up in the web application's logs, unless that dependency is also packaged within the web application (same principle as approach #2 above). But in practice, separation of logging API and backing implementations makes this difficult. For example, you can read here on StackOverflow that selection of SLF4J bindings is rather "random" (JVM-dependent). If you put different bindings to shared.loader and into one of the web application's WEB-INF folder, you may not have certainly about which binding is going to get selected.
I certainly can not recommend the scenario we are trying to achieve but the described "solution" definitely works as expected (despite the pitfalls).

Accessing WAR-packaged classpath resources from within Spring container on Weblogic 9.x

Inside web application I use some Spring scheduled-tasks (so managed standalone by Spring container). These tasks execute some business logic and require access to StringTemplate resources, which after deployment are located in WEB-INF/classes. I provide their directory as String (i.e. "some/templates") which works fine when working in exploded mode, but after switching to WAR-packaging, these resources cannot be found by ST. Project's page suggest using URL/URI (the "quagmire"), but that's a bit unclear to me. Other resources work properly, the only problem is the STGroupDir constructor.
How should I construct URL/URI/Paths arguments so that these resources could be accessed by WAR-packaged Spring-managed scheduled-tasks?
It appeared to be an issue with Weblogic 9.x creating an internal _wl_cls_gen.jar within the packaged WAR, containing all the classpath (i.e. WEB-INF/classes) resources. This results in problems with many frameworks that rely on getResource(path) methods (such as the ClassLoader one). Because of that StringTemplate could not access the group files. I fixed the problem by moving the templates out of the classpath and to WEB-INF location, then injecting the path as URL for StringTemplate to use.
I found some further information regarding this issue here and here.

EJB 1.1 and disk io

I have a question about EJB 1.1 (yes really that old ... - please dont kid me...)
So the question is one of the old ones: Why should I not do disk io within EJBs? Especially reading files.
To be more precise the use case: Its all about one file that is needed as a template for some special data export.
So it is:
one file
very rarely changed (for example within a special maintanance time)
rarely read
no heavy load
Is there any reason, why not to read that template file from disk?
Are there any technical restrictions like an ForbiddenOperationException when I try to do disk io within an EJB. I already run a test and reading and transferring is working just fine. Is that behaviour different within EJB 2.x or 3.x?
Thanks a lot!
This restriction is in the specification to allow for clustering of EJBs, which is easier if the EJB is self-contained and does not rely on the outside environment such as the file system.
Accessing the file system should work fine however, if you truly want to comply with the spec you could bundle the file inside the EJB jar and access it from the classpath using Class.getResourceAsStream.
From EJB Restrictions :
Enterprise beans aren't allowed to access files primarily because
files are not transactional resources. Allowing EJBs to access files
or directories in the filesystem, or to use file descriptors, would
compromise component distributability, and would be a security hazard.
You can pack file in a JAR so that you can read it with getResource() or getResourceAsStream() & can change, redeploy independently.
Else, if you haven't encountered any issues with your current approach, then its fine, but isn't recommended in accordance with the specification.
Why not store it in database as a blob?
then you can have an admin webapp to change it from browser
and you can use ldap to authenticate/authorize the webapp
oops, sorry for making life so complicated

Relative views in view-states within a flow that is loaded from a jar-file

I have a question regarding Spring Web Flow with JSF: How can I teach Spring Web Flow to be able to load relative views like view="pages/view.xhtml" from a jar in the classpath of a tomcat webapp? After some research via google I think, that Web Flow does not support this constellation out of the box.
Maybe some context, to help understanding my question:
- Flows are registered in multiple FlowRegistries (I solved this problem by implementing a custom implementation, which finds all flowRegistries in the Spring Context)
- Flows can reside either as file resource outside the classpath or within a jar in the classpath, i.e. file ressource flows are located somewhere in WEB-INF/conf and they are at the same position within the jar files.
- Views in the flow definitions are adressed relatively to the flow-definition-file
Now you might ask the question why we have both constellations, where the flows can reside. At the moment we are trying to extract from a big bunch of a webapp modules that contain all functionality belonging to a certain domain. The approach is to bundle all artifacts relevant there within a single project that can be built as jar and added to the webapp then.
While it is no problem to load the Spring beans for each jar without knowing where our configuration files are located, the Web Flow causes some problems.
The first problem was, that the flowRegistry is a monolith that cannot be split without doing something before hand. This problem is solved by a custom flow registry.
But now I came to a second problem: Within view states we reference the pages relatively to the flow definition, like described in the documentation:
<view-state id="some-id" view="pages/somepage.xhtml"> ... </view-state>
Now, when I enter such a view state, web flow throws an exception, which tells me that this way is not supported:
A ContextResource is required to get relative view paths within this context;
the resource was ...
Googling around brought up this possible solution:
workaround for webflows in jars
But this workaround is not working as it has a problem with my multiple flow registries.
Another option might be to not put everything into the jar, but I am not sure if that is a better idea. Likely have everything that can be loaded from classpath in the jar and the rest as pure files in a defined structure.
Any ideas? Thank you very much for your efforts and hints.
I found a slight different solution by myself after several hours of trying and debugging my application on how to accomplish the goal of the question.
first thing to change was to advance from Tomcat 6 to Tomcat 7 because of a change in the servlet API spec, that enabled me to solve my problem with slight modifications
I switched from relative referencing in view states to absolute addressing
I changed the directory structure of my jar file to fit to the newer servlet API: all file resources needed for JSF or Spring Webflow needed to be placed in META-INF/resources (see Javadoc of ServletContext look for the method getResource, it specifies what I needed)
These three steps enabled me to completely pack webflows and their resources in jar-files.

Categories