I have my rest class below.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
#Path("/users")
public class UserRestService {
#GET
public Response getUser() {
return Response.status(200).entity("getUser is called").build();
}
}
I dont know how does server mapping this /users uri pattern with this UserRestService.java file.Do we need to configure in web configuration...?
My question: How it is invoking UserRestService.java when /users URI pattern is matching?
Thanks in Advance...
Because your jax-ws servlet is set to respond to particular url in your application like a one follows
<servlet>
<servlet-name>jaxws-servlet</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSSpringServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jaxws-servlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
There is a class javax.ws.rs.core.Application; which you need to extend (atleast I did this) in order to register your JaxRs Resource URI and provide the corresponding info in web.xml like :-
public class ExtendedClass extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(UserRestService.class);
return classes;
}
}
in web.xml :-
<servlet>
<description>
JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>package.name.ExtendedClass</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>
/</url-pattern>
</servlet-mapping>
In a REST based architecture everything is a resource. A resource is accessed via a common interface based on the HTTP standard methods (e.g., POST, GET, PUT or DELETE). And it's org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher servlet class mentioned in web.xml of your web application that enlist all JAX-RS root resources and providers.
And with the /* url-pattern all resources will be passed to RESTeasy servlet.
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
You will be wondering how RESTeasy came to know about my class annotated with #Path, so there is another configuration that let RESTeasy know about your resources which you have to mention in your web.xml i.e.
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
So when request comes from /users then org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher serrvlet identifies the URI path that a resource class or class method will serve requests for and call it which is UserRestService in your case.
Hope it helps :)
Related
I have a confusion regarding the structure of the web.xml for the servlet mapping, I don't have any problem by executing it but I am trying to figure it how why we have such a pattern in the deployment descriptor.
<web-app>
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-path>foo.Servlet</servlet-path>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/enroll</url-pattern>
</servlet-mapping>
</web-app>
Now as far as my understanding whenever a request is comes for url-pattern "/enroll", servlet container is going to match the servlet-name with the url-pattern and will try to find the corresponding servlet-path and will forward the control to foo.Servlet. so basically there would be two passes one for finding servlet-name and another for servlet-path, my question is if container is designed to work in the following way
<web-app>
<servlet>
<servlet-name>foo.Servlet</servlet-path>
<url-pattern>/enroll</url-pattern>
</servlet>
</web-app>
what would be the drawback if we use the following approach. Wouldn't that be more efficient and the response time would be fast.
It allows servlets to have multiple servlet mappings:
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-path>foo.Servlet</servlet-path>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/enroll</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/pay</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/bill</url-pattern>
</servlet-mapping>
It allows filters to be mapped on the particular servlet:
<filter-mapping>
<filter-name>Filter1</filter-name>
<servlet-name>Servlet1</servlet-name>
</filter-mapping>
Your proposal would support neither of them. Note that the web.xml is read and parsed only once during application's startup, not on every HTTP request as you seem to think.
Since Servlet 3.0, there's the #WebServlet annotation which minimizes this boilerplate:
#WebServlet("/enroll")
public class Servlet1 extends HttpServlet {
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading
Difference between each instance of servlet and each thread of servlet in servlets?
Our Servlets wiki page
Writing a Web Service in Java (Jersey/Maven). I'd like to construct a class that builds a number of databases before the application is deployed - as all of its resources depend on those databases. Although there is a textual representation of the Jersey's ServletContainer source code, it has already been compiled into bytecode and packed into a jar and, thus, cannot be edited. Is the solution as simple as declaring an instance of the ServletContainer class in my code and overriding the init method there?
You can just do all your initialization in the ResourceConfig.
package org.foo;
public class AppConfig extends ResourceConfig {
public AppConfig() {
// initialize here
packages("the.packages.to.scan");
}
}
And you can declare it in the web.xml
<web-app>
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.foo.AppConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
For other deployment options see Servlet-based Deployment
I'm working with Jersey restful API with Atmosphere.
Here is my web.xml
<servlet>
<description>AtmosphereServlet</description>
<servlet-name>AtmosphereServlet</servlet-name>
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.example.p1</param-value>
</init-param>
<async-supported>true</async-supported>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>AdminPanel</servlet-name>
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.example.p2</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
<param-value>/WEB-INF/admin/</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AdminPanel</servlet-name>
<url-pattern>/admin/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Now, I have a resource class with #Path("/register") and I have defined both #GET and #POST methods. There is no other class which handles the path /register in my entire project.
#Path("/register")
public class Register{
#POST
public String method1(){
return "POST";
}
#GET
public String method1(){
return "GET";
}
}
The url I'm using is http://129.123.3.3/user/register and I'm using the POST method in my call.
Inspite of defining both GET and POST methods I'm getting
HTTP Status 405 - Method Not Allowed
But, when I remove my serlvet mapping for AdminPanel and change the <url-pattern> for AtmosphereServlet to /* instead of / the appropriate method is called. But this way I cannot use URLS which are defined in my AdminPanel servlet. What am I missing? If this is a problem solely related to Servlet Mapping what can be the mapping so that the requests are correctly routed to /admin and the other requests are not hampered?
Implement a class
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends javax.ws.rs.core.Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
resources.add(Register.class);
return resources;
}
}
The your URL will be
GET /<context>/webresources/register
I have a confusion regarding the structure of the web.xml for the servlet mapping, I don't have any problem by executing it but I am trying to figure it how why we have such a pattern in the deployment descriptor.
<web-app>
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-path>foo.Servlet</servlet-path>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/enroll</url-pattern>
</servlet-mapping>
</web-app>
Now as far as my understanding whenever a request is comes for url-pattern "/enroll", servlet container is going to match the servlet-name with the url-pattern and will try to find the corresponding servlet-path and will forward the control to foo.Servlet. so basically there would be two passes one for finding servlet-name and another for servlet-path, my question is if container is designed to work in the following way
<web-app>
<servlet>
<servlet-name>foo.Servlet</servlet-path>
<url-pattern>/enroll</url-pattern>
</servlet>
</web-app>
what would be the drawback if we use the following approach. Wouldn't that be more efficient and the response time would be fast.
It allows servlets to have multiple servlet mappings:
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-path>foo.Servlet</servlet-path>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/enroll</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/pay</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/bill</url-pattern>
</servlet-mapping>
It allows filters to be mapped on the particular servlet:
<filter-mapping>
<filter-name>Filter1</filter-name>
<servlet-name>Servlet1</servlet-name>
</filter-mapping>
Your proposal would support neither of them. Note that the web.xml is read and parsed only once during application's startup, not on every HTTP request as you seem to think.
Since Servlet 3.0, there's the #WebServlet annotation which minimizes this boilerplate:
#WebServlet("/enroll")
public class Servlet1 extends HttpServlet {
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading
Difference between each instance of servlet and each thread of servlet in servlets?
Our Servlets wiki page
The JAX-RS 1.1 specification says on page 6:
If no Application subclass is present
the added servlet MUST be named:
javax.ws.rs.core.Application
What is the added servlet? Could it be an arbitrary servlet?
If an Application subclass is present
and there is already a servlet defined
that has a servlet initialization
parameter named:
javax.ws.rs.Application
Again, what is "a servlet" here?
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.
Does "the servlet added by the ContainerInitializer" mean that the servlets is added automatically? How would a configuration look like?
At the moment I use neither an Application class nor a web.xml and it works (with GlassFish 3.1). Does this deployment mechanism require a full class path scan, which could be slow with big libraries?
How to deploy on a Servlet container?
There is a confusing number of configuration options around in the web. See this example with context params in the web.xml (doesn't work for me!). What is the preferred way to deploy a JAX-RS application?
There are a number of options for deploying into a Java EE 6 container (more specifically a Servlet 3.0 implementation):
The simplest is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Then all the #Path and #Provider classes found in your web application will be available in the "default" JAX-RS application with a servlet URL pattern of "/rest/*".
If you have one or more classes that extends javax.ws.rs.core.Application, you can specify like so:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>com.example.jaxrs.MyApplication</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>com.example.jaxrs.MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
You may want to do the above in case you wish to only return specific sets of #Path/#Provider classes on a URL (so you could have a second MyApplication2 with a different URL pattern above).
You can also skip the whole web.xml altogether and just annotate your MyApplication class wih #ApplicationPath which will serve as the URL pattern. I would recommend keeping the web.xml in any case because you will probably have to add other information about the web application there anyway.
If you're wondering where the servlet-class comes from, it is automatically added in by the environment. You can get an idea by looking at the Servlet 3.0 ServletContext.
With WAS 8.5, I change the web.xml to add:
<servlet>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.tada.rest.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
My RestApplication look like :
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
public class RestApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> sets = new HashSet<Class<?>>();
sets.add(RestService.class);
return sets;
}
}
My RestService looks like
#Path("/tada")
public class RestService {
#GET
public String getSomething() {
return "tada";
}
}
And I add in the pom.xml the dependency:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
With Servlet3.0, follow this. This works for me.
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>your.restsrv.config.RESTConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<enabled>true</enabled>
<async-supported>false</async-supported>
</servlet>
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
As I said in the comment above, it all depends on the framework you want to use.
http://syrupsucker.blogspot.com/2008/10/deploying-jersey-in-tomcat-60.html for Jersey
http://syrupsucker.blogspot.com/2008/10/deploying-resteasy-in-tomcat-60.html for RESTeasy
As far as I know, JAX-RS does not contain a specification for deployment.