Skip to content

Commit 8e929ac

Browse files
committed
HSEARCH-5356 Introduce the extended (platform) BOM
1 parent fcffca0 commit 8e929ac

File tree

8 files changed

+994
-27
lines changed

8 files changed

+994
-27
lines changed

bom/platform-next/pom.xml

Lines changed: 360 additions & 0 deletions
Large diffs are not rendered by default.

bom/platform/pom.xml

Lines changed: 355 additions & 0 deletions
Large diffs are not rendered by default.

build/enforcer/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
</properties>
3333

3434
<dependencies>
35+
<dependency>
36+
<groupId>com.google.code.gson</groupId>
37+
<artifactId>gson</artifactId>
38+
</dependency>
3539
<dependency>
3640
<groupId>org.apache.maven.enforcer</groupId>
3741
<artifactId>enforcer-api</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.search.build.enforcer;
6+
7+
import java.io.IOException;
8+
import java.io.InputStreamReader;
9+
import java.net.URI;
10+
import java.net.URLEncoder;
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.ArrayList;
13+
import java.util.HashSet;
14+
import java.util.List;
15+
import java.util.Locale;
16+
import java.util.Set;
17+
import java.util.concurrent.TimeUnit;
18+
import java.util.stream.Collectors;
19+
20+
import javax.inject.Inject;
21+
import javax.inject.Named;
22+
23+
import com.google.gson.Gson;
24+
import com.google.gson.GsonBuilder;
25+
import com.google.gson.stream.JsonReader;
26+
27+
import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
28+
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
29+
import org.apache.maven.execution.MavenSession;
30+
import org.apache.maven.model.Dependency;
31+
32+
@Named("dependencyManagementIncludesAllGroupIdArtifactsRule") // rule name - must start with lowercase character
33+
public class DependencyManagementIncludesAllGroupIdArtifactsRule extends AbstractEnforcerRule {
34+
/**
35+
* See <a href="https://central.sonatype.org/search/rest-api-guide/">Maven Central REST API</a>
36+
*/
37+
private static final String BASE_URL_FORMAT =
38+
"https://search.maven.org/solrsearch/select?q=%s&core=gav&start=%d&rows=%d&wt=json";
39+
private static final int ROWS_PER_PAGE = 100;
40+
private static final int MAX_RETRIES = 5;
41+
private static final int RETRY_DELAY_SECONDS = 2;
42+
43+
44+
// Inject needed Maven components
45+
@Inject
46+
private MavenSession session;
47+
48+
/**
49+
* Rule parameter as list of items.
50+
*/
51+
private Set<Dependency> includedDependencyFilters = new HashSet<>();
52+
53+
/**
54+
* Rule parameter as list of items.
55+
*/
56+
private Set<Dependency> dependenciesToSkip = new HashSet<>();
57+
58+
public void execute() throws EnforcerRuleException {
59+
Set<String> dependencies = session.getCurrentProject()
60+
.getDependencyManagement()
61+
.getDependencies()
62+
.stream()
63+
.map( d -> String.format( Locale.ROOT, "%s:%s:%s", d.getGroupId(), d.getArtifactId(), d.getVersion() ) )
64+
.collect( Collectors.toSet() );
65+
Set<String> skip = dependenciesToSkip.stream()
66+
.map( d -> String.format( Locale.ROOT, "%s:%s:%s", d.getGroupId(), d.getArtifactId(), d.getVersion() ) )
67+
.collect( Collectors.toSet() );
68+
69+
final Gson gson = new GsonBuilder().create();
70+
Set<Artifact> foundArtifacts = new HashSet<>();
71+
72+
for ( Dependency filter : includedDependencyFilters ) {
73+
StringBuilder queryBuilder = new StringBuilder();
74+
queryBuilder.append( "g:" ).append( encodeValue( filter.getGroupId() ) );
75+
76+
if ( filter.getArtifactId() != null && !filter.getArtifactId().trim().isEmpty() ) {
77+
queryBuilder.append( "+AND+a:" ).append( encodeValue( filter.getArtifactId() ) );
78+
}
79+
if ( filter.getVersion() != null && !filter.getVersion().trim().isEmpty() ) {
80+
queryBuilder.append( "+AND+v:" ).append( encodeValue( filter.getVersion() ) );
81+
}
82+
83+
84+
int start = 0;
85+
do {
86+
String url = String.format( Locale.ROOT, BASE_URL_FORMAT, queryBuilder, start, ROWS_PER_PAGE );
87+
SearchResponse response = fetch( gson, url );
88+
foundArtifacts.addAll( response.response.docs );
89+
if ( response.response.start + response.response.docs.size() >= response.response.numFound ) {
90+
break;
91+
}
92+
}
93+
while ( true );
94+
}
95+
96+
List<String> problems = new ArrayList<>();
97+
for ( Artifact artifact : foundArtifacts ) {
98+
String toCheck = artifact.formattedString();
99+
if ( skip.contains( toCheck ) ) {
100+
continue;
101+
}
102+
if ( !dependencies.remove( toCheck ) ) {
103+
// The artifact is NOT in the dependencies
104+
problems.add( "`" + toCheck + "` is missing from the dependency management section" );
105+
}
106+
}
107+
108+
if ( !problems.isEmpty() ) {
109+
throw new EnforcerRuleException( String.join( ";\n", problems ) );
110+
}
111+
}
112+
113+
private SearchResponse fetch(Gson gson, String url) throws EnforcerRuleException {
114+
for ( int i = 0; i < MAX_RETRIES; i++ ) {
115+
try (
116+
var stream = URI.create( url ).toURL().openStream(); var isr = new InputStreamReader( stream );
117+
var reader = new JsonReader( isr )
118+
) {
119+
getLog().info( "Fetching included artifacts from " + url );
120+
return gson.fromJson( reader, SearchResponse.class );
121+
}
122+
catch (IOException e) {
123+
getLog().warn( "Fetching artifacts from " + url + " failed Retrying in " + RETRY_DELAY_SECONDS
124+
+ "s... (Attempt " + ( i + 1 ) + "/" + ( MAX_RETRIES ) + "): " + e.getMessage() );
125+
try {
126+
TimeUnit.SECONDS.sleep( RETRY_DELAY_SECONDS );
127+
}
128+
catch (InterruptedException ie) {
129+
Thread.currentThread().interrupt();
130+
throw new EnforcerRuleException( ie );
131+
}
132+
}
133+
}
134+
throw new EnforcerRuleException(
135+
"Fetching the artifacts from " + url + " failed after " + ( MAX_RETRIES ) + " attempts." );
136+
}
137+
138+
private String encodeValue(String value) {
139+
return URLEncoder.encode( value, StandardCharsets.UTF_8 );
140+
}
141+
142+
private static class Artifact {
143+
String g;
144+
String a;
145+
String v;
146+
147+
public String formattedString() {
148+
return String.format( Locale.ROOT, "%s:%s:%s", g, a, v );
149+
}
150+
}
151+
152+
private static class SearchResponse {
153+
ResponseData response;
154+
}
155+
156+
public static class ResponseData {
157+
int numFound;
158+
int start;
159+
List<Artifact> docs;
160+
}
161+
}

build/parents/build/pom.xml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,15 @@
3838
Also make sure to update Javadocs for RewriteMethod.
3939
-->
4040
<version.org.apache.lucene>9.12.2</version.org.apache.lucene>
41+
<version.org.apache.lucene.next>10.2.2</version.org.apache.lucene.next>
4142
<javadoc.org.apache.lucene.tag>${parsed-version.org.apache.lucene.majorVersion}_${parsed-version.org.apache.lucene.minorVersion}_${parsed-version.org.apache.lucene.incrementalVersion}</javadoc.org.apache.lucene.tag>
4243
<javadoc.org.apache.lucene.core.url>https://lucene.apache.org/core/${javadoc.org.apache.lucene.tag}/core/</javadoc.org.apache.lucene.core.url>
4344
<javadoc.org.apache.lucene.analysis.common.url>https://lucene.apache.org/core/${javadoc.org.apache.lucene.tag}/analysis/common/</javadoc.org.apache.lucene.analysis.common.url>
4445
<javadoc.org.apache.lucene.queryparser.url>https://lucene.apache.org/core/${javadoc.org.apache.lucene.tag}/queryparser/</javadoc.org.apache.lucene.queryparser.url>
4546

4647
<version.com.carrotsearch.hppc>0.10.0</version.com.carrotsearch.hppc>
47-
<version.org.apache.lucene.next>10.2.2</version.org.apache.lucene.next>
4848

4949
<!-- >>> Elasticsearch -->
50-
<!-- The version of the Elasticsearch client used by Hibernate Search, independently of the version of the remote cluster -->
51-
<!-- Use the latest open-source version here. Currently, low-level clients are open-source even in 8.5+ -->
52-
<version.org.elasticsearch.client>9.0.3</version.org.elasticsearch.client>
5350
<!-- The main compatible version of Elasticsearch, advertised by default. Used in documentation links. -->
5451
<version.org.elasticsearch.compatible.main>${version.org.elasticsearch.latest}</version.org.elasticsearch.compatible.main>
5552
<documentation.org.elasticsearch.url>https://www.elastic.co/guide/en/elasticsearch/reference/${parsed-version.org.elasticsearch.compatible.main.majorVersion}.${parsed-version.org.elasticsearch.compatible.main.minorVersion}</documentation.org.elasticsearch.url>

documentation/src/main/asciidoc/public/reference/_compatibility.adoc

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,35 @@ https://hibernate.org/search/releases/#compatibility-matrix[compatibility matrix
3939
The https://hibernate.org/community/compatibility-policy/[compatibility policy] may also be of interest.
4040
====
4141

42-
[TIP]
42+
[NOTE]
43+
.Elasticsearch licensing
4344
====
45+
While Elasticsearch up to 7.10 was distributed under the Apache License 2.0,
46+
be aware that Elasticsearch 7.11-8.15 versions are distributed under the Elastic License and the SSPL,
47+
which are https://opensource.org/node/1099[not considered open-source by the Open Source Initiative].
48+
Starting with Elasticsearch 8.16 the AGPL v3 license was added.
49+
Please refer to https://www.elastic.co/ to learn more on the licensing of Elasticsearch.
50+
51+
Only the low-level Java REST client, which Hibernate Search depends on, remains open-source.
52+
====
53+
54+
[NOTE]
55+
.OpenSearch
56+
====
57+
While it historically targeted link:{elasticsearchUrl}[Elastic's Elasticsearch distribution],
58+
Hibernate Search is also compatible with link:{openSearchUrl}[OpenSearch] and regularly tested against it;
59+
see <<backend-elasticsearch-compatibility>> for more information.
60+
61+
Every section of this documentation referring to Elasticsearch
62+
is also relevant for the OpenSearch distribution.
63+
====
64+
65+
[[compatibility-search-dependencies]]
66+
=== Adding Hibernate Search dependencies to your project
67+
68+
[[compatibility-search-dependencies-bom]]
69+
==== Hibernate Search BOM
70+
4471
If you get Hibernate Search from Maven, it is recommended to import Hibernate Search BOM
4572
as part of your dependency management to keep all its artifact versions aligned:
4673
[source, XML, subs="+attributes"]
@@ -62,30 +89,69 @@ as part of your dependency management to keep all its artifact versions aligned:
6289
</dependencies>
6390
</dependencyManagement>
6491
----
65-
====
6692

67-
[NOTE]
68-
.Elasticsearch licensing
69-
====
70-
While Elasticsearch up to 7.10 was distributed under the Apache License 2.0,
71-
be aware that Elasticsearch 7.11-8.15 versions are distributed under the Elastic License and the SSPL,
72-
which are https://opensource.org/node/1099[not considered open-source by the Open Source Initiative].
73-
Starting with Elasticsearch 8.16 the AGPL v3 license was added.
74-
Please refer to https://www.elastic.co/ to learn more on the licensing of Elasticsearch.
93+
[[compatibility-search-dependencies-platform]]
94+
==== Hibernate Search Platform
7595

76-
Only the low-level Java REST client, which Hibernate Search depends on, remains open-source.
77-
====
96+
include::../components/_incubating-warning.adoc[]
7897

79-
[NOTE]
80-
.OpenSearch
81-
====
82-
While it historically targeted link:{elasticsearchUrl}[Elastic's Elasticsearch distribution],
83-
Hibernate Search is also compatible with link:{openSearchUrl}[OpenSearch] and regularly tested against it;
84-
see <<backend-elasticsearch-compatibility>> for more information.
98+
Besides the lean BOM file, Hibernate Search also provides several platform POM files that mange
99+
dependencies that are not directly used by Hibernate Search but are related.
100+
For example, it brings the management of all other `org.hibernate.orm` artifacts,
101+
beyond the ones required by the <<mapper-orm,ORM mapper>>, or extra Lucene artifacts like
102+
`lucene-suggest` or `lucene-analysis-icu` and others, that can be helpful for more advanced applications.
103+
These platform files will help keep the versions of extra Hibernate ORM/Lucene/Elasticsearch client dependencies
104+
aligned with the versions of artifacts from the same groups that are used by Hibernate Search itself.
85105

86-
Every section of this documentation referring to Elasticsearch
87-
is also relevant for the OpenSearch distribution.
88-
====
106+
Currently, there are two platform POM files provided, to account for the <<other-integrations-lucene-next>> backend:
107+
108+
* `hibernate-search-platform` that manages versions of published artifacts that belong to the following group ids:
109+
- `org.hibernate.search` for the {hibernateSearchVersion} version of Hibernate Search;
110+
- `org.hibernate.orm` for the {hibernateVersion} version of Hibernate ORM;
111+
- `org.apache.lucene` for the {luceneVersion} version of Lucene;
112+
- `org.elasticsearch.client` for the {elasticsearchClientVersions} version of the Elasticsearch client;
113+
* `hibernate-search-platform-next` that manages versions of published artifacts that belong to the following group ids:
114+
- `org.hibernate.search` for the {hibernateSearchVersion} version of Hibernate Search;
115+
- `org.hibernate.orm` for the {hibernateVersion} version of Hibernate ORM;
116+
- `org.apache.lucene` for the {luceneNextVersion} version of Lucene;
117+
- `org.elasticsearch.client` for the {elasticsearchClientVersions} version of the Elasticsearch client;
118+
119+
To leverage the dependency management provided by these platform files, use the same approach of importing as for
120+
the <<compatibility-search-dependencies-bom,regular BOM>> file:
121+
122+
.Importing the Hibernate Search platform
123+
[source, XML, subs="+attributes"]
124+
----
125+
<dependencyManagement>
126+
<dependencies>
127+
<!--
128+
Import Hibernate Search platform
129+
to get all of its artifact versions aligned:
130+
-->
131+
<dependency>
132+
<groupId>org.hibernate.search</groupId>
133+
<artifactId>hibernate-search-platform</artifactId>
134+
<version>{hibernateSearchVersion}</version>
135+
<type>pom</type>
136+
<scope>import</scope>
137+
</dependency>
138+
<!-- Any other dependency management entries -->
139+
</dependencies>
140+
</dependencyManagement>
141+
142+
<dependencies>
143+
<!-- Any other dependency management entries -->
144+
<!--
145+
For example, add an extra Lucene dependency without specifying the version
146+
as it is managed by the platform POM:
147+
-->
148+
<dependency>
149+
<groupId>org.apache.lucene</groupId>
150+
<artifactId>lucene-suggest</artifactId>
151+
</dependency>
152+
<!-- Any other dependency management entries -->
153+
</dependencies>
154+
----
89155

90156
[[compatibility-framework]]
91157
== [[gettingstarted-framework]] Framework support
@@ -183,7 +249,7 @@ or by explicitly listing a dependency with its version that we want to be used:
183249
<dependency>
184250
<groupId>org.hibernate.orm</groupId>
185251
<artifactId>hibernate-platform</artifactId>
186-
<version>${version.org.hibernate.orm}</version>
252+
<version>{hibernateVersion}</version>
187253
<type>pom</type>
188254
<scope>import</scope>
189255
</dependency>

engine/src/main/java/org/hibernate/search/engine/search/common/RewriteMethod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* For more details on rewrite methods, and in particular which options are allowed, see the backend specific documentation, e.g.
1919
* Elasticsearch <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-term-rewrite.html">rewrite parameters page</a>,
2020
* OpenSearch <a href="https://opensearch.org/docs/latest/query-dsl/full-text/query-string/#parameters">query string parameters table</a>
21-
* or Lucene <a href="https://lucene.apache.org/core/9_9_2/core/org/apache/lucene/search/MultiTermQuery.html">MultiTermQuery</a>.
21+
* or Lucene <a href="https://lucene.apache.org/core/9_12_2/core/org/apache/lucene/search/MultiTermQuery.html">MultiTermQuery</a>.
2222
*/
2323
public enum RewriteMethod {
2424

pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@
158158

159159
<modules>
160160
<module>bom/public</module>
161+
<module>bom/platform</module>
162+
<module>bom/platform-next</module>
161163
<module>build/parents/relocation</module>
162164
<module>build/parents/build</module>
163165
<module>build/enforcer</module>
@@ -315,6 +317,28 @@
315317
<version.spotless-maven-plugin>2.45.0</version.spotless-maven-plugin>
316318
<version.maven-antrun-plugin>3.1.0</version.maven-antrun-plugin>
317319

320+
<!-- >>> Version of dependencies that we need to keep in the root to share between build and "bom" pom files -->
321+
<!-- >>> ORM 7 with Jakarta Persistence -->
322+
<!-- IMPORTANT: Make sure that version.jakarta.persistence aligns with the imported version! -->
323+
<!--
324+
NOTE: when Hibernate ORM updates Byte Buddy, make sure to check Jenkinsfile to see if
325+
`net.bytebuddy.experimental` property can be removed.
326+
-->
327+
<version.org.hibernate.orm>7.0.6.Final</version.org.hibernate.orm>
328+
<!-- >>> Lucene -->
329+
<!--
330+
When upgrading Lucene, check HibernateSearchKnnVectorsFormat to see if its internals should be updated too.
331+
In particular if a delegating Lucene99HnswVectorsFormat should be changed to a different version.
332+
333+
Also make sure to update Javadocs for RewriteMethod.
334+
-->
335+
<version.org.apache.lucene>9.12.2</version.org.apache.lucene>
336+
<version.org.apache.lucene.next>10.2.2</version.org.apache.lucene.next>
337+
<!-- >>> Elasticsearch -->
338+
<!-- The version of the Elasticsearch client used by Hibernate Search, independently of the version of the remote cluster -->
339+
<!-- Use the latest open-source version here. Currently, low-level clients are open-source even in 8.5+ -->
340+
<version.org.elasticsearch.client>9.0.3</version.org.elasticsearch.client>
341+
318342
<!-- Repository Deployment URLs -->
319343

320344
<!-- We always publish to a local directory, JReleaser is supposed to take care of publishing to Nexus: -->

0 commit comments

Comments
 (0)