ExternalContext#getResourceAsStream() returns null, where to place the resource file? - jsf

I'm trying to obtain a PNG file as InputStream in my managed bean as below:
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
InputStream input = externalContext.getResourceAsStream("/myFile.png");
// input is null.
However, the InputStream is always null. How is this caused and how can I solve it?

Apparently you placed the resource in physically the wrong location.
The ExternalContext#getResourceAsStream(), which delegates in case of servlet containers under the covers to ServletContext#getResoruceAsStream(), has its root in the web content of the WAR (the parent folder of /WEB-INF and /META-INF folders, thus the files therein are also available this way), and the /META-INF/resources folder of all JARs in /WEB-INF/lib. In case of a JSF web application it are usually XHTML, CSS, JavaScript and image files.
In other words, it returns web resources. It doesn't return a disk file system resource, for that you need new FileInputStream() instead. It also doesn't return a classpath resource, for that you need ClassLoader#getResourceAsStream() instead. The classpath has its root in a.o. /WEB-INF/classes, all JARs in /WEB-INF/lib, and some VM/server-configured folders depending on the runtime environment.
In an usual web content file structure, the resource file has to be placed exactly here in order to obtain it the desired way:
WebContent
|-- META-INF
|-- WEB-INF
| |-- faces-config.xml
| `-- web.xml
|-- myFile.png <-- Here.
:
getResourceAsStream() vs FileInputStream
Accessing properties file in a JSF application programmatically
Where to place and how to read configuration resource files in servlet based application?
How to get the root path of a web project in java EE

Related

Issue with h:form - Returning 404 when submitting through h:commandbutton

I am working on a JSF (2.2) application. I am seeing some weird behavior working with h:form and h:commandbutton.
Issue - I have following code in say searchRecord.xhtml -
<h:form>
<!-- Input fields -->
<h:commandbutton type="submit" value="Search" title="Search" action="#{bean.search}"/>
</h:form>
The issue I am facing is when I click on submit button, it shows 404-page not found with URL pointing to current page. It is not executing the specified bean action.
I tried to debug this. When the form is getting translated into HTML, the form is getting generated with method="post" action="/MyApplication/WEB-INF/searchRecord.xhtml" (which looks to be the correct behaviour). Still, on clicking the button, I am getting 404.
Can anyone please help me figuring out what is the issue? I wasted my weekend figuring this out but in vain.
EDIT -
IDE - Eclipse
JSF Version - Mojarra 2.2.8
Directory structure of my project is -
Project
- Java Resource
----src -> contains java files
- WebContent
---- META-INF
---- WEB-INF
------facelets -> contains *.xhtml files
------resources -> contains img, css and JS files in respective folders
------commonLayout.xhtml
- index.xhtml
I access my application using a launchHandler servlet which validates the request parameters and forward to searchRecord.xhtml.
I am able to see searchRecord.xhtml. but Now when I click , I am getting 404.
As a standard, we are required to use servlet and then forward accordingly.
I found solution for my problem. The issue here was the wrong directory structure (Somehow I missed the point that resources under /WEB-INF are not reachable by URL. Thanks to #BalusC for pointing this out!!!). Based on the answers on below post -
JSF files inside WEB-INF directory, how do I access them?
Which XHTML files do I need to put in /WEB-INF and which not?
I restructured my projects as follows -
My Application
|- Java Resource
|----src -> contains java files
|- WebContent
|---- META-INF
|---- Resources -> contains img, css and JS files in respective folders
|---- JSF
| |--Contains client .xhtml files
|---- WEB-INF
| |--template -> contains the master templates for my application
| |--web.xml
|---- index.xhtml
Now the navigation is happening as expected and all the pages are displayed.
I am also planning to use JSF 2.2 configuration parameter and put resources under WEB-INF.

Access from internet the web.xml file of an applicaiton

Is it possible for someone to access or view the web.xml file of a web application over internet, using somthing like wget tool? I'm asking for saecurity reasons like username
By specification, it is not possible to directly access /WEB-INF (and /META-INF) contents by a public URL. Here are extracts of relevance from the aforelinked specification:
10.5 Directory structure
...
Also, except
for the case where static resources are packaged in JAR files, any requests from the
client to access the resources in WEB-INF/ directory must be returned with a
SC_NOT_FOUND(404) response.
10.6 Web Application Archive File
...
Also, any requests to access the resources in META-INF
directory must be returned with a SC_NOT_FOUND(404) response.
However, there have been implementations, configurations and even homegrown servlets or filters which introduced a security bug making this possible. All those security issues boil down to be caused by a RequestDispatcher#forward() or even RequestDispatcher#include() (so watch out with dynamic <jsp:include>!) call forwarding or including a resource which is specified by a client-controlled request path or parameter, if necessary making use of path traversal with ../.
Here's the simplest example of such a servlet exposing the security issue:
#WebServlet("/test/*")
public class TestServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher(request.getPathInfo()).forward(request, response);
}
}
On Tomcat (tested with 8.0.21), you can with the above servlet get the web.xml contents by just calling http://localhost:8080/context/test/WEB-INF/web.xml. Such a servlet is often implemented as part of homegrown MVC front controller or dispatcher pattern. Decent MVC frameworks like JSF and Spring MVC shouldn't have this issue.
And, some users configure a MVC front controller on a "catch-all" URL pattern of /* or even /, and then re-map the static resources like CSS/JS/images on /static/* to container's default servlet like so:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
On older Tomcat versions (before 7.0.4), the enduser can get /WEB-INF (and /META-INF) contents through such a mapping. This problem was mentioned previously in this Q&A: Tomcat serving static content. Actually, this mapping approach is wrong and should have been solved with help of a filter as descibed in this answer: How to access static resources when mapping a global front controller servlet on /*. See also Tomcat issue 50026.
Summarized: by default it's not possible. But (bad) code and configuration can make this possible.

Deploying backing bean with composite component in separate jar

I have some difficulties deploying my web app on JBoss AS 6.1. My current Project is separated into the main web app (controller/managed beans & web frontend using JSF 2 facelets) and one jar with the composite components + backing beans. But when I try to access the page I got an error that the specified component type could not be instantiated.
Copying the backing bean into the main web app solves the problem, but this isn't what I want. So is there anything to pay attention to?
The backing bean looks like
#FacesComponent(value = "elementBase")
public class ElementBase extends UINamingContainer {
...
}
and the composite components interface
<composite:interface componentType="elementBase">
... some attributes
</composite:interface>
The structure of the jar is the following
-- META-INF
|-- resources
| |-- components
| |-- elementBase.xhtml
-- com
|-- example
| |-- ElementBase.class
I've also tried to add faces-config.xml within META-INF folder, with the component type, but the component type was still not found.
Through the BalusC's answer to the question JEE6> Packaging JSF facelets (xhtml) and ManagedBeans as JAR
As to the managed beans and other JSF classes like validators, converters, etc, just annotate them with #ManagedBean, #FacesValidator, #FacesConverter, etc and package them in the JAR the usual way. You only need to provide a JSF 2.0 compatible /META-INF/faces-config.xml file in the JAR.
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
</faces-config>
This way JSF will be triggered to scan the classes in the JAR for JSF specific annotations. Alternatively you can also just register them in the JAR's faces-config.xml the JSF 1.x way.
and Java EE6 Tutorial: Application Configuration Resource File
You can have more than one application configuration resource file for an application. The JavaServer Faces implementation finds the configuration file or files by looking for the following:
A resource named /META-INF/faces-config.xml in any of the JAR files in the web application’s /WEB-INF/lib/ directory and in parent class loaders. If a resource with this name exists, it is loaded as a configuration resource. This method is practical for a packaged library containing some components and renderers. In addition, any file with a name that ends in faces-config.xml is also considered a configuration resource and is loaded as such.
A context initialization parameter, javax.faces.application.CONFIG_FILES, in your web deployment descriptor file that specifies one or more (comma-delimited) paths to multiple configuration files for your web application. This method is most often used for enterprise-scale applications that delegate to separate groups the responsibility for maintaining the file for each portion of a big application.
A resource named faces-config.xml in the /WEB-INF/ directory of your application. Simple web applications make their configuration files available in this way.
.. I could fix my problem.
Step by step solution
Create backing bean
#FacesComponent(value = "elementBase")
public class ElementBase extends UINamingContainer {
...
}
and a composite components with the following interface
<composite:interface componentType="elementBase">
... some attributes, value holder, ..
</composite:interface>
provide a faces-config.xml within the deployed jar, to indicate that the jar contains annotated classes. The structure of the deployed jar should look like
-- META-INF
|-- resources
| |-- components
| |-- elementBase.xhtml
|-- faces-config.xml
-- com
|-- example
| |-- ElementBase.class
deploy the jar within the /WEB-INF/lib folder of the web application.
Research/Related links and topics
JEE6> Packaging JSF facelets (xhtml) and ManagedBeans as JAR
Java EE6 Tutorial: Application Configuration Resource File
JSF facelets template packaging
How to create a modular JSF 2.0 application?

Can the index.xhtml be stored in an external JAR file? What would be its URL?

I'd like to have all the facelets and managed bean into one external jar, but if I put de index.xhtml there I don't konw how to reference it.
If the jar structure is:
IndexManagedBean.class
META-INF/
resources/
pages/
index.xhtml
What is its URL?
Assuming that the JAR is placed in webapp's /WEB-INF/lib folder and that you're using JSF 2.x and that webapp's context path is /contextpath, and the FacesServlet is mapped on an URL pattern of *.xhtml then you can reference it by the following URL:
http://example.com/contextpath/pages/index.xhtml
See also
Structure for multiple JSF projects with shared code

How to get an image or js from a JAR in the server in JSF (For a custom component)

I have done a custom JSF component (it looks like a combobox (icefaces selectonemenu)) but it uses a couple of images (png) and a bit of javascript.
I jar everything, so then the developers use it as a jar copied in the web-inf/lib folder.
The image and the js are just for this custom component, so I can't make them put this image and js in his project, it has to be in MY jar.
I jar everything and it works almost great, just the image and the JS, I do not get them to work. I do not know how to reference them being in the jar. I could make them work as long as they are part of the application, but not being part of the jar.
How should I do to get them in my encodebegin code for example?
I am using JSF with icefaces 1.8
Thanks in advance!!
If you're already on JSF 2.0, it should work just fine out the box when you're using #ResourceDependency or #ResourceDependencies annotation which can resolve resources based on JAR's /META-INF/resources folder.
On JSF 1.x, your best bet is to create a custom "resource servlet" which is mapped on a certain URL pattern, e.g. /com.nahiko.resources/* and just streams the resources from the classpath to the HTTP response. Basic kickoff example:
String path = "/META-INF/resources" + request.getPathInfo();
InputStream input = getClass().getResourceAsStream(path);
OutputStream output = response.getOutputStream();
// ...
Document along your JAR that this servlet has to be mapped. Or if you target a Servlet 3.0 container, just add the #WebServlet annotation to get it to auto-register.

Resources