0

I am trying to develop a Jersey server application for a booking system in Eclipse using Payara server. When I run the project I get "HTTP Status 404 - Not Found". I have checked several tutorials and StackOverflow posts but cannot find the error. Can anybody help me with this?

BookingService interface:

public interface BookingService {

    public Response addBooking(Room room);

    public Response cancelBooking(Room room);

    public Room getRoom(int roomNumber);

    public Room[] getAllAvailableRooms();
}

BookingService implementation:

@Path("/booking")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class BookingServiceImpl implements BookingService{

private static Map<Integer,Room> rooms = new HashMap<Integer,Room>();

@POST
@Path("/add")
public Response addBooking(Room room) {
    Response response = new Response();

    if(rooms.get(room.getNumber()).isBooked()) {
        response.setMessage("This room is not available");
        return response;
    }
    room.bookRoom();
    response.setMessage("Room successfully booked");

    return response;
}

@GET
@Path("/delete")
public Response cancelBooking(Room room) {
    Response response = new Response();
    if(!rooms.get(room.getNumber()).isBooked()) {
        response.setMessage("This room is not booked so booking cannot be cancelled");
        return response;
    }

    room.cancelBooking();
    response.setMessage("The booking for room " + room.getNumber() + "has been successfully cancelled");
    return null;
}

@GET
@Path("/getAll")
public Room[] getAllAvailableRooms() {
    Set<Integer> keys = rooms.keySet();
    Room[] roomArray = new Room[keys.size()];
    int i=0;
    for(Integer key : keys){
        if (!rooms.get(key).isBooked()) {
            roomArray[i] = rooms.get(key);
            i++;
        }
    }
    return roomArray;
}

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>se.kth.id1212</groupId>
<artifactId>ID1212BookingSystem</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>ID1212BookingSystem Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>2.20</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.20</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.13</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
        <version>2.22.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>
<build>
    <finalName>ID1212BookingSystem</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <warSourceDirectory>WebContent</warSourceDirectory>
                <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Edit: When I researched the problem I read that the web.xml file did not have to specify anything other than display name when using jersey 2. I don't know if that's true, but below is the web.xml file I used before reading that, but it does not work either.

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <!-- Jersey Servlet configurations -->
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>se.kth.id1212.ID1212BookingSystem</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <!-- Jersey Servlet configurations -->
</web-app>

Edit 2, added the following images:

Project package structure

Postman 404 error

Ravi
  • 30,829
  • 42
  • 119
  • 173
DMJessieSP
  • 15
  • 1
  • 4
  • which tutorial are you following ? where is your rest app context root path in web.xml ? Also, what is the url your are using to access ? – Ravi Dec 31 '17 at 16:32
  • which tutorials ? – Ravi Jan 01 '18 at 12:42
  • I have mainly followed these tutorials: https://www.journaldev.com/9170/restful-web-services-tutorial-java#comment-41869, https://needhamia.com/how-to/java-software-development/create-a-jersey-web-project-using-maven-tomcat-and-eclipse/, but looked at several others. I read in another StackOverflow post that when using jersey 2 there is no need for anything else in the web.xml file, but I previously had a web.xml file similar to those in the tutorials and that did not work either. I have tried the URLs http://localhost:8080/ID1212BookingSystem/booking/add as well as the same with /getAll. – DMJessieSP Jan 01 '18 at 12:50
  • What's the URL that gives you HTTP 404 error? With your configuraion, it would be normal to get 404 error on the root URL like http://localhost/myapp because no REST resource is bound to the this URL. Instead, try with URL like http://localhost/myapp/getAll which matches the method BookingServiceImpl.getAllAvailableRooms. See my answer for more advice. – OndroMih Jan 02 '18 at 12:00
  • The URL in my comment above should be http://localhost/myapp/booking/getAll – OndroMih Jan 02 '18 at 12:28

2 Answers2

0

Even, your latest web.xml has issue, you need to go slow and compare each changes with tutorial. As per mentioned tutorials

You should have below init-param in your web.xml

<init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>se.kth.id1212.ID1212BookingSystem</param-value>
</init-param>

But, instead you have written

<init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>se.kth.id1212.ID1212BookingSystem</param-value>
</init-param>

Also, just for side note, /add expects POST, that means it will expect request data in its body. I would suggest to use some REST client, may be POSTMAN for your testing.

== Updated ==

I really don't understand, why are you using below package name in your web.xml ????

<param-value>se.kth.id1212.ID1212BookingSystem</param-value>

I was definite, somewhere, you have don't blunders, the package of BookingServiceImpl should be server.service not se.kth.id1212.ID1212BookingSystem. So, in param-value, you are supposed to provide the same package name not the random one.. So, it should be

 <param-value>server.service</param-value>

Also, I see, you have used Produces/Consumes annotations on class, instead it should be on each methods

 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
 public class BookingServiceImpl implements BookingService{

It's my humble request, don't mix your knowledge with available tutorial. First try to understand the implementation, by EXACTLY following any available tutorials (may be just copy/paste). Pick the simplest tutorial may be just printing Hello World

Ravi
  • 30,829
  • 42
  • 119
  • 173
  • Thank you for your reply, but the reason I use javax.ws.rs.Application is because I use Jersey 2. The tutorials I linked uses Jersey 1. Jersey 2 does not use com.cun.jersey.config.property.packages anymore: https://stackoverflow.com/questions/18086218/java-lang-classnotfoundexception-com-sun-jersey-spi-container-servlet-servletco. I have tried using both packages suggested by the two top replies, as well as the package used in this tutorial for Jersey 2: http://www.javahelps.com/2015/08/jersey-2x-hello-world.html. I did try anyway with what you suggested but it didn't work unfortunately. – DMJessieSP Jan 01 '18 at 15:42
  • @DMJessieSP No, you can't change the package name as per your convenient. check my post now. Since, you are using jersey 2, then package name would be `jersey.config.server.provider.packages` – Ravi Jan 01 '18 at 15:45
  • Ok, I have changed it, thank you! Unfortunately, it still doesn't work, I still get 404 not found. – DMJessieSP Jan 01 '18 at 16:03
  • @DMJessieSP Can you add screenshot of your browser (with url and error) to your original post. ? Also, add screenshot of your project folder structure – Ravi Jan 01 '18 at 16:06
  • @DMJessieSP you have done lot of blunders in your code. Please check my updated post. – Ravi Jan 01 '18 at 17:03
  • @DMJessieSP Don't forget to upvote and accept the answer, if it was helpful. – Ravi Jan 02 '18 at 03:56
0

Your application seems to define no REST endpoint that listens on the root URL. If your app is running on a URL like http://localhost/myapp then it's completely normal to get HTTP 404 response for that URL. You would get a valid response only from URLs that are bound to some REST methods.

Because BookingServiceImpl is bound to "/booking" and all its methods are bound to subpaths like "/add" or "/getAll", you can access the REST methods by combining

  • the application context root, e.g. "myapp" (that's unknown to me)
  • JAX-RS application root path, which is "/*" as defined in web.xml, which means it's empty
  • BookingServiceImpl path, which is "/booking"
  • path on a BookingServiceImpl method, for example "/getAll" for getAllAvailableRooms

So to call the getAllAvailableRooms method, you should use an URL like http://localhost/myapp/booking/getAll and not only http://localhost/myapp.

In a recent Payara Server version, you should be able to see all the available URLs in the web admin console when you go to application details and click "View endpoints" in the "Modules and Components" table at the bottom, see screenshots at the end.

Additional notes:

I recommend defining the JAX-RS application in a separate class that extends javax.ws.rs.Application and accepts @ApplicationPath annotation with the servlet mapping. Then you don't need anything in your web.xml and you can even delete it. This is Java code that's equivalent to your web.xml (yes, it's that simple, all other code is optional):

@ApplicationPath("/")  // maps the servlet to "/*"
public class MyRESTApplication extends Application {
}

I also recommend to watch a short video about creating a REST service with Payara in Netbeans (it should be very similar in Eclipse, the IDE isn't much relevant). You can skip the intro and start from 3:30.

REST Endpoint details in Payara Admin Console

Application details in Admin console REST endpoints in Admin console

Sadeq Dousti
  • 3,346
  • 6
  • 35
  • 53
OndroMih
  • 7,280
  • 1
  • 26
  • 44