[ 
https://issues.apache.org/jira/browse/HADOOP-15984?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17912257#comment-17912257
 ] 

ASF GitHub Bot commented on HADOOP-15984:
-----------------------------------------

slfan1989 commented on PR #7019:
URL: https://github.com/apache/hadoop/pull/7019#issuecomment-2585703680

   I have completed the review of all modules and we can say that the upgrade 
from Jersey 1.x to Jersey 2.x is essentially complete. We can now begin the PR 
review. There are only a few minor questions, but I believe they should not be 
blockers. I will summarize and explain them in detail below:
   
   > Background
   
   We are upgrading Hadoop to support JDK 17, and one of the biggest challenges 
is upgrading Jersey from 1.x to 2.x. There are many differences between Jersey 
1.x and Jersey 2.x, and they are almost entirely unrelated, especially since 
Jersey 2.x has undergone a significant internal refactor and now includes its 
own dependency injection framework, which makes integration with Guice very 
difficult.
   
   I noticed that many community members had previously attempted to integrate 
Guice into Jersey 2.x, but with limited success. At the beginning of this PR, I 
also tried this approach, but it didn’t progress smoothly. After careful 
consideration, I decided to move away from Guice and directly use Jersey 2.x's 
own dependency injection framework.
   
   I initially tested this approach in the NodeManager module and confirmed its 
feasibility. I then applied this solution to other modules and validated that 
it works as expected.
   
   I have created a simple upgrade diagram, as shown below:
   
   <img width="920" alt="image" 
src="https://github.com/user-attachments/assets/d36673aa-543e-4f1a-82e2-d7aa36eb3afd";
 />
   
   > Upgrade process
   
   Step1. The way Jetty is injected has been adjusted. 
   
   We now rely on Jersey 2's `ResourceConfig` for package scanning to complete 
dependency injection. We can refer to the following code:
   
   
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java
   
   ```
   /**
      * Add a Jersey resource package.
      * @param packageName The Java package name containing the Jersey resource.
      * @param pathSpec The path spec for the servlet
      * @param params properties and features for ResourceConfig
      */
     public void addJerseyResourcePackage(final String packageName,
         final String pathSpec, Map<String, String> params) {
       LOG.info("addJerseyResourcePackage: packageName = {}, pathSpec = {}.",
           packageName, pathSpec);
       final ResourceConfig config = new ResourceConfig().packages(packageName);
       final ServletHolder sh = new ServletHolder(new ServletContainer(config));
       for (Map.Entry<String, String> entry : params.entrySet()) {
         sh.setInitParameter(entry.getKey(), entry.getValue());
       }
       webAppContext.addServlet(sh, pathSpec);
     }
   
     /**
      * Add a Jersey resource config.
      * @param config The Jersey ResourceConfig to be registered.
      * @param pathSpec The path spec for the servlet
      * @param params properties and features for ResourceConfig
      */
     public void addJerseyResourceConfig(final ResourceConfig config,
         final String pathSpec, Map<String, String> params) {
       LOG.info("addJerseyResourceConfig: pathSpec = {}.", pathSpec);
       final ServletHolder sh = new ServletHolder(new ServletContainer(config));
       if (params != null) {
         for (Map.Entry<String, String> entry : params.entrySet()) {
           sh.setInitParameter(entry.getKey(), entry.getValue());
         }
       }
       webAppContext.addServlet(sh, pathSpec);
     }
   ```
   
   Step2.  Modify the way WebServices are injected in each module.
   
   We will take ResourceManager as an example.
   
   
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
   
   - @Inject, @Singleton, and @Name are all from the standard javax 
annotations, not from Guice annotations.
   
   ```
     @Inject
     public RMWebServices(final @javax.inject.Named("rm") ResourceManager rm,
         @javax.inject.Named("conf") Configuration conf) {
       // don't inject, always take appBaseRoot from RM.
       super(null);
       this.rm = rm;
       this.conf = conf;
       isCentralizedNodeLabelConfiguration =
           YarnConfiguration.isCentralizedNodeLabelConfiguration(conf);
       this.filterAppsByUser  = conf.getBoolean(
           YarnConfiguration.FILTER_ENTITY_LIST_BY_USER,
           YarnConfiguration.DEFAULT_DISPLAY_APPS_FOR_LOGGED_IN_USER);
         .....
       }
     }
   ```
   
   
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebApp.java
   
   - When the ResourceManager starts, the instances of RM and Conf are directly 
injected into RMWebServices via Jersey2.
   
   ```
     public ResourceConfig resourceConfig() {
       ResourceConfig config = new ResourceConfig();
       config.packages("org.apache.hadoop.yarn.server.resourcemanager.webapp");
       config.register(new JerseyBinder());
       config.register(RMWebServices.class);
       config.register(GenericExceptionHandler.class);
       config.register(new 
JettisonFeature()).register(JAXBContextResolver.class);
       return config;
     }
   
     private class JerseyBinder extends AbstractBinder {
       @Override
       protected void configure() {
         bind(rm).to(ResourceManager.class).named("rm");
         bind(rm.getConfig()).to(Configuration.class).named("conf");
       }
     }
   ```
   
   
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java
   Line 1484-Line 1486
   ```
   try {
         RMWebApp rmWebApp = new RMWebApp(this);
         builder.withResourceConfig(rmWebApp.resourceConfig());
         webApp = builder.start(rmWebApp, uiWebAppContext);
       } catch (WebAppException e) {
         webApp = e.getWebApp();
         throw e;
       }
   ```
   
   Through the steps outlined above, we have injected the required instances 
into the WebServices and the relevant servlets into Jetty. From my perspective, 
this approach is straightforward to understand and involves minimal 
modifications.
   
   Step3.  Refactoring for unit testing.




> Update jersey from 1.19 to 2.x
> ------------------------------
>
>                 Key: HADOOP-15984
>                 URL: https://issues.apache.org/jira/browse/HADOOP-15984
>             Project: Hadoop Common
>          Issue Type: Improvement
>            Reporter: Akira Ajisaka
>            Assignee: Shilun Fan
>            Priority: Major
>              Labels: pull-request-available
>          Time Spent: 2h 10m
>  Remaining Estimate: 0h
>
> jersey-json 1.19 depends on Jackson 1.9.2. Let's upgrade.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to