Search code examples
eclipsetomcatjax-rsweb-deploymentwar-filedeployment

Rest app (Jersey/JAX-RS) runs in glassfish through eclipse but not when deployed in tomcat


I created a web app using eclipse and (Jersey/JAX-RS). Although when i "run on server" from eclipse in glassfish everything is ok when I deploy the war file I produce either from maven install or from eclipse "export war file" it is deployed succesfully but when i try to access the same rest resources that work in the first option described above, they are not available "404" error.

This is my web.xml file :

  <?xml version = "1.0" encoding = "UTF-8"?> 
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"  
   xmlns = "http://java.sun.com/xml/ns/javaee"  
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
   id = "WebApp_ID" version = "3.0"> 
   <display-name>Rate it</display-name> 

   <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>

   <listener>
        <listener-class>
             com.rateit.util.MyAppServletContextListener
        </listener-class>
   </listener>

   <servlet> 
      <servlet-name>RateIt login services</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.rateit.login</param-value> 
      </init-param> 
      <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
      </init-param>
   </servlet> 

   <servlet-mapping> 
      <servlet-name>RateIt login services</servlet-name> 
      <url-pattern>/loginServices/*</url-pattern> 
   </servlet-mapping> 
</web-app>

This is my pom file :

<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>com.gamechangerapps</groupId>
  <artifactId>rateit</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>

  <name>rateit Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <dependencies>

    <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
    </dependency>  

    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
         <artifactId>jersey-client</artifactId>
         <version>2.22.2</version>
         <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.eclipsesource.minimal-json/minimal-json -->
    <dependency>
        <groupId>com.eclipsesource.minimal-json</groupId>
        <artifactId>minimal-json</artifactId>
        <version>0.9.4</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>


    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
        <version>3.2.2</version>
    </dependency>

    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>mail</artifactId>
        <version>1.4</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.19</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.0</version>
    </dependency>

  </dependencies>

  <build>
    <finalName>rateit</finalName>
    <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-war-plugin</artifactId>
              <configuration>
                  <webXml>WebContent\WEB-INF\web.xml</webXml>
              </configuration>
          </plugin>

          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
   </plugins>
  </build>
</project>

and this is my project structure :

project structure

This is LoginServices class

package com.rateit.login;

import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.UriBuilder;
import org.apache.log4j.Logger;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import com.rateit.causecodes.LoginCodes;
import com.rateit.inbox.InboxServices;
import com.rateit.mailing.MailServices;
import com.rateit.property.Building;
import com.rateit.property.PropertyDao;
import com.rateit.rating.RatingQueue;
import com.rateit.util.BaseUriProvider;
import com.rateit.util.FileOperations;
import com.rateit.util.GlobalVariables;
import com.rateit.util.JobIdGenerator; 

@Path("/Welcome") 
public class LoginServices {   
     UserDao userDao = UserDao.getInstance();
     MailServices mailBot = MailServices.getInstance();
     FileOperations fileManager = new FileOperations();
     PropertyDao propDao = PropertyDao.getInstance();
     InboxServices inServ = new InboxServices();
     String baseUri = BaseUriProvider.getStreamInstance().getBaseUri();

     static Logger logger = Logger.getLogger(LoginServices.class);

     @Context
     private ServletContext context;

     /**
     * Service for Login purposes  
     *
     * @FormParam   String user email
     * @FormParam   String user password
     * 
     * @return      LoginCodes  LOGIN_SUCCESFUL/LOGIN_FAILURE_INVALID_EMAIL/LOGIN_FAILURE_INVALID_PASSWORD/LOGIN_FAILURE_GENERIC  
     *                   
     */
     @Path("/login")
     @POST
     @Consumes("application/x-www-form-urlencoded")
     public Response login(@FormParam("email") String e, @FormParam("password") String p) {   
         ResponseBuilder builder = null;

         // get new JobId for this operation
         int jobId = JobIdGenerator.getStreamInstance().getJobId();

         // Create the user object
         User userInput = new User(e,p);

         String loginCheck = LoginCodes.LOGIN_FAILURE_GENERIC.getDescription();  

         User userFromDB = userDao.getUser(userInput.getEmail());
         logger.info("JobID="+jobId+" for user with email  "+userInput.getEmail()+" this user "+userFromDB.getEmail()+" was found in DB");

         // login successful
         if(userInput.getEmail().equals(userFromDB.getEmail()) && userInput.getPassword().equals(userFromDB.getPassword())){
             loginCheck = LoginCodes.LOGIN_SUCCESFUL.getDescription();
             builder = Response.seeOther(UriBuilder.fromUri(baseUri+"/login.html").queryParam("user", userFromDB.getEmail()).queryParam("loginCheck", loginCheck).build());
         }
         // invalid mail
         else if(!userInput.getEmail().equals(userFromDB.getEmail())){
             loginCheck = LoginCodes.LOGIN_FAILURE_INVALID_EMAIL.getDescription();
             builder = Response.seeOther(UriBuilder.fromUri(baseUri+"/login.html").queryParam("loginCheck", loginCheck).build());
         }
         // invalid password
         else if(userInput.getEmail().equals(userFromDB.getEmail()) && !userInput.getPassword().equals(userFromDB.getPassword())){
             loginCheck = LoginCodes.LOGIN_FAILURE_INVALID_PASSWORD.getDescription();
             builder = Response.seeOther(UriBuilder.fromUri(baseUri+"/login.html").queryParam("loginCheck", loginCheck).build());
         }
         // both password and mail invalid
         else{
             builder = Response.seeOther(UriBuilder.fromUri(baseUri+"/login.html").queryParam("loginCheck", loginCheck).build());
         }

         logger.info("JobID="+jobId+" Login attempt for user "+e+" "+loginCheck);

         return builder.build();
     }

The problem is the follwing :

The following test can not hit the rest api

@Test
    public void loginUserSuccessTest() 
    {
        // Create a user and add him to the DB
        User testUser = new User("[email protected]","1234");
        mockDaoObject.addnewUser(testUser);

        // Create a HTTP request
        Client client = ClientBuilder.newClient();
        //WebTarget target = client.target(baseUri+"/loginServices/Welcome/login");
        WebTarget target = client.target("http://localhost:8080/rateit/loginServices/Welcome/login");
        target.property(ClientProperties.FOLLOW_REDIRECTS, false);
        Builder basicRequest = target.request();  

        // Create a form with the front end parameters
        Form form = new Form();
        form.param("email", testUser.getEmail());
        form.param("password", testUser.getPassword());

        // Send the request and get the response
        Response response = basicRequest.post(Entity.form(form), Response.class);

        // Delete the user
        mockDaoObject.deleteUser(testUser);

        // Check that the response is success
        boolean correctCause = response.getLocation().toString().contains("loginCheck=User+logged+in+successfully");
        boolean correctUser = response.getLocation().toString().contains("user=");

        assertEquals(true, correctCause);
        assertEquals(true, correctUser);
        assertEquals(303, response.getStatus());    
    }

Any advice will be helpful


Solution

  • After some investigation i found the issue. The problem was that some dependencies were missing and also a configuration in eclipse. I found the error by checking the logs/localhost.date log in tomcat. There i found the following exception :

    15-Oct-2019 23:04:16.492 INFO [http-nio-8080-exec-42] org.apache.catalina.core.ApplicationContext.log Marking servlet [RateIt login services] as unavailable
    15-Oct-2019 23:04:16.493 SEVERE [http-nio-8080-exec-42] org.apache.catalina.core.StandardWrapperValve.invoke Allocate exception for servlet [RateIt login services]
        java.lang.ClassNotFoundException: org.glassfish.jersey.servlet.ServletContainer
            at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1365)
            at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188)
            at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:540)
            at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:521)
            at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:150)
            at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1042)
            at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:761)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:135)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
            at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
            at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
            at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
            at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)
            at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Unknown Source)
    

    Based on this error i fixed the deployment issue with the 3 following steps :

    1. I added the following dependencies in my pom.xml file

      org.glassfish.jersey.containers jersey-container-servlet 2.19 org.glassfish.jersey.core jersey-server 2.19

      1. I added the maven dependencies in WEB-INF/lib folder through eclipse

      MyProject->Properties->Deployment Assembly->Add(Maven Dependencies:source and WEB-INF/lib:Deploy Path

      1. I created the war file through export in eclipse and not through maven task