Skip to content

Commit 19640da

Browse files
Dmitriy FingermanDmitriy Fingerman
authored andcommitted
HIVE-29468: Standalone HMS REST Catalog Server: Migrate to Spring Boot
1 parent 89631dc commit 19640da

11 files changed

Lines changed: 636 additions & 259 deletions

File tree

itests/hive-iceberg/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@
5151
<version>${keycloak.version}</version>
5252
<scope>test</scope>
5353
</dependency>
54+
<dependency>
55+
<groupId>jakarta.annotation</groupId>
56+
<artifactId>jakarta.annotation-api</artifactId>
57+
<version>${jakarta.annotation.version}</version>
58+
<scope>test</scope>
59+
</dependency>
5460
<dependency>
5561
<groupId>org.apache.hive</groupId>
5662
<artifactId>hive-standalone-metastore-common</artifactId>

itests/qtest-iceberg/pom.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,27 @@
475475
<version>${project.version}</version>
476476
<scope>test</scope>
477477
</dependency>
478+
<!-- Spring Boot test dependencies -->
479+
<dependency>
480+
<groupId>org.springframework.boot</groupId>
481+
<artifactId>spring-boot-starter-test</artifactId>
482+
<version>${spring-boot.version}</version>
483+
<scope>test</scope>
484+
<exclusions>
485+
<exclusion>
486+
<groupId>org.springframework.boot</groupId>
487+
<artifactId>spring-boot-starter-logging</artifactId>
488+
</exclusion>
489+
<exclusion>
490+
<groupId>org.junit.jupiter</groupId>
491+
<artifactId>junit-jupiter</artifactId>
492+
</exclusion>
493+
<exclusion>
494+
<groupId>org.junit.vintage</groupId>
495+
<artifactId>junit-vintage-engine</artifactId>
496+
</exclusion>
497+
</exclusions>
498+
</dependency>
478499
<dependency>
479500
<groupId>org.testcontainers</groupId>
480501
<artifactId>testcontainers</artifactId>

itests/qtest-iceberg/src/test/java/org/apache/hadoop/hive/cli/TestStandaloneRESTCatalogServer.java

Lines changed: 219 additions & 151 deletions
Large diffs are not rendered by default.

packaging/pom.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@
184184
<MIT>
185185
https?://(www\.)?opensource\.org/licenses/mit(-license.php)?
186186
</MIT>
187+
<public-domain-1.0.html>
188+
https?://creativecommons\.org/publicdomain/zero/1\.0/?
189+
</public-domain-1.0.html>
187190
</licenseUrlFileNames>
188191
<licenseUrlFileNameSanitizers>
189192
<licenseUrlFileNameSanitizer>

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,15 @@
228228
<rs-api.version>2.0.1</rs-api.version>
229229
<json-path.version>2.9.0</json-path.version>
230230
<janino.version>3.1.12</janino.version>
231+
<jakarta.annotation.version>2.1.1</jakarta.annotation.version>
231232
<datasketches.version>2.0.0</datasketches.version>
232233
<spotbugs.version>4.8.6</spotbugs.version>
233234
<validation-api.version>1.1.0.Final</validation-api.version>
234235
<aws-secretsmanager-caching.version>2.1.1</aws-secretsmanager-caching.version>
235236
<jansi.version>2.4.0</jansi.version>
236237
<!-- If upgrading, upgrade atlas as well in ql/pom.xml, which brings in some springframework dependencies transitively -->
237238
<spring.version>5.3.39</spring.version>
239+
<spring-boot.version>2.7.18</spring-boot.version>
238240
<spring.ldap.version>2.4.4</spring.ldap.version>
239241
<project.build.outputTimestamp>2025-01-01T00:00:00Z</project.build.outputTimestamp>
240242
<keycloak.version>26.0.6</keycloak.version>

standalone-metastore/metastore-rest-catalog/pom.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,34 @@
4242
<artifactId>hive-iceberg-catalog</artifactId>
4343
<version>${hive.version}</version>
4444
</dependency>
45+
<!-- Spring Boot dependencies - use Jetty instead of Tomcat for Java 21 compatibility -->
46+
<dependency>
47+
<groupId>org.springframework.boot</groupId>
48+
<artifactId>spring-boot-starter-web</artifactId>
49+
<exclusions>
50+
<exclusion>
51+
<groupId>org.springframework.boot</groupId>
52+
<artifactId>spring-boot-starter-logging</artifactId>
53+
</exclusion>
54+
<exclusion>
55+
<groupId>org.springframework.boot</groupId>
56+
<artifactId>spring-boot-starter-tomcat</artifactId>
57+
</exclusion>
58+
</exclusions>
59+
</dependency>
60+
<dependency>
61+
<groupId>org.springframework.boot</groupId>
62+
<artifactId>spring-boot-starter-jetty</artifactId>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.springframework.boot</groupId>
66+
<artifactId>spring-boot-starter-actuator</artifactId>
67+
</dependency>
68+
<dependency>
69+
<groupId>io.micrometer</groupId>
70+
<artifactId>micrometer-registry-prometheus</artifactId>
71+
<version>1.9.17</version>
72+
</dependency>
4573
<!-- Test dependencies -->
4674
<dependency>
4775
<groupId>org.apache.hive</groupId>
@@ -236,6 +264,13 @@
236264
<artifactId>keycloak-admin-client</artifactId>
237265
<scope>test</scope>
238266
</dependency>
267+
<!-- Required by keycloak-admin-client/Resteasy for jakarta.annotation.Priority -->
268+
<dependency>
269+
<groupId>jakarta.annotation</groupId>
270+
<artifactId>jakarta.annotation-api</artifactId>
271+
<version>${jakarta.annotation.version}</version>
272+
<scope>test</scope>
273+
</dependency>
239274
<dependency>
240275
<groupId>org.testcontainers</groupId>
241276
<artifactId>testcontainers</artifactId>
@@ -303,6 +338,22 @@
303338
</execution>
304339
</executions>
305340
</plugin>
341+
<plugin>
342+
<groupId>org.springframework.boot</groupId>
343+
<artifactId>spring-boot-maven-plugin</artifactId>
344+
<version>${spring-boot.version}</version>
345+
<configuration>
346+
<mainClass>org.apache.iceberg.rest.standalone.StandaloneRESTCatalogServer</mainClass>
347+
<classifier>exec</classifier>
348+
</configuration>
349+
<executions>
350+
<execution>
351+
<goals>
352+
<goal>repackage</goal>
353+
</goals>
354+
</execution>
355+
</executions>
356+
</plugin>
306357
</plugins>
307358
</build>
308359
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.iceberg.rest.standalone;
19+
20+
import javax.servlet.http.HttpServlet;
21+
22+
import org.apache.hadoop.conf.Configuration;
23+
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
24+
import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
25+
import org.apache.iceberg.rest.HMSCatalogFactory;
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
import org.springframework.boot.web.servlet.ServletRegistrationBean;
29+
import org.springframework.context.annotation.Bean;
30+
31+
/**
32+
* Spring configuration for the Iceberg REST Catalog servlet.
33+
* Extracted to separate concerns from the main application bootstrap.
34+
*/
35+
@org.springframework.context.annotation.Configuration
36+
public class IcebergCatalogConfiguration {
37+
private static final Logger LOG = LoggerFactory.getLogger(IcebergCatalogConfiguration.class);
38+
39+
private final Configuration conf;
40+
41+
public IcebergCatalogConfiguration(Configuration conf) {
42+
this.conf = conf;
43+
}
44+
45+
@Bean
46+
public ServletRegistrationBean<HttpServlet> restCatalogServlet() {
47+
// Determine servlet path and port
48+
String servletPath = MetastoreConf.getVar(conf, ConfVars.ICEBERG_CATALOG_SERVLET_PATH);
49+
if (servletPath == null || servletPath.isEmpty()) {
50+
servletPath = "iceberg";
51+
MetastoreConf.setVar(conf, ConfVars.ICEBERG_CATALOG_SERVLET_PATH, servletPath);
52+
}
53+
54+
int port = MetastoreConf.getIntVar(conf, ConfVars.CATALOG_SERVLET_PORT);
55+
if (port == 0) {
56+
port = 8080;
57+
MetastoreConf.setLongVar(conf, ConfVars.CATALOG_SERVLET_PORT, port);
58+
}
59+
60+
LOG.info("Creating REST Catalog servlet at /{}", servletPath);
61+
62+
// Create servlet from Iceberg factory
63+
org.apache.hadoop.hive.metastore.ServletServerBuilder.Descriptor descriptor =
64+
HMSCatalogFactory.createServlet(conf);
65+
if (descriptor == null || descriptor.getServlet() == null) {
66+
throw new IllegalStateException("Failed to create Iceberg REST Catalog servlet");
67+
}
68+
69+
ServletRegistrationBean<HttpServlet> registration =
70+
new ServletRegistrationBean<>(descriptor.getServlet(), "/" + servletPath + "/*");
71+
registration.setName("IcebergRESTCatalog");
72+
registration.setLoadOnStartup(1);
73+
74+
return registration;
75+
}
76+
}

0 commit comments

Comments
 (0)