Skip to content

Commit aedf48a

Browse files
committed
[#1805] feat(spark): Support Spark 4 in client-spark/extension
Spark 4 switched the UI servlet API from javax.servlet (Jetty 9) to jakarta.servlet (Jetty 11+). WebUIPage.render must override its parent signature exactly, so the same .scala file cannot serve both. Route extension through a ServletCompat type alias backed by two version-specific source roots (scala-javax / scala-jakarta). The build-helper-maven-plugin picks one via ${extension.servlet.source.dir}, switched by a spark4 profile in this module's pom that merges with the root pom's spark4 profile. Other changes: - Add client-spark/extension to the root pom's spark4 profile modules. - Add rss-client-spark-ui dependency to client-spark/spark4/pom.xml, mirroring client-spark/spark3/pom.xml. - Bump build-helper-maven-plugin 1.10 -> 3.6.0. - Contributor notes document new-variant and new-spark-version steps, IDE re-import on profile switch, and ~/.m2 hygiene. Verified: extension compiles cleanly under spark3 / spark3.0 / spark3.2 / spark3.2.0 / spark3.3 / spark3.4 / spark3.5 / spark4 profiles.
1 parent c18774d commit aedf48a

6 files changed

Lines changed: 160 additions & 2 deletions

File tree

client-spark/extension/pom.xml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,56 @@
3333
<packaging>jar</packaging>
3434
<name>Apache Uniffle Client spark ui</name>
3535

36+
<!--
37+
Servlet API compatibility across Spark versions.
38+
39+
Spark 3.x and earlier depend on javax.servlet (Jetty 9 era).
40+
Spark 4.x switched to jakarta.servlet (Jetty 11+ era).
41+
These APIs cannot coexist in one .scala file because Spark's
42+
WebUIPage.render(request) must override the parent signature exactly.
43+
44+
Strategy: a pair of version-specific source roots, each exposing the
45+
same alias `org.apache.spark.ui.ServletCompat.HttpServletRequest`
46+
pointing to the appropriate underlying class. The active profile
47+
selects one via ${extension.servlet.source.dir}. The javax variant is
48+
the module-level default; profiles override it when needed.
49+
50+
To add support for a new Spark major version:
51+
1. If it reuses an existing servlet variant (javax or jakarta),
52+
add the new spark profile to the root pom.xml, then add a
53+
matching <profile> with the same id here in this module's pom
54+
whose <properties> sets ${extension.servlet.source.dir} to the
55+
matching scala-* directory. Maven merges same-id profiles, so
56+
both activate together under -P<new-id>. The javax variant is
57+
already the default, so reusing it needs no profile override
58+
(for example, all existing spark3.* profiles in the root pom
59+
use the javax default without a matching profile in this pom).
60+
2. If it introduces a new servlet variant, create a new source root
61+
`src/main/scala-<variant>` with a mirrored ServletCompat (same
62+
aliases, different underlying types), then follow step 1.
63+
3. Keep every scala-* variant of ServletCompat.scala in sync: every
64+
alias must exist in every variant; only the underlying package
65+
may differ.
66+
67+
Notes for contributors:
68+
* When an IDE (IntelliJ IDEA, VSCode) is told to activate a
69+
different spark profile, re-import the project so the selected
70+
scala-* source root is re-resolved.
71+
* `rss-client-spark-ui` is published under a single Maven coordinate
72+
regardless of profile, but different profiles produce incompatible
73+
bytecode (servlet variant and Scala binary version both differ).
74+
Do not leave jars from different profiles mixed in your local
75+
`~/.m2` cache; run `mvn clean` when switching profiles. Publishing
76+
more than one profile's build to the same coordinate in a remote
77+
repository is not supported by this module; artifact partitioning
78+
(classifier or profile-specific artifactId) is out of scope here.
79+
-->
80+
<properties>
81+
<!-- Default: javax.servlet variant (Spark 2.x / 3.x).
82+
Overridden by the local `spark4` profile below. -->
83+
<extension.servlet.source.dir>src/main/scala-javax</extension.servlet.source.dir>
84+
</properties>
85+
3686
<dependencies>
3787
<dependency>
3888
<groupId>org.apache.uniffle</groupId>
@@ -72,6 +122,24 @@
72122

73123
<build>
74124
<plugins>
125+
<plugin>
126+
<groupId>org.codehaus.mojo</groupId>
127+
<artifactId>build-helper-maven-plugin</artifactId>
128+
<executions>
129+
<execution>
130+
<id>add-servlet-compat-source</id>
131+
<phase>generate-sources</phase>
132+
<goals>
133+
<goal>add-source</goal>
134+
</goals>
135+
<configuration>
136+
<sources>
137+
<source>${extension.servlet.source.dir}</source>
138+
</sources>
139+
</configuration>
140+
</execution>
141+
</executions>
142+
</plugin>
75143
<plugin>
76144
<groupId>net.alchim31.maven</groupId>
77145
<artifactId>scala-maven-plugin</artifactId>
@@ -90,4 +158,20 @@
90158
</plugin>
91159
</plugins>
92160
</build>
161+
162+
<profiles>
163+
<profile>
164+
<!--
165+
This profile shares its id with the root pom's `spark4` profile.
166+
Maven merges same-id profiles across the reactor, so activating
167+
`-Pspark4` triggers both. This module only contributes the
168+
source-dir override so that Spark 4 builds pick up the
169+
jakarta.servlet variant of ServletCompat.
170+
-->
171+
<id>spark4</id>
172+
<properties>
173+
<extension.servlet.source.dir>src/main/scala-jakarta</extension.servlet.source.dir>
174+
</properties>
175+
</profile>
176+
</profiles>
93177
</project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.spark.ui
19+
20+
// Servlet type aliases for Spark 4.x (jakarta.servlet variant).
21+
// Selected by build-helper-maven-plugin via ${extension.servlet.source.dir}
22+
// when the spark4 profile is active; see client-spark/extension/pom.xml.
23+
//
24+
// Usage: `import ServletCompat.HttpServletRequest`, then reference the bare
25+
// `HttpServletRequest` symbol. Callers must reside in package
26+
// `org.apache.spark.ui` because the object is `private[ui]`.
27+
//
28+
// IMPORTANT: this file must stay in sync with every other ServletCompat.scala
29+
// under src/main/scala-*. Every alias must exist in every variant; only the
30+
// underlying servlet package may differ. When adding or renaming an alias
31+
// here, make the same change in every other variant.
32+
private[ui] object ServletCompat {
33+
type HttpServletRequest = jakarta.servlet.http.HttpServletRequest
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.spark.ui
19+
20+
// Servlet type aliases for Spark 2.x / 3.x (javax.servlet variant).
21+
// Selected by build-helper-maven-plugin via ${extension.servlet.source.dir}
22+
// when the spark4 profile is not active; see client-spark/extension/pom.xml.
23+
//
24+
// Usage: `import ServletCompat.HttpServletRequest`, then reference the bare
25+
// `HttpServletRequest` symbol. Callers must reside in package
26+
// `org.apache.spark.ui` because the object is `private[ui]`.
27+
//
28+
// IMPORTANT: this file must stay in sync with every other ServletCompat.scala
29+
// under src/main/scala-*. Every alias must exist in every variant; only the
30+
// underlying servlet package may differ. When adding or renaming an alias
31+
// here, make the same change in every other variant.
32+
private[ui] object ServletCompat {
33+
type HttpServletRequest = javax.servlet.http.HttpServletRequest
34+
}

client-spark/extension/src/main/scala/org/apache/spark/ui/ShufflePage.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
package org.apache.spark.ui
1919

2020
import org.apache.spark.internal.Logging
21+
import org.apache.spark.ui.ServletCompat.HttpServletRequest
2122
import org.apache.spark.util.Utils
2223
import org.apache.spark.{AggregatedShuffleMetric, AggregatedShuffleReadMetric, AggregatedShuffleWriteMetric, AggregatedTaskInfoUIData, ShuffleType}
2324

2425
import java.util.concurrent.ConcurrentHashMap
25-
import javax.servlet.http.HttpServletRequest
2626
import scala.collection.JavaConverters.{collectionAsScalaIterableConverter, mapAsScalaMapConverter}
2727
import scala.xml.{Node, NodeSeq}
2828

client-spark/spark4/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@
5959
<artifactId>rss-client-spark-common</artifactId>
6060
<version>${project.version}</version>
6161
</dependency>
62+
<dependency>
63+
<groupId>org.apache.uniffle</groupId>
64+
<artifactId>rss-client-spark-ui</artifactId>
65+
<version>${project.version}</version>
66+
</dependency>
6267
<dependency>
6368
<groupId>io.netty</groupId>
6469
<artifactId>netty-all</artifactId>

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@
945945
<plugin>
946946
<groupId>org.codehaus.mojo</groupId>
947947
<artifactId>build-helper-maven-plugin</artifactId>
948-
<version>1.10</version>
948+
<version>3.6.0</version>
949949
</plugin>
950950
<plugin>
951951
<groupId>org.codehaus.mojo</groupId>
@@ -2008,6 +2008,7 @@
20082008
<module>client-spark/spark4-shaded</module>
20092009
<module>integration-test/spark-common</module>
20102010
<module>integration-test/spark4</module>
2011+
<module>client-spark/extension</module>
20112012
</modules>
20122013
<dependencyManagement>
20132014
<dependencies>

0 commit comments

Comments
 (0)