Migration of Java / Spring Boot Applications: From Weblogic to Tomcat Server
Tags: java, tomcat, weblogic, server
Published: 2021-04-15 13:39:06

**Oracle WebLogic** Server is a scalable, enterprise Java platform application server for Java-based web applications. It is popular within the commercial sphere — where companies require reliable software that comes with enterprise support.

**Apache Tomcat** is an open-source Java servlet container that implements many Java Enterprise Specs such as the Websites API, Java-Server Pages and last but not least, the Java Servlet. Tomcat is the lightweight server, ideal for modern deployments including Docker, Kubernetes and Cloud deployments.

####Why migrate from Weblogic to Tomcat?

- Reduce complexity
 - Weblogic is complicated, both to program and to administer.
 - Development, debugging and deployment in Weblogic takes more time. It is too heavyweight.
 - Tomcat is faster at tasks such as redeployment. It focuses on essential features.

- Reduce operation costs
 - Maintaining Weblogic is very costly. One significant cost is licensing.
 - The hardware required to support a Weblogic instance and the associated space/power/cooling costs are high.
 - Typical Tomcat operating costs are estimated at ¼ to ⅙ the cost of Weblogic

- Automatic Scaling of WebLogic application server is challenging, as WebLogic deployment architecture is complex.


####Checklist to determine migration suitability

| Factor  |      Migrate to Tomcat?      |  Next Steps |
|----------|:-------------:|------:|
| Application has been developed using Tomcat as runtime during development |  Yes  | Determine configuration and deployment changes |
| Application primarily uses servlets and/or JSPs |    Yes   |   Check if app leverages any WebLogic-specific services and identify their equivalent replacements for Tomcat |
| Application uses Spring framework | Yes |  Determine configuration and deployment changes   |
| Application is written to be strictly standards-compliant | Yes |    Determine if other Java EE technologies are used and identify equivalent replacements for Tomcat |
| Application is a third-party software, that is also available for Tomcat | Yes |    Obtain the Tomcat version of the web application and deploy it in Tomcat |
| Application uses EJB or other WebLogic server functionality, not readily available for Tomcat | No |    Need code refactoring to remove the use of such functionality. This is preferably a “new application”, not a migration |

-----
##Regular Java Applications (Non - Spring Boot):
There are well known differences in the web application configuration and file layout conventions between WebLogic and those of the Java servlet specification standard. Making your application more standards-compliant makes it suitable to run on Tomcat.

Items to check and migrate to the Java Servlet standard:
- If the web application has JSPs, make sure that any references to `java.util.*` packages have corresponding statements in the JSP file.
- Make sure the root of the web application directory includes a WEB-INF directory with a `web.xml` file inside it. The XML in this file needs to declare your mappings from any `weblogic.properties` file you had. 
- If you were already using a `web.xml` file for WebLogic, you will likely have to scrub it for nonstandard elements and attributes and find the standard way of doing the same thing. Tomcat will point these out to you.
- Move your classes directory (if you have one) from the root of your web application to `WEB-INF/classes`.
- Move any JSP files from your `jspfiles` directory (if you have one) into the root of your web application’s directory. Tomcat requires them in the root of your web application.
- Move any JAR files bundled by your web application to `WEB-INF/lib`.
- Remove or stub out any code in your web application that imports/uses the `com.bea.*` or `com.weblogic.*` packages.
- If the web application uses an “invoker” servlet, where the servlet isn’t mapped anywhere in the `web.xml` file, and the servlet is still invoked via a URI such as `/servlets/com.myCompany.myServlet`. Tomcat comes with an invoker servlet that is turned off by default. If you need to use it, refer the Tomcat documentation to enable it.

The above steps needs to be followed to make the application suitable for deployment in an external tomcat server.

####Challenges
- If you are targeting to deploy the application in an embedded tomcat server, Spring Boot framework is the ideal way. 
- But for some reason, if you cannot move to spring boot, then you will need extra efforts. You will have to write a solution to embed the Tomcat server in your application using tomcat-embed API

-----
##Spring Boot Applications
The spring boot applications can be either deployed on an embedded tomcat server or a standalone tomcat server.

#####Embedded Tomcat Server
- This makes it easier to run the app without installing/configuring an external server during development and deployment.

- The generated jar file will include a Tomcat server within, making it possible to run the application with just a java runtime.

- This is the preferred approach to containerize the application with Docker and deploy the container into a container-hosted environment such as Kubernetes.

#####Standalone / External Tomcat Server
- This is the traditional way. You have a war file, which will be used to deploy the application on an external tomcat installation.

- Here, one Tomcat installation can have many applications running in it.

Any `weblogic.properties` file you had will not be used in Spring Boot. If there is any required configuration, move it to `application.properties` file.

For all the changes required to migrate from Weblogic to Tomcat, the steps for both Embedded Tomcat and Standalone Tomcat are provided.

###Changes in dependencies
- By default, Spring Boot has embedded Tomcat server included.

- The `spring-boot-starter-web` dependency, which is used in almost all Spring Boot based applications, includes the Embedded-Tomcat dependency `spring-boot-starter-tomcat` within.

- In the WebLogic app, they would have explicitly excluded this Tomcat dependency in `pom.xml` file as shown below.

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
```

#####For Embedded Tomcat
- Remove the `<exclusions>` tag  and its contents, to add back the embedded Tomcat dependency.

- Here we use jar packaging for deployment. From pom.xml, remove the line `<packaging>war</packaging>`, if present.

- Please note that when no packaging is declared, Maven assumes the artifact is the default: jar.

#####For Standalone Tomcat
- We need to ensure that the embedded servlet container does not interfere with the servlet container to which the war file is deployed. 
- To do so, you need to mark the embedded servlet container dependency as being “provided” in `pom.xml`:
```xml
<dependencies>
    <!-- … -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <!-- … -->
</dependencies>
```
- Here, we use WAR packaging for deployment. Declare the packaging type ‘war’ in pom.xml file as follows:
```xml
<version>0.0.1-your-app-version </version>
<packaging>war</packaging>
<name>your-app-name</name>
```


###Changes in ServletInitializer:

In a Spring Boot application deployed to WebLogic, the servlet extends SpringBootServletInitializer and this initializer directly implements WebApplicationInitializer.

This can be either found in the main class with `@SpringBootApplication` itself:
```java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.WebApplicationInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements 
WebApplicationInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder 
     application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
```

Or, this can be found in a separate class as follows:
```java
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer implements WebApplicationInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder 
     application) {

        return application.sources(ServerTestApplication.class);

    }

}
```

In either cases, follow these steps and make changes to one of the classes.

#####For Standalone Tomcat:
- We do not need the implementation of WebApplicationInitializer. Remove this `implements WebApplicationInitializer` statement.
- Make sure that SpringBootServletInitializer is extended and overrides the configure method as in above code snippet.

#####For Embedded Tomcat:
- We do not need the implementation of WebApplicationInitializer. Also we don’t need to extend the SpringBootServletInitializer, which means to remove the overridden configure method as well. 
- The resulting main class should be of the default format:
```java
@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    //Other methods, beans, etc.

}
```
- If you had a separate ServletInitializer class, that class can be removed as it is not required anymore.


###Deployment

Generate the deployable jar/war file using Maven. 

Run the following commands at project-root folder, to generate jar/war files:

```
mvn clean
mvn install
```
You can alternatively use IDE maven tools to generate jar/war files.
This creates a jar/war file at the path {project-root}/target.

#####For Embedded Tomcat:
- Use the generated jar file to deploy the application. This jar can be run using just a java runtime, without a server configuration. 
- You can easily containerize this application, using Docker.

#####For Standalone Tomcat:
- Use the generated war file to deploy the application in an external Tomcat server.

- NOTE: The version of tomcat present in your dependency tree must be the same as your installed external Tomcat version. This can be resolved in 2 ways:

 - Check the tomcat version in the dependency tree and install the same version externally for deployment.
 - If you need to keep a specific version of external tomcat, you can also change the version used in the app by specifying it in pom.xml. But this method might give rise to cascading errors, which needs to be resolved.
```xml
 <properties>
    <java.version>11</java.version>
    <tomcat.version>10.0.5</tomcat.version>
</properties>
```

**********************

If your application successfully ran on Tomcat, Kudos! You have successfully broken the vendor lock-in for the goodness of open-source.

Cheers!