After some time spent with servlets and JSPs now i'm trying to learn something about JSF. I've learned the basics, made a couple of simple examples, have a basic ideea of the 'workflow' but I still can't understand what's with the javax.faces.webapp.FacesServlet thing.
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
I know that "Faces Servlet" it's just an 'internal' name just for the XML and that it gets bind with a class, in this case: javax.faces.webapp.FacesServlet. But where is this class anyway?! I'm using Eclipse, created a new Dynamic Project, GlassFish 4.0 as Server, JSF 2.0 as Configuration (selected no library) and neither did I import any jar. How can it be working? And when I try to run the same thing with JBoss I must import a javax.faces-2.2.2.jar file.
Ok, the library might be already included in GlassFish since it works but... will I face any problems if I try to deploy my app on another server? Like JBoss or Websphere.
In a nutshell: what are the prerequisites when working with JSF technology :)
Thank you.
javax.faces.webapp.FacesServlet is a class that implements Servlet interface. In order to be recognized in your application, you should add it in the web.xml as a <servlet>. This is basically done in this configuration:
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Now, we can refer to this class in the web.xml file using the Faces Servlet name. Next thing do to is define the URL that will be handled by this servlet. This is done in this configuration:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
So, any GET or POST request to this application server that ends with jsf suffix will be handled by Faces Servlet. You can use other URL patterns for the servlet mapping. This is better explained here: JSF Facelets: Sometimes I see the URL is .jsf and sometimes .xhtml. Why?
will I face any problems if I try to deploy my app on another server? Like JBoss or Websphere?
If the application server is a Java EE 5 compliant server, then you will have access to this servlet by using Mojarra implementation in form of JSF 1.2. For Java EE 6 compliant servers this will be in Mojarra implementation in for of JSF 2.x (check the notes of the application server to know the exact version). Currently, with GlassFish 4, you get Mojarra for JSF 2.2.
In case the application server is not a Java EE compliant server e.g. Tomcat, you must add the libraries manually in WEB-INF/lib folder of your web application. Which libraries to add? Depending on the JSF version and its requirements (read further).
what are the prerequisites when working with JSF technology?
This is covered in StackOverflow JSF wiki. Taken from there:
Minimum requirements
JSF 1.0 and 1.1 requires a minimum of Servlet 2.4 / JSP 2.0 and Java 1.4.
JSF 1.2 works on Servlet 2.4, but requires a minimum of JSP/EL 2.1 which goes hand in hand with Servlet 2.5, so it after all requires Servlet 2.5. If you replace JSP 2.1 by Facelets 1.x as default view technology, then you can use JSF 1.2 on Servlet 2.4. It requires a minimum of Java 1.5.
JSF 2.0 which uses by default Facelets 2.x requires a minimum of EL 2.1 which goes hand in hand with Servlet 2.5, so it requires after all Servlet 2.5. If you supply your own EL 2.1 API/impl, then you can in theory run JSF 2.0 on Servlet 2.4. It requires a minimum of Java 1.5.
JSF 2.1 uses some Servlet 3.0 specific features, but is backwards compatible with Servlet 2.5. Those Servlet 3.0 features are optional.
JSF 2.2 requires a minimum of Servlet 3.0, because of the new file upload component which is internally using the standard Servlet 3.0 API without the need for 3rd party libraries. It requires a minimum of Java 1.6.
Examples of Servlet 2.4 containers are Tomcat 5.5.x, JBoss AS 4.x and Sun Java Application Server.
Examples of Servlet 2.5 containers are Tomcat 6.0.x, JBoss AS 5.x and GlassFish 2.x.
Examples of Servlet 3.0 containers are Tomcat 7.0.x, JBoss AS 6.x and 7.x and GlassFish 3.x.
Examples of Servlet 3.1 containers are Tomcat 8.0.x, WildFly 8.x, and GlassFish 4.x.
Related
Environment
Spring 4.3 (no Spring Boot!), JDK 8/11, Tomcat 8.5.x, Vaadin 19/20-SNAPSHOT
I have a legacy webapp running another servlet-api-driven web framework at http://app.com. I want to add a path that adds a Vaadin-driven UI to this application - let's say at http://app.com/vaaadin-app . I'm using the newly developed official Gradle plugin. (Both Vaadin and non-Vaadin web applications should be run from single WAR, effectively sharing single classloader for shared state access, so no proxy/rewrite/etc solutions will help here).
Problem
After adding dependencies the Vaadin app is properly built and war created. Yet as soon as I call http://app.com (not http://app.com/vaadin-app) it looks like Vaadin servlet/whatever is taking over all requests. It looks like it is automatically initialized by (I guess) servlet 3.0 annotations.
Question
How can I enable Vaadin only for http://app.com/vaadin-app and keep it away from altering requests not directed there? I know with Vaadin 8 it was possible to achieve this with:
<servlet>
<servlet-name>vaadinServlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>app.vaadin.additem.AddItemUI</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>vaadinServlet</servlet-name>
<url-pattern>/vaadin-app/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>vaadinServlet</servlet-name>
<url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>
In other words: how to prevent Vaadin 19/20 from spawning itself automatically for /* but to serve application only when user hits the /vaadin-app/* servlet path???
I think in case of maven plugin there was the "disable.automatic.servlet.registration" option to achieve this? But I don't see anything like this in case of Gradle plugin.
Thanks!
The servlet registration in Vaadin should have nothing related to Gradle, so applying the generic instructions should work. The automatic servlet registration is omitted if you define a VaadinServlet manually (extend it and map the servlet to your location of choice using #WebServlet).
Check this part of the documentation for more details: https://vaadin.com/docs/latest/flow/advanced/application-lifecycle/#automatic-servlet-registration
From the textbook "RESTful Java with JAX-RS" we can read:
If our application server is JAX-RS-aware or, in other words, is tightly integrated with JAX-RS declare our ShoppingApplication class as a servlet:
<?xml version="1.0"?>
<web-app>
<servlet>
<servlet-name>Rest</servlet-name>
<servlet-class>
com.restfully.shop.services.ShoppingApplication
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Rest</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
If our application server is not JAX-RS-aware, you will have to specify the JAX-RS provider's servlet that handles JAX-RS invocations. The Application class should be specified as an init-param of the servlet:
Now my question is: Is Tomcat a JAX-RS aware Servlet container? How do you distinguish a servlet container JAX-RS aware from one which is not JAX-RS aware? Why in the first case it's possible to use your custom class which extends javax.ws.rs.core.Application as a Servlet?
"Is Tomcat a JAX-RS aware Servlet container?"
No.
"How do you distinguish a servlet container JAX-RS aware from one wich is not JAX-RS aware?"
The fact this it is only a Servlet container, should tell you that it is not "JAX-RS aware". JAX-RS is part of the Java EE specification. Servlet containers supports exactly what their name implies; a container for Servlets. They might have support for other little features like JSP, but will not support the entire EE spec. This is not part of their design. If you want to use JAX-RS in a Servlet container, you need to add an implementation, like Jersey or Resteasy
When you say Servlet container you think of servers like Jetty, Tomcat, Undertow, Grizzly. If you want full Java EE support then you need to get an actual Java EE application server that supports the entire spec, like JBoss/Wildfly, Glassfish, TomEE, WebSphere, WebLogic.
"Why in the first case it's possible to use your custom class wich extends javax.ws.rs.core.Application as a Servlet?"
I was not able to produce a working example with either Glassfish 4.0 or Wildfly 8.1, nor is this specified anywhere in the JAX-RS specification. In Glassfish, I'll get an exception about ShoppingApplication not being a Servlet, and in Wildfly I'll just get a NotFoundException, meaning the application is never loaded.
The closest thing I could find to what the book states, is to specify the name of the application class as the <servlet-name> (which is part of the JAX-RS spec, but is not at all dependent on being deployed to a Java EE server)
<servlet>
<servlet-name>com.restfully.shop.services.ShoppingApplication</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>com.restfully.shop.services.ShoppingApplication</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
This is from the JAX-RS spec
If an Application subclass is present that is not being handled by an existing servlet, then the servlet added by the ContainerInitializer MUST be named with the fully qualified name of the Application subclass.
Read JAX-RS spec - Plublication - 2.3.2 Servlet for the completely specification on standard JAX-RS deployment options. Any other deployment/configuration option not specified is implementation specific.
we recently upgraded our jetty version. when we did this both of our legacy gui war files, which no one has modified in some time, stopped working correctly. I believe I hunted the root cause to the proxy (used to proxy to a restful interface on another port), any call to the proxy throws the exception:
IllegalStateException: !asyncSupported
I'm not sure why this would occure with 1.9 but not with the old jetty. I can't build the war file currently, it was a mess that only one developer could ever build, but I trid unzipping it with jetty -x and ading to the servlet section of the web.xml file this:
<async-supported>true</async-supported>
and then rezipping it with jar c command. that didn't seem to help, though now i get exceptions in my jetty log fhile while before they would only show in the browser.
can anyone tell me what to do to activate async support and/or why the switch in jetty would cause this?
Ah, the evolution of the spec ...
Jetty 7 was Servlet 2.5 (no async there)
Jetty 8 was Servlet 3.0 (async introduced) - spec was vague on what was default, so Jetty defaulted to async-supported == true
Jetty 9 is Servlet 3.1 (even more async) - the spec was clarified, and jetty chose its default poorly. The default according to the spec is async-supported == false
That's why you didn't have to specify async-supported in the past, but now you do.
Bug about this bugs.eclipse.org/410893
Commit: 9bf7870c7c8a209f2660f63c14dd4acb62b07533
My exception is the same to you. then I put "<async-supported>true</async-supported>" append to every servlet and filter. it work well.
For excample
<filter>
<filter-name>continuation</filter-name>
<filter-class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
the other hand. if you used jetty9.x. you'd better update your comet jar to version 3.0.x or later. I hope it will help you.
I can't (yet) put this as a comment, but I'd like to add: If you are having this trouble and have added the async-supported tag as appropriate (or are using Jetty 8), make sure your filters also support async or are not used with the servlet in question.
For Java based config you may use
#javax.servlet.annotation.WebServlet(name = "HelloWorld",urlPatterns = { "/MyServlet" },asyncSupported =true)
I have Weblogic 10.3.5 installed. I deployed the JSF 2.0 war on the server. In my WebContent folder, I have *.xhtml and *.jsp files, which contain JSF2.0 xhtml and pure JSP code, respectively. When I navigate to http://localhost:7001/MyApp/NewFile123.xhtml, I get a 404 Not found error page. (Nothing informative on the Eclipse console). But http://localhost:7001/MyApp/NewFile.jsp works well and does what it's supposed to do.
I am not mixing JSF and JSP but just wanted to see if JSP is gonna work. I have the appropriate servlet-mapping for the XHTML files.
I also have these on my classpath:
glassfish.el_1.0.0.0_2-2.jar
glassfish.jsf_1.0.0.0_2-1-5.jar
glassfish.jstl_1.2.0.2.jar
javax.servlet_1.0.0.0_2-5.jar
Another interesting thing, when I try to edit the *.xhtml files, the auto-complete doesn't work. (i.e it won't autocomplete <h:outp. It used to when I was using Weblogic 12.1 which has JSF2.0 out of the box.
Edit: Here is the relevant part of web.xml
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
So why do I get a 404 when I try to navigate to a JSF page? Any suggestions?
I also have these on my classpath:
glassfish.el_1.0.0.0_2-2.jar
glassfish.jsf_1.0.0.0_2-1-5.jar
glassfish.jstl_1.2.0.2.jar
javax.servlet_1.0.0.0_2-5.jar
Remove all those container-specific libraries from your /WEB-INF/lib. They do not belong there at all, the container already ships with them. Your /WEB-INF/lib should contain only the webapp-specific libraries which are not shipped with the container.
Your problem is most likely caused by the fact that Weblogic 1.0.3.5 is a Servlet 2.5 container which already ships with JSF 2.0, but that you're supplying a JSF 2.1 library which requires Servlet 3.0. I don't use Weblogic, but I've read that 1.0.3.x requires some specific steps to get JSF 2.0 to work, see also this blog. Here's an extract of relevance:
Download and install one of the latest Oracle WebLogic Server 11g Rel 1 (10.3.3) Installers from OTN. (Give the ZIP Installer a try. Aweseome lightweight!)
Create a new sample domain (call it whatever you want) and start the admin server
Open the administration console (http://localhost:7001/console/)
deploy the JSF 2.0 library (Deployments - Install - wlserver_10.3\common\deployable-libraries\jsf-2.0.war
Find your favorite JSF 2.0 sample (I'll take the guessNumber thing from the mojarra-2.0.2 distribution)
Add a weblogic.xml file to the WEB-INF/ folder with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app>
<library-ref>
<library-name>jsf</library-name>
<specification-version>2.0</specification-version>
<implementation-version>1.0.0.0_2-0-2</implementation-version>
<exact-match>true</exact-match>
</library-ref>
</weblogic-web-app>
Update as per the comments:
I now suspect that it may be because of the project settings. I created a Dynamic Web Project and chose JSF 1.2. On the next step, where it asked me for the JSF specification and implementation, I pointed him to those glassfish jsf2 jars. The default was 1.2. Maybe I shouldn't have done that?
That might have generated a JSF 1.2 compliant faces-config.xml which would force JSF 2.0 to run in JSF 1.2 modus. You need to redeclare the <faces-config> root declaration to comply JSF 2.0.
<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">
Is it possible to use the embedded java code to add servlets:
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
context.getInitParams().put("useFileMappedBuffer", "false");
context.addServlet(new ServletHolder(new MyServlet()), "/myurl");
....
server.start();
server.join();
in stead of the lengthy web.xml way:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>package.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myurl</url-pattern>
</servlet-mapping>
I know this is posible in a non-maven project, but it seems the Maven Jetty plugin requires this web.xml method.
In servlet 3.0 - yes, regardless of maven and jetty:
Use ServletContext.addServlet(..) where you specify the servlet name, and its class/instance/class name (3 overloaded methods)
Then call addMapping(..) on the returned ServletRegistration to map it to url-pattern(s)
In Servlet 3.0, servlets can be declared and mapped using the #WebServlet annotation. There is no configuration in the web.xml required, and no boilerplate Java code.
#WebServlet("/myurl")
public class MyServlet extends HttpServlet { ... }
However, the current release of Jetty (7.x) only supports Servlet 2.5. Jetty 8.x is currently in development and supports Servlet 3.0. Unless you can use Jetty 8.x, or another servlet container that supports Servlet 3.0, you may need to continue using the web deployment descriptor for defining and mapping servlets.
I believe the maven-jetty-plugin currently only supports Jetty 7 and therefore may require the web.xml as you've found. You might check to see if there is a snapshot of the maven-jetty-plugin available that uses the experimental Jetty 8.x.