3

I've got a (working) JSF app. Now i want a document that is not a page resource (let's say a plain text document) to be expanded using the JSF expression language (as i need state from my beans and this seems "natural"). But it seems i don't get completely the mechanics...

In order to work on "*.txt" files if have in web.xml

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping> 
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.txt</url-pattern>
</servlet-mapping>

I add a "plain.txt" resource

<f:view contentType="text/plain" xmlns:f="http://java.sun.com/jsf/core" >

hi #{request.contextPath}/

</f:view>

Requesting

http://myServer/myApp/plain.txt

failed with an endless loop on the server with myfaces 2.1.10. Renaming the resource to "plain.xhtml" and requesting it worked fine.

After updating to myfaces 2.1.17 (same on 2.2.9), serving "plain.txt" worked, too!

The question is: is using templates this way "best practice" or "accidental side effect" (and should not really work)? Is there a better way to implement such a templating task?

EDIT

After some more attempts it seems even more odd. Serving the expanded content seems to fail at random (both 2.1.17 and 2.2.9). After restarting i get the "loop" on the server side for one resource "res1.txt", but not for an exact copy of the resource "res2.txt". It also happened that "res1.txt" was rendered succesfully. Maybe the server traces can give some hint:

First, there's a very long "recursion"

Mär 09, 2016 5:06:20 PM org.apache.catalina.core.ApplicationDispatcher invoke
SCHWERWIEGEND: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
    at org.apache.myfaces.shared.context.flash.FlashImpl.isKeepMessages(FlashImpl.java:388)
    at org.apache.myfaces.shared.context.flash.FlashImpl._saveMessages(FlashImpl.java:668)
    at org.apache.myfaces.shared.context.flash.FlashImpl.doPostPhaseActions(FlashImpl.java:269)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:254)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
    at org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:369)
    at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:99)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:78)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

This trace is repeated and get shorter each time until it comes eventually to this end:

Mär 09, 2016 5:06:20 PM org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet [Faces Servlet] in context with path [/cloudsuite-snippets] threw exception
java.lang.NullPointerException
    at org.apache.myfaces.shared.context.flash.FlashImpl.isKeepMessages(FlashImpl.java:388)
    at org.apache.myfaces.shared.context.flash.FlashImpl._saveMessages(FlashImpl.java:668)
    at org.apache.myfaces.shared.context.flash.FlashImpl.doPostPhaseActions(FlashImpl.java:269)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:254)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

The browser page is simply white..

EDIT II

And another information: The failure is not really indeterministic (which would have damaged my faith a little bit ...) but nonetheless strange. Rendering succeeded for all resources where i had a resource with the same name, but the ending ".xhtml".

The server seems to redirect internally to the ".xhtml" version, render the content of this one and return it with the name of the ".txt" version (ignoring the content of the latter). What's going on here?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
mtraut
  • 4,522
  • 3
  • 22
  • 32

2 Answers2

3

The question is: is using templates this way "best practice" or "accidental side effect" (and should not really work)?

It should not really work. JSF as being a HTML form based MVC framework doesn't support text/plain content in first place, but only HTML based ones such as text/html. When trying your use case on Mojarra instead of MyFaces (after having renamed plain.txt to plain.xhtml, see later), I get below exception:

java.lang.IllegalArgumentException: Unrecognized Content Type.

As to view resolving, technically you should have named your plain.txt file as plain.xhtml and only have added *.txt URL pattern to FacesServlet. The FacesServlet namely locates the physical view after remapping any file extension in URL pattern against javax.faces.DEFAULT_SUFFIX context parameter which defaults to .xhtml. When the physical file is absent, JSF will fall back from Facelets views to JSP views (which is confirmed by presence of JspViewDeclarationLanguage in stack trace) but as plain.jsp also doesn't exist and the URL still matches the FacesServlet mapping this in turn runs in an infinite loop in a fruitless attempt to find and render the physical resource.

For an elaborate explanation of the inner workings of JSF view resolving, see also JSF Facelets: Sometimes I see the URL is .jsf and sometimes .xhtml. Why? As to the infinite loop on dispatch(), this is in turn technically a bug in JSF as it should really have returned a 404 instead.


Is there a better way to implement such a templating task?

If the sole purpose is evaluating EL expressions, then better use JSP servlet instead of the JSF servlet and exclusively use read-only EL expressions ${} instead of writable EL expressions #{} because this isn't supported by JSP.

The simplest way is to change the servlet name to be the one of Tomcat's own JSP servlet: jsp (a <servlet> entry is not necessary as Tomcat has already definied it in its own /conf/web.xml).

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.txt</url-pattern>
</servlet-mapping>

Then alter the /plain.txt as a JSP view as below. Note that ${request} doesn't exist in JSP, it's only available as property of ${pageContext}. See also our EL wiki page.

<%@page contentType="text/plain" %>

hi ${pageContext.request.contextPath}/

As to resolving managed beans, it only doesn't discover JSF @ManagedBean, but it can discover CDI @Named. So when you install CDI on Tomcat and rework the managed beans of interest to be CDI managed beans instead of JSF managed beans, then they will be available.

A different alternative which requires a little bit more work but is guaranteed portable across servletcontainers (because the servlet name of jsp is Tomcat specific although almost all servletcontainers have the same "de facto" name) is using a plain vanilla servlet or perhaps even a JAX-RS (RESTful) resource for the task you had in mind. Map it to the desired URL pattern of /plain.txt, let it prepare the desired models and finally forward to a "real" JSP file the usual way.

@WebServlet("/plain.txt")
public class PlainTxtServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("/WEB-INF/plain.jsp").forward(request, response);
    }

}

And have a /WEB-INF/plain.jsp as physical file, still with the abovementioned JSP syntax. Note that it's placed inside /WEB-INF as you don't want the enduser to be able to directly request /plain.jsp instead of /plain.txt.

Additional advantage is that this doesn't necessarily require CDI for managing beans as you can manually manage beans like below:

Bean bean = new Bean();
request.setAttribute("bean", bean);

It'll be available as ${bean} in EL.

See also:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • As always a sound, in-depth and clear analysis. I appreciate you and your invaluable contributions at this site. – mtraut Mar 12 '16 at 10:38
  • To give some clarification: Mapping to extension .txt is part of the hack requested. In the real world we talk about a dynamic .jnlp and in the not so obvious ways different platforms, browsers and security settings launch this file the correct extension upon "downloading" is important. If "squeezing" this quick and dirty into JSF is not correct, i will revert to the clean JaxRS solution. Maybe based on another template engine (freemarker) if i have to code anyway... – mtraut Mar 12 '16 at 10:47
  • I think plain Servlet(+JSP) is best suitable for the job as JAX-RS implies a "web service" API which returns an entity / entities as XML/JSON/CSV/etc, not a "file resource" API on a file where you solely need access to EL context. – BalusC Mar 12 '16 at 11:11
  • I will think about this... This is a twilight zone, where complex documents like PDF would most probably be served using a service. So why not a "simple" document, as far as it is not part of the control flow of the webapp itself, but a technical artifact in a loosely related process. – mtraut Mar 12 '16 at 11:26
  • I can imagine the need for EL context in character based content (HTML/CSS/JS/TXT/etc), but PDF? Perhaps this is helpful: http://stackoverflow.com/q/9391838 and http://stackoverflow.com/q/13015410 – BalusC Mar 12 '16 at 13:11
  • EL context can be pushed into JasperReports and then we go.. Thx again for the tips in the links. – mtraut Mar 12 '16 at 16:44
0

I am not quite sure what is going on there but here is how I did it...

Leave your web.xml file as you already have it.

create xhtm file like plain.xhtml like so...

<ui:composition
    xmlns:ui="http://java.sun.com/jsf/facelets">
    hi #{request.contextPath}/
</ui:composition>

now go to .../plain.txt

it should work just fine

Teddy
  • 154
  • 3
  • 15
  • This produces the wrong content type header in response. OP explicitly wanted `text/plain`. – BalusC Mar 12 '16 at 10:24
  • you could listen to preRenderView event, like... then FacesContext fc = FacesContext.getCurrentInstance(); ExternalContext ec = fc.getExternalContext(); Map params = ec.getRequestParameterMap(); ec.setResponseContentType("text/plain"); ec.getResponseOutputWriter().write("Some text content"); //or read from file like... String y = ec.getRealPath(((HttpServletRequest) ec.getRequest()).getRequestUrl()); fc.responseComplete(); But I guess that a lot of work – Teddy Mar 12 '16 at 12:24