Get rid of .xhtml extension [duplicate] - spring

I have Login.xhtml and Home.xhtml. I configured the url pattern in web.xml as follows
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>Login.xhtml</welcome-file>
</welcome-file-list>
When I run the whole project, the login page URL is like this http://localhost:8080/fran/Login.xhtml , here fran is my project name..
However, I would like it to be http://localhost:8080/fran/Login/ instead of http://localhost:8080/fran/Login.xhtml.
How can I achieve this? Is it possible to customize the <url-pattern> for every page to get rid of the .xhtml extension?

If your sole reason is to get rid of the .xhtml extension, then there are various ways depending on the JSF version you're using.
JSF 2.3+
JSF 2.3 offers a new API to collect all views: the ViewHandler#getViews(). Combine this with ServletRegistration#addMapping() in a ServletContextListener as below.
#FacesConfig
#WebListener
public class ApplicationConfig implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
addExtensionLessMappings(event.getServletContext(), FacesContext.getCurrentInstance());
}
private void addExtensionLessMappings(ServletContext servletContext, FacesContext facesContext) {
servletContext
.getServletRegistrations().values().stream()
.filter(servlet -> servlet.getClassName().equals(FacesServlet.class.getName()))
.findAny()
.ifPresent(facesServlet -> facesContext
.getApplication()
.getViewHandler()
.getViews(facesContext, "/", ViewVisitOption.RETURN_AS_MINIMAL_IMPLICIT_OUTCOME)
.forEach(view -> facesServlet.addMapping(view))
);
}
}
Effectively, this is an oneliner. Source: Arjan Tijms' Blog and The Definitive Guide to JSF.
If you're using MyFaces as JSF 2.3 implementation, then this can be transparently activated by solely the following web.xml context parameter:
<context-param>
<param-name>org.apache.myfaces.AUTOMATIC_EXTENSIONLESS_MAPPING</param-name>
<param-value>true</param-value>
</context-param>
Mojarra does not have an equivalent yet.
JSF 2.2-
Use OmniFaces FacesViews. It offers a zero-configuration way to achieve that by placing the view files in /WEB-INF/faces-views/ folder. Otherwise, if you intend to not modify your project structure and want to keep your view files at the usual place and still benefit of extensionless URLs, then it's a matter of adding the following context parameter:
<context-param>
<param-name>org.omnifaces.FACES_VIEWS_SCAN_PATHS</param-name>
<param-value>/*.xhtml</param-value>
</context-param>
In case you don't want to use OmniFaces, but rather want to homegrow your own, just look at source code of OmniFaces. It's open source under Apache 2.0 License. It's only not an oneliner.

Take a look at prettyfaces: Pretty URLs for JavaServer Faces ,
Look at the 2. Create pretty-config.xml example in the main page
And take a look at the Chapter 2. Get Started

Just a little complement to mr. #balusc excelent answer about MyFaces on JSF 2.3... (Edit: not really a complement as one can not complement what's complete, but just a workaround for tomcat/tomee users to deal with this tomcat bug).
Using MyFaces 2.3.6, I received a Exception talking about servlet specification and ServletContextListener:
java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with #WebListener
Following the stack i saw this line:
at org.apache.myfaces.webapp.StartupServletContextListener.contextInitialized(StartupServletContextListener.java:103)
And after adding that listener to web.xml all worked fine:
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>

Related

Spring Security tag lib not working with JSF

I want to use springboot with security and primefaces.
I have followed this article but with one little change, I don't want to use JoinFaces. Everything works fine except the spring sec taglib.
xmlns:sec="http://www.springframework.org/security/tags
Now I'm not sure how to configure servletContext so that the sec tags would work.
Here is GitHub repo for now its really simple project just to test the combination SB + SS + PF.
I had the same scenario before and I ended up adding springsecurity.taglib.xml in my project. You can copy the file content from here and then register it in your web.xml file as follow:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
</context-param>

How to configure logback context-param using jHipster?

Fact 1: in this answer it is mentioned that the web.xml file has been replaced by the (generated) WebConfigurer class.
Fact 2: in the logback documentation it is explained that, in order to avoid the logback facility shutting down before the application shutdown is completed, which would cause loss of logging messages, the web.xml file should be edited by adding the following stanza:
<web-app>
<context-param>
<param-name>logbackDisableServletContainerInitializer</param-name>
<param-value>true</param-value>
</context-param>
</web-app>
Putting it all together, how can I set this configuration parameter while using jHipster?
Bonus question(s): how are the contents of the web.xml file mapped to the WebConfigurer class's contents? Can the WebConfigurer be customized during the generation phase, or should it be edited manually after generation?
As reported in the answer to this question, the web.xml file can be found (and edited) in the "src/main/webapp/WEB-INF" folder, although it is discouraged to use it. However, there does not seem to be another way to operate in this case.

Mapping extension content types in Jersey, not CXF

Quite a while ago, I had worked on a REST service that was implemented using Apache CXF. Earlier this year, I ported it to Jersey, but there is an incompatibility that I didn't notice at the time.
Apache CXF provides a convenient way to do "extension mapping". The clients of the original service were written to expect this. We're now discovering that using extensions in the client with the ported service isn't working, because extension mapping isn't configured in the service. After looking around for a while, I see that Jersey doesn't provide an obvious way to do this.
Short of changing the clients to not provide the extension, what are some possible strategies for "fixing" this in the service? I'm fairly certain that there are no clients that will be using XML.
Assuming you're using Jersey 2.x, there actually is a convenient way to handle this. It is with the ServerProperties.MEDIA_TYPE_MAPPINGS property. If you are using a ResourceConfig subclass for your configuration you can just do
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("com.example");
Map<String, MediaType> mappings = new HashMap<>();
mappings.put("json", MediaType.APPLICATION_JSON_TYPE);
mappings.put("xml", MediaType.APPLICATION_XML_TYPE);
property(ServerProperties.MEDIA_TYPE_MAPPINGS, mappings);
}
}
If you are using a web.xml, you can do
<servlet>
<servlet-name>JerseyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.example</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.mediaTypeMappings</param-name>
<param-value>xml:application/xml, json:application/json</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

p:fileUpload always return null file and Listener method is never invoked [duplicate]

I'm trying to upload a file using PrimeFaces, but the fileUploadListener method isn't being invoked after the upload finishes.
Here is the view:
<h:form>
<p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload}"
mode="advanced"
update="messages"
sizeLimit="100000"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
<p:growl id="messages" showDetail="true"/>
</h:form>
And the bean:
#ManagedBean
#RequestScoped
public class FileUploadController {
public void handleFileUpload(FileUploadEvent event) {
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
I've placed a breakpoint on the method, but it's never called. When using mode="simple" and ajax="false", it is been invoked, but I want it to work in the advanced mode. I'm using Netbeans and Glassfish 3.1.
How to configure and troubleshoot <p:fileUpload> depends on PrimeFaces and JSF version.
All PrimeFaces versions
The below requirements apply to all PrimeFaces versions:
The enctype attribute of the <h:form> needs to be set to multipart/form-data. When this is absent, the ajax upload may just work, but the general browser behavior is unspecified and dependent on form composition and webbrowser make/version. Just always specify it to be on the safe side.
When using mode="advanced" (i.e. ajax upload, this is the default), then make sure that you've a <h:head> in the (master) template. This will ensure that the necessary JavaScript files are properly included. This is not required for mode="simple" (non-ajax upload), but this would break look'n'feel and functionality of all other PrimeFaces components, so you don't want to miss that anyway.
When using mode="simple" (i.e. non-ajax upload), then ajax must be disabled on any PrimeFaces command buttons/links by ajax="false", and you must use <p:fileUpload value> with <p:commandButton action> instead of <p:fileUpload listener>.
So, if you want (auto) file upload with ajax support (mind the <h:head>!):
<h:form enctype="multipart/form-data">
<p:fileUpload listener="#{bean.upload}" auto="true" /> // For PrimeFaces version older than 8.x this should be fileUploadListener instead of listener.
</h:form>
public void upload(FileUploadEvent event) {
UploadedFile uploadedFile = event.getFile();
String fileName = uploadedFile.getFileName();
String contentType = uploadedFile.getContentType();
byte[] contents = uploadedFile.getContents(); // Or getInputStream()
// ... Save it, now!
}
Or if you want non-ajax file upload:
<h:form enctype="multipart/form-data">
<p:fileUpload mode="simple" value="#{bean.uploadedFile}" />
<p:commandButton value="Upload" action="#{bean.upload}" ajax="false" />
</h:form>
private transient UploadedFile uploadedFile; // +getter+setter
public void upload() {
String fileName = uploadedFile.getFileName();
String contentType = uploadedFile.getContentType();
byte[] contents = uploadedFile.getContents(); // Or getInputStream()
// ... Save it, now!
}
Do note that ajax-related attributes such as auto, allowTypes, update, onstart, oncomplete, etc are ignored in mode="simple". So it's needless to specify them in such case.
Also note that the UploadedFile property is declared transient just to raise awareness that this is absolutely not serializable. The whole thing should be placed in a request scoped bean instead of a view or even session scoped one. If this is the case, then you can safely remove the transient attribute.
Also note that you should immediately read and save the file contents inside the abovementioned methods and not in a different bean method invoked by a later HTTP request. This is because technically speaking the uploaded file contents is request scoped and thus unavailable in a later/different HTTP request. Any attempt to read it in a later request will most likely end up with java.io.FileNotFoundException on the temporary file and only cause confusion.
PrimeFaces 8.x or newer
Configuration is identical to the 5.x version info below, but if your listener is not called, check if the method attribute is called listener and not fileUploadListener like as in versions before 8.x.
PrimeFaces 5.x
This does not require any additional configuration if you're using at least JSF 2.2 and your faces-config.xml is also declared conform at least JSF 2.2 version. You do not need the PrimeFaces file upload filter at all and you also do not need the primefaces.UPLOADER context parameter in web.xml. In case it's unclear to you how to properly install and configure JSF depending on the target server used, head to How to properly install and configure JSF libraries via Maven? and "Installing JSF" section of our JSF wiki page.
If you're however not using JSF 2.2 yet and you can't upgrade JSF 2.0/2.1 to 2.2 yet (should be effortless though when already on a Servlet 3.0 compatible container), then you need to manually register the below PrimeFaces file upload filter in web.xml (it will parse the multi part request and fill the regular request parameter map so that FacesServlet can continue working as usual):
<filter>
<filter-name>primeFacesFileUploadFilter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>primeFacesFileUploadFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
The <servlet-name> value of facesServlet must match exactly the value in the <servlet> entry of the javax.faces.webapp.FacesServlet in the same web.xml. So if it's e.g. Faces Servlet, then you need to edit it accordingly to match.
PrimeFaces 4.x
The same story as PrimeFaces 5.x applies on 4.x as well.
There's only a potential problem in getting the uploaded file content by UploadedFile#getContents(). This will return null when native API is used instead of Apache Commons FileUpload. You need to use UploadedFile#getInputStream() instead. See also How to insert uploaded image from p:fileUpload as BLOB in MySQL?
Another potential problem with native API will manifest is when the upload component is present in a form on which a different "regular" ajax request is fired which does not process the upload component. See also File upload doesn't work with AJAX in PrimeFaces 4.0/JSF 2.2.x - javax.servlet.ServletException: The request content-type is not a multipart/form-data.
Both problems can also be solved by switching to Apache Commons FileUpload. See PrimeFaces 3.x section for detail.
PrimeFaces 3.x
This version does not support JSF 2.2 / Servlet 3.0 native file upload. You need to manually install Apache Commons FileUpload and explicitly register the file upload filter in web.xml.
You need the following libraries:
commons-fileupload.jar
commons-io.jar
Those must be present in the webapp's runtime classpath. When using Maven, make sure they are at least runtime scoped (default scope of compile is also good). When manually carrying around JARs, make sure they end up in /WEB-INF/lib folder.
The file upload filter registration detail can be found in PrimeFaces 5.x section here above. In case you're using PrimeFaces 4+ and you'd like to explicitly use Apache Commons FileUpload instead of JSF 2.2 / Servlet 3.0 native file upload, then you need next to the mentioned libraries and filter also the below context param in web.xml:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value><!-- Allowed values: auto, native and commons. -->
</context-param>
Troubleshooting
In case it still doesn't work, here are another possible causes unrelated to PrimeFaces configuration:
Only if you're using the PrimeFaces file upload filter: There's another Filter in your webapp which runs before the PrimeFaces file upload filter and has already consumed the request body by e.g. calling getParameter(), getParameterMap(), getReader(), etcetera. A request body can be parsed only once. When you call one of those methods before the file upload filter does its job, then the file upload filter will get an empty request body.
To fix this, you'd need to put the <filter-mapping> of the file upload filter before the other filter in web.xml. If the request is not a multipart/form-data request, then the file upload filter will just continue as if nothing happened. If you use filters that are automagically added because they use annotations (e.g. PrettyFaces), you might need to add explicit ordering via web.xml. See How to define servlet filter order of execution using annotations in WAR
Only if you're using the PrimeFaces file upload filter: There's another Filter in your webapp which runs before the PrimeFaces file upload filter and has performed a RequestDispatcher#forward() call. Usually, URL rewrite filters such as PrettyFaces do this. This triggers the FORWARD dispatcher, but filters listen by default on REQUEST dispatcher only.
To fix this, you'd need to either put the PrimeFaces file upload filter before the forwarding filter, or to reconfigure the PrimeFaces file upload filter to listen on FORWARD dispatcher too:
<filter-mapping>
<filter-name>primeFacesFileUploadFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
There's a nested <h:form>. This is illegal in HTML and the browser behavior is unspecified. More than often, the browser won't send the expected data on submit. Make sure that you are not nesting <h:form>. This is completely regardless of the form's enctype. Just do not nest forms at all.
If you're still having problems, well, debug the HTTP traffic. Open the webbrowser's developer toolset (press F12 in Chrome/Firebug23+/IE9+) and check the Net/Network section. If the HTTP part looks fine, then debug the JSF code. Put a breakpoint on FileUploadRenderer#decode() and advance from there.
Saving uploaded file
After you finally got it to work, your next question shall probably be like "How/where do I save the uploaded file?". Well, continue here: How to save uploaded file in JSF.
You are using prettyfaces too? Then set dispatcher to FORWARD:
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
One point I noticed with Primefaces 3.4 and Netbeans 7.2:
Remove the Netbeans auto-filled parameters for function handleFileUpload i.e. (event) otherwise event could be null.
<h:form>
<p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
mode="advanced"
update="messages"
sizeLimit="100000"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
<p:growl id="messages" showDetail="true"/>
</h:form>
Looks like javax.faces.SEPARATOR_CHAR must not be equal to _
Putting p:fileUpload inside a h:form solved the problem at my case.
I had same issue with primefaces 5.3 and I went through all the points described by BalusC with no result. I followed his advice of debugging FileUploadRenderer#decode() and I discovered that my web.xml was unproperly set
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>auto|native|commons</param-value>
</context-param>
The param-value must be 1 of these 3 values but not all of them!! The whole context-param section can be removed and the default will be auto
bean.xhtml
<h:form enctype="multipart/form-data">
<p:outputLabel value="Choose your file" for="submissionFile" />
<p:fileUpload id="submissionFile"
value="#{bean.file}"
fileUploadListener="#{bean.uploadFile}" mode="advanced"
auto="true" dragDropSupport="false" update="messages"
sizeLimit="100000" fileLimit="1" allowTypes="/(\.|\/)(pdf)$/" />
</h:form>
Bean.java
#ManagedBean
#ViewScoped
public class Submission implements Serializable {
private UploadedFile file;
//Gets
//Sets
public void uploadFasta(FileUploadEvent event) throws FileNotFoundException, IOException, InterruptedException {
String content = IOUtils.toString(event.getFile().getInputstream(), "UTF-8");
String filePath = PATH + "resources/submissions/" + nameOfMyFile + ".pdf";
MyFileWriter.writeFile(filePath, content);
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
event.getFile().getFileName() + " is uploaded.", null);
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
web.xml
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
Neither of the suggestions here were helpful for me. So I had to debug primefaces and found the reason of the problem was:
java.lang.IllegalStateException: No multipart config for servlet fileUpload
Then I have added section into my faces servlet in the web.xml. So that has fixed the problem:
<servlet>
<servlet-name>main</servlet-name>
<servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<multipart-config>
<location>/tmp</location>
<max-file-size>20848820</max-file-size>
<max-request-size>418018841</max-request-size>
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
</servlet>
For people using Tomee or Tomcat and can't get it working, try to create context.xml in META-INF and add allowCasualMultipartParsing="true"
<?xml version="1.0" encoding="UTF-8"?>
<Context allowCasualMultipartParsing="true">
<!-- empty or not depending your project -->
</Context>
With JBoss 7.2(Undertow) and PrimeFaces 6.0 org.primefaces.webapp.filter.FileUploadFilter should be removed from web.xml and context param file uploader should be set to native:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>native</param-value>
</context-param>
I had the same issue, due to the fact that I had all the configuration that describe in this post, but in my case was because I had two jQuery imports (one of them was PrimeFaces's bundled jQuery) which caused conflicts to upload files.
Manually adding / loading jQuery with PrimeFaces results in Uncaught TypeErrors

JAX-RS Custom ExceptionMapper not intercept RuntimeException

I want to wrap underlaying RuntimeExceptions to a custom json format , making the servlet container won't dump the stacktrace to client.
I follow this question : JAX-RS (Jersey) custom exception with XML or JSON .
When calling :
try {
doSomething(parameters);
}
catch(RuntimeException e) {
throw new MyCustomException(500 , e.getMessage() , Status.INTERNAL_SERVER_ERROR);
}
When I intentionally feed wrong parameters (and trigger RuntimeException thrown by doSomething() ) , I didn't see MyCustomExceptionMapper working. Instead , the servlet container dumps :
The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
api.MyCustomException: (underlaying msgs)
The MyCustomExceptionMapper is indeed registered in the javax.ws.rs.core.Application :
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> set = new HashSet<Class<?>>();
set.add(other classes);
set.add(MyCustomExceptionMapper.class);
return set;
}
What did I miss ?
Thanks a lot !
Environment : JAX-RS , jersey-server 1.5
classes spec :
class MyCustomException extends RuntimeException
#Provider
class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException>
updated :
I suspect that Application.getClasses() is never called , so I add some println messages :
#Override
public Set<Class<?>> getClasses()
{
System.out.println("\n\n\n\n ApiConfig getClasses");
}
And in deed , it's never shown !
I am sure this ApiConfig is in the web.xml :
<context-param>
<param-name>javax.ws.rs.core.Application</param-name>
<param-value>destiny.web.api.ApiConfig</param-value>
</context-param>
But why it seems Jersey never calls it ?
I found the solution.
All I have to do is annotate MyCustomExceptionMapper with Spring's #Repository.
And remove the section in web.xml (not needed)
<context-param>
<param-name>javax.ws.rs.core.Application</param-name>
<param-value>destiny.web.api.ApiConfig</param-value>
</context-param>
Because Spring will lookup all #Repository and find a #Provider , and Jersey will make use of it.
I think (on the basis of my experiments) that exception providers are looked up by exact class match, rather than by inheritance match, so an exception provider that handles RuntimeException will only fire if the app throws a raw RuntimeException; that's not the case with the class you've showed us. I have some theories about how to fix this (e.g., with a custom filter handler, or possibly some use of AOP) but nothing final yet.
In relation to the second half of your question, I just don't know. What I do know is that Apache CXF (the JAX-RS implementation I've worked with) has/had some failings in this area, and that I thus stick to registering all my #Providers by hand in the app's Spring config. I offer that as experience…
Your web.xml had an incorrect param-name in web.xml so that setting was being ignored.
The correct param name is javax.ws.rs.Application (not javax.ws.rs.core.Application which is the class you're extending).
See for example:
docs.oracle.com/cd/E24329_01/web.1211/e24983/configure.htm#RESTF179
You just need to configure the servlet in web.xml. You don't need to add #Repository to your ExceptionMapper.
<servlet>
<servlet-name>rest-servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>your.base.package.to.rest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
When the application is deploy you can see the following lines in log file:
INFO: Scanning for root resource and provider classes in the packages:
your.base.package.to.rest
INFO: Root resource classes found:
class your.base.package.to.rest.resources.FooResource
INFO: Provider classes found:
class your.base.package.to.rest.providers.NotFoundMapper
Tested with:
Jersey v1.11 12/09/2011 10:27 AM
Spring v3.1.1
GlassFish Server Open Source Edition 3.1.2 (build 23)
I faced the same problem and the change in web.xml, in particular in tag solved the issue.
Just make sure that the for the includes your package for the exception and exception mapper classes not only the packages containing the models and resources
jersey.config.server.provider.packages
basepackage
ex. if package for models/entities is pkg.entity and for exception is pkg.exception param-value (basepackage) will be pkg. If basepackage is set pkg.entity it doesn't work...that is how i solved the issue.

Resources