From d2c98912eb224e3ee8ba65914ccf138f25b75f69 Mon Sep 17 00:00:00 2001 From: Dawid Weiss Date: Sun, 19 Dec 2021 08:51:13 +0100 Subject: [PATCH] This reverts commit a7b50f723d6c6249faa688a1a4423cc4006d37dd. --- build.gradle | 9 +- gradle/documentation/render-javadoc.gradle | 62 ++-- gradle/ide/eclipse.gradle | 6 +- gradle/ide/intellij-idea.gradle | 2 +- gradle/java/jar-manifest.gradle | 32 -- gradle/java/javac.gradle | 3 +- gradle/java/modules-debugging.gradle | 84 +++++ gradle/java/modules.gradle | 254 +++++++++++++++ gradle/maven/publications.gradle | 10 +- gradle/testing/randomization.gradle | 4 +- gradle/validation/ecj-lint.gradle | 60 +++- gradle/validation/ecj-lint/ecj.javadocs.prefs | 8 +- lucene/CHANGES.txt | 3 + lucene/analysis/common/build.gradle | 2 +- .../analysis/common/src/java/module-info.java | 222 +++++++++++++ lucene/analysis/icu/build.gradle | 6 +- lucene/analysis/icu/src/java/module-info.java | 37 +++ lucene/analysis/kuromoji/build.gradle | 4 +- .../kuromoji/src/java/module-info.java | 40 +++ lucene/analysis/morfologik.tests/build.gradle | 28 ++ .../src/test/module-info.java | 27 ++ .../tests/TestMorfologikAnalyzer.java | 47 +++ lucene/analysis/morfologik/build.gradle | 11 +- .../morfologik/src/java/module-info.java | 32 ++ .../uk/UkrainianMorfologikAnalyzer.java | 102 +++--- lucene/analysis/nori/build.gradle | 4 +- .../analysis/nori/src/java/module-info.java | 33 ++ lucene/analysis/opennlp/build.gradle | 6 +- .../opennlp/src/java/module-info.java | 34 ++ lucene/analysis/phonetic/build.gradle | 6 +- .../phonetic/src/java/module-info.java | 31 ++ lucene/analysis/smartcn/build.gradle | 4 +- .../smartcn/src/java/module-info.java | 28 ++ lucene/analysis/stempel/build.gradle | 4 +- .../stempel/src/java/module-info.java | 29 ++ lucene/backward-codecs/build.gradle | 4 +- .../backward-codecs/src/java/module-info.java | 45 +++ lucene/benchmark/build.gradle | 24 +- lucene/benchmark/src/java/module-info.java | 40 +++ lucene/classification/build.gradle | 6 +- .../classification/src/java/module-info.java | 27 ++ lucene/codecs/build.gradle | 2 +- lucene/codecs/src/java/module-info.java | 39 +++ lucene/core/src/java/module-info.java | 72 +++++ lucene/demo/build.gradle | 12 +- lucene/demo/src/java/module-info.java | 30 ++ lucene/distribution.tests/build.gradle | 62 ++++ .../lucene/distribution/TestModularLayer.java | 295 ++++++++++++++++++ lucene/distribution/binary-release.gradle | 59 +++- .../src/binary-release/bin/luke.cmd | 2 +- .../src/binary-release/bin/luke.sh | 2 +- lucene/expressions/build.gradle | 17 +- lucene/expressions/src/java/module-info.java | 28 ++ lucene/facet/build.gradle | 6 +- lucene/facet/src/java/module-info.java | 31 ++ lucene/grouping/build.gradle | 4 +- lucene/grouping/src/java/module-info.java | 24 ++ lucene/highlighter/build.gradle | 6 +- lucene/highlighter/src/java/module-info.java | 28 ++ lucene/join/build.gradle | 2 +- lucene/join/src/java/module-info.java | 23 ++ lucene/licenses/asm-analysis-7.2.jar.sha1 | 1 + lucene/licenses/asm-tree-7.2.jar.sha1 | 1 + lucene/licenses/assertj-core-3.21.0.jar.sha1 | 1 + lucene/licenses/assertj-core-LICENSE-ASL.txt | 201 ++++++++++++ lucene/licenses/assertj-core-NOTICE.txt | 0 lucene/luke/build.gradle | 49 +-- lucene/luke/src/java/module-info.java | 27 ++ .../lucene/luke/app/desktop/LukeMain.java | 30 +- .../luke/app/desktop/util/FontUtils.java | 6 +- .../desktop/{font => util}/ElegantIcons.ttf | Bin lucene/memory/build.gradle | 2 +- lucene/memory/src/java/module-info.java | 23 ++ lucene/misc/build.gradle | 2 +- lucene/misc/src/java/module-info.java | 29 ++ lucene/monitor/build.gradle | 6 +- lucene/monitor/src/java/module-info.java | 25 ++ lucene/queries/build.gradle | 2 +- lucene/queries/src/java/module-info.java | 30 ++ lucene/queryparser/build.gradle | 6 +- lucene/queryparser/src/java/module-info.java | 52 +++ lucene/replicator/build.gradle | 8 +- lucene/replicator/src/java/module-info.java | 29 ++ lucene/sandbox/build.gradle | 4 +- lucene/sandbox/src/java/module-info.java | 31 ++ lucene/spatial-extras/build.gradle | 10 +- .../spatial-extras/src/java/module-info.java | 37 +++ lucene/spatial3d/build.gradle | 2 +- lucene/spatial3d/src/java/module-info.java | 24 ++ lucene/suggest/build.gradle | 4 +- lucene/suggest/src/java/module-info.java | 36 +++ settings.gradle | 8 +- versions.lock | 5 +- versions.props | 3 +- 94 files changed, 2599 insertions(+), 259 deletions(-) create mode 100644 gradle/java/modules-debugging.gradle create mode 100644 gradle/java/modules.gradle create mode 100644 lucene/analysis/common/src/java/module-info.java create mode 100644 lucene/analysis/icu/src/java/module-info.java create mode 100644 lucene/analysis/kuromoji/src/java/module-info.java create mode 100644 lucene/analysis/morfologik.tests/build.gradle create mode 100644 lucene/analysis/morfologik.tests/src/test/module-info.java create mode 100644 lucene/analysis/morfologik.tests/src/test/org/apache/lucene/analysis/morfologik/tests/TestMorfologikAnalyzer.java create mode 100644 lucene/analysis/morfologik/src/java/module-info.java create mode 100644 lucene/analysis/nori/src/java/module-info.java create mode 100644 lucene/analysis/opennlp/src/java/module-info.java create mode 100644 lucene/analysis/phonetic/src/java/module-info.java create mode 100644 lucene/analysis/smartcn/src/java/module-info.java create mode 100644 lucene/analysis/stempel/src/java/module-info.java create mode 100644 lucene/backward-codecs/src/java/module-info.java create mode 100644 lucene/benchmark/src/java/module-info.java create mode 100644 lucene/classification/src/java/module-info.java create mode 100644 lucene/codecs/src/java/module-info.java create mode 100644 lucene/core/src/java/module-info.java create mode 100644 lucene/demo/src/java/module-info.java create mode 100644 lucene/distribution.tests/build.gradle create mode 100644 lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java create mode 100644 lucene/expressions/src/java/module-info.java create mode 100644 lucene/facet/src/java/module-info.java create mode 100644 lucene/grouping/src/java/module-info.java create mode 100644 lucene/highlighter/src/java/module-info.java create mode 100644 lucene/join/src/java/module-info.java create mode 100644 lucene/licenses/asm-analysis-7.2.jar.sha1 create mode 100644 lucene/licenses/asm-tree-7.2.jar.sha1 create mode 100644 lucene/licenses/assertj-core-3.21.0.jar.sha1 create mode 100644 lucene/licenses/assertj-core-LICENSE-ASL.txt create mode 100644 lucene/licenses/assertj-core-NOTICE.txt create mode 100644 lucene/luke/src/java/module-info.java rename lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/{font => util}/ElegantIcons.ttf (100%) create mode 100644 lucene/memory/src/java/module-info.java create mode 100644 lucene/misc/src/java/module-info.java create mode 100644 lucene/monitor/src/java/module-info.java create mode 100644 lucene/queries/src/java/module-info.java create mode 100644 lucene/queryparser/src/java/module-info.java create mode 100644 lucene/replicator/src/java/module-info.java create mode 100644 lucene/sandbox/src/java/module-info.java create mode 100644 lucene/spatial-extras/src/java/module-info.java create mode 100644 lucene/spatial3d/src/java/module-info.java create mode 100644 lucene/suggest/src/java/module-info.java diff --git a/build.gradle b/build.gradle index b13d195f2f6..30b31c868e3 100644 --- a/build.gradle +++ b/build.gradle @@ -110,6 +110,10 @@ apply from: file('buildSrc/scriptDepVersions.gradle') apply from: file('gradle/generation/local-settings.gradle') +// IDE support, settings and specials. +apply from: file('gradle/ide/intellij-idea.gradle') +apply from: file('gradle/ide/eclipse.gradle') + // Set up defaults and configure aspects for certain modules or functionality // (java, tests) apply from: file('gradle/java/folder-layout.gradle') @@ -119,14 +123,11 @@ apply from: file('gradle/testing/randomization.gradle') apply from: file('gradle/testing/fail-on-no-tests.gradle') apply from: file('gradle/testing/alternative-jdk-support.gradle') apply from: file('gradle/java/jar-manifest.gradle') +apply from: file('gradle/java/modules.gradle') // Maven artifact publishing. apply from: file('gradle/maven/publications.gradle') -// IDE support, settings and specials. -apply from: file('gradle/ide/intellij-idea.gradle') -apply from: file('gradle/ide/eclipse.gradle') - // Validation tasks apply from: file('gradle/validation/measure-task-times.gradle') apply from: file('gradle/validation/error-prone.gradle') diff --git a/gradle/documentation/render-javadoc.gradle b/gradle/documentation/render-javadoc.gradle index 4501e8184f8..e4a4f28e293 100644 --- a/gradle/documentation/render-javadoc.gradle +++ b/gradle/documentation/render-javadoc.gradle @@ -57,20 +57,28 @@ allprojects { outputDir = project.javadoc.destinationDir } - task renderSiteJavadoc(type: RenderJavadocTask) { - description "Generates Javadoc API documentation for the site (relative links)." - group "documentation" + if (project.path == ':lucene:luke' || project.path.endsWith(".tests")) { + // These projects are not part of the public API so we don't render their javadocs + // as part of the site's creation. A side-effect of this is that javadocs would not + // be linted for these projects. To avoid this, we connect the regular javadoc task + // to check so that everything is validated. + project.tasks.getByName("check").dependsOn renderJavadoc + } else { + task renderSiteJavadoc(type: RenderJavadocTask) { + description "Generates Javadoc API documentation for the site (relative links)." + group "documentation" - taskResources = resources - dependsOn sourceSets.main.compileClasspath - classpath = sourceSets.main.compileClasspath; - srcDirSet = sourceSets.main.java; + taskResources = resources + dependsOn sourceSets.main.compileClasspath + classpath = sourceSets.main.compileClasspath + srcDirSet = sourceSets.main.java - relativeProjectLinks = true + relativeProjectLinks = true - // Place the documentation under Lucene or Solr's documentation directory. - // docroot is defined in 'documentation.gradle' - outputDir = project.docroot.toPath().resolve(project.relativeDocPath).toFile() + // Place the documentation under the documentation directory. + // docroot is defined in 'documentation.gradle' + outputDir = project.docroot.toPath().resolve(project.relativeDocPath).toFile() + } } } } @@ -255,10 +263,6 @@ configure(subprojects) { } } -configure(project(':lucene:luke')) { - project.tasks.matching { it.name == 'renderSiteJavadoc' }.configureEach { it.enabled = false } -} - class OfflineLink implements Serializable { @Input String url @@ -353,16 +357,18 @@ class RenderJavadocTask extends DefaultTask { @TaskAction public void render() { - def srcDirs = srcDirSet.srcDirs.findAll { dir -> dir.exists() } + def srcDirs = srcDirSet.sourceDirectories.filter { dir -> dir.exists() } + def optionsFile = project.file("${getTemporaryDir()}/javadoc-options.txt") // create the directory, so relative link calculation knows that it's a directory: outputDir.mkdirs(); def opts = [] - opts << [ '-overview', project.file("${srcDirs[0]}/overview.html") ] - opts << [ '-sourcepath', srcDirs.join(File.pathSeparator) ] - opts << [ '-subpackages', project.path.startsWith(':lucene') ? 'org.apache.lucene' : 'org.apache.solr' ] + + def overviewSourceSetDir = srcDirs.filter { dir -> project.file("${dir}/overview.html").exists() }.singleFile + opts << [ '-overview', project.file("${overviewSourceSetDir}/overview.html") ] + opts << [ '-d', outputDir ] opts << '-protected' opts << [ '-encoding', 'UTF-8' ] @@ -454,6 +460,24 @@ class RenderJavadocTask extends DefaultTask { def jOpts = opts.findAll { opt -> opt instanceof String && opt.startsWith("-J") } opts.removeAll(jOpts) + // Collect all source files, for now excluding module descriptors. + opts.addAll( + srcDirs.collectMany { dir -> + project.fileTree(dir: dir, include: "**/*.java", exclude: "**/module-info.java").files + }.collect { it.toString() } + ) + + // handle doc-files manually since in explicit source file mode javadoc does not copy them. + srcDirs.each { File dir -> + project.copy { + into outputDir + + from(dir, { + include "**/doc-files/**" + }) + } + } + // Temporary file that holds all javadoc options for the current task (except jOpts) optionsFile.withWriter("UTF-8", { writer -> // escapes an option with single quotes or whitespace to be passed in the options.txt file for diff --git a/gradle/ide/eclipse.gradle b/gradle/ide/eclipse.gradle index 0a5b6083d63..4db9ae3ba6c 100644 --- a/gradle/ide/eclipse.gradle +++ b/gradle/ide/eclipse.gradle @@ -58,7 +58,11 @@ configure(rootProject) { jars += prj.configurations.testCompileClasspath.resolve() } - classpath.entries += sources.sort().collect {name -> new SourceFolder(name, "build/eclipse/" + name) } + classpath.entries += sources.sort().collect { name -> + def sourceFolder = new SourceFolder(name, "build/eclipse/" + name) + sourceFolder.setExcludes(["module-info.java"]) + return sourceFolder + } classpath.entries += jars.unique().findAll { location -> location.isFile() }.collect { location -> new LibEntry(location.toString()) } diff --git a/gradle/ide/intellij-idea.gradle b/gradle/ide/intellij-idea.gradle index 1d5b8d21bd5..589aaec3562 100644 --- a/gradle/ide/intellij-idea.gradle +++ b/gradle/ide/intellij-idea.gradle @@ -16,7 +16,7 @@ */ // Try to detect IntelliJ model loader ("reimport") early. -def isIdea = System.getProperty("idea.active") != null || +rootProject.ext.isIdea = System.getProperty("idea.active") != null || gradle.startParameter.taskNames.contains('idea') || gradle.startParameter.taskNames.contains('cleanIdea') diff --git a/gradle/java/jar-manifest.gradle b/gradle/java/jar-manifest.gradle index d4ab812cf45..359b5792101 100644 --- a/gradle/java/jar-manifest.gradle +++ b/gradle/java/jar-manifest.gradle @@ -69,12 +69,6 @@ subprojects { "X-Build-OS" : "${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}" ] - // Only apply automatic module name to jar task. - if (task.name in ["jar"]) { - manifestAttrs["Automatic-Module-Name"] = - "${-> project.path.replaceFirst(/^:lucene/, Matcher.quoteReplacement(project.group)).replace(':', '.').replace('-', '_')}" - } - manifest { attributes(manifestAttrs) } @@ -88,29 +82,3 @@ subprojects { } } } - -configure(rootProject) { - tasks.register("showModuleNames", { showModuleTask -> - def allJarTasks = [] - - rootProject.subprojects.each { subproject -> - subproject.tasks.matching { it.name == 'jar' }.all { - allJarTasks.add it - } - } - - dependsOn allJarTasks - - doFirst { - allJarTasks.each { jarTask -> - File jarFile = jarTask.outputs.files.singleFile - try (def jar = new JarFile(jarFile)) { - logger.lifecycle(String.format(Locale.ROOT, - "%-50s -> %s", - jarFile.name, - jar.manifest.mainAttributes.getValue("Automatic-Module-Name"))) - } - } - } - }) -} diff --git a/gradle/java/javac.gradle b/gradle/java/javac.gradle index 78c5fb40a9e..25f66c39de0 100644 --- a/gradle/java/javac.gradle +++ b/gradle/java/javac.gradle @@ -39,7 +39,8 @@ allprojects { "-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty", - "-Xlint:exports", + // TODO: uh-oh we have broken APIs. + "-Xlint:-exports", "-Xlint:fallthrough", "-Xlint:finally", "-Xlint:opens", diff --git a/gradle/java/modules-debugging.gradle b/gradle/java/modules-debugging.gradle new file mode 100644 index 00000000000..52bc6fe1b3c --- /dev/null +++ b/gradle/java/modules-debugging.gradle @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Debugging/ validation utilities and helpers to aid transition +// to java modules. + +allprojects { + plugins.withType(JavaPlugin) { + // Show all non-empty package names + tasks.register("showPackageNames", { task -> + doFirst { + listPackageNames(sourceSets).each { println(it) } + } + }) + + tasks.register("showServiceProviders", { task -> + doFirst { + def services = listServices(sourceSets) + services.each { entry -> { + println(entry.key) + entry.value.each { println(" ${it}") } + }} + } + }) + } +} + +/* Utility method to collect all package names in a source sets. */ +static def listPackageNames(SourceSetContainer sourceSets) { + var pkgNameSet = [] as Set + sourceSets.main.each { sourceSet -> + var dirs = sourceSet.allJava.srcDirTrees.collect { it.dir.toPath() } + var pattern = new PatternSet() + .include('**/*.java') + .exclude('module-info.java') + .exclude('**/package-info.java') + sourceSet.allJava.matching(pattern).each {srcFile -> + var srcPath = srcFile.toPath() + var dir = dirs.find { srcPath.startsWith(it) } + var pkgName = srcPath.subpath(dir.nameCount, srcPath.nameCount).parent.stream().map(Object::toString).collect(Collectors.joining('.')) + pkgNameSet.add(pkgName) + } + } + var pkgNames = pkgNameSet as List + pkgNames.sort() + return pkgNames +} + +/* Utility method to collect all service providers in a source sets. */ +static def listServices(SourceSetContainer sourceSets) { + def services = [:] as Map> + sourceSets.main.each {sourceSet -> + var pattern = new PatternSet().include('META-INF/services/*') + sourceSet.resources.matching(pattern).each {file -> + def serviceName = file.name + def providers = [] + file.withReader { reader -> { + reader.lines().each { l -> + def line = l.trim() + if (line != "" && !line.startsWith("#")) { + def provider = line.replace('$', '.') + providers.add(provider) + } + } + }} + services.put(serviceName, providers) + } + } + return services +} diff --git a/gradle/java/modules.gradle b/gradle/java/modules.gradle new file mode 100644 index 00000000000..45405a25791 --- /dev/null +++ b/gradle/java/modules.gradle @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Configure miscellaneous aspects required for supporting the java module system layer. + +allprojects { + plugins.withType(JavaPlugin) { + // We won't be using gradle's built-in automatic module finder. + java { + modularity.inferModulePath.set(false) + } + + // Map convention configuration names to "modular" corresponding configurations. + Closure moduleConfigurationNameFor = { String configurationName -> + return "module" + configurationName.capitalize().replace("Classpath", "Path") + } + + // + // For each source set, create explicit configurations for declaring modular dependencies. + // These "modular" configurations correspond 1:1 to Gradle's conventions but have a 'module' prefix + // and a capitalized remaining part of the conventional name. For example, an 'api' configuration in + // the main source set would have a corresponding 'moduleApi' configuration for declaring modular + // dependencies. + // + // Gradle's java plugin "convention" configurations extend from their modular counterparts + // so all dependencies end up on classpath by default for backward compatibility with other + // tasks and gradle infrastructure. + // + // At the same time, we also know which dependencies (and their transitive graph of dependencies!) + // should be placed on module-path only. + // + // Note that an explicit configuration of modular dependencies also opens up the possibility of automatically + // validating whether the dependency configuration for a gradle project is consistent with the information in + // the module-info descriptor because there is a (nearly?) direct correspondence between the two: + // + // moduleApi - 'requires transitive' + // moduleImplementation - 'requires' + // moduleCompileOnly - 'requires static' + // + project.sourceSets.all { SourceSet sourceSet -> + ConfigurationContainer configurations = project.configurations + + // Create modular configurations for convention configurations. + Closure createModuleConfigurationForConvention = { String configurationName -> + Configuration conventionConfiguration = configurations.maybeCreate(configurationName) + Configuration moduleConfiguration = configurations.maybeCreate(moduleConfigurationNameFor(configurationName)) + moduleConfiguration.canBeConsumed(false) + moduleConfiguration.canBeResolved(false) + conventionConfiguration.extendsFrom(moduleConfiguration) + + project.logger.info("Created module configuration for '${conventionConfiguration.name}': ${moduleConfiguration.name}") + return moduleConfiguration + } + + Configuration moduleApi = createModuleConfigurationForConvention(sourceSet.apiConfigurationName) + Configuration moduleImplementation = createModuleConfigurationForConvention(sourceSet.implementationConfigurationName) + moduleImplementation.extendsFrom(moduleApi) + Configuration moduleRuntimeOnly = createModuleConfigurationForConvention(sourceSet.runtimeOnlyConfigurationName) + Configuration moduleCompileOnly = createModuleConfigurationForConvention(sourceSet.compileOnlyConfigurationName) + // sourceSet.compileOnlyApiConfigurationName // This seems like a very esoteric use case, leave out. + + // Set up compilation module path configuration combining corresponding convention configurations. + Closure createResolvableModuleConfiguration = { String configurationName -> + Configuration conventionConfiguration = configurations.maybeCreate(configurationName) + Configuration moduleConfiguration = configurations.maybeCreate( + moduleConfigurationNameFor(conventionConfiguration.name)) + moduleConfiguration.canBeConsumed(false) + moduleConfiguration.canBeResolved(true) + moduleConfiguration.attributes { + // Prefer class folders over JARs. The exception is made for tests projects which require a composition + // of classes and resources, otherwise split into two folders. + if (project.name.endsWith(".tests")) { + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR)) + } else { + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.CLASSES)) + } + } + + project.logger.info("Created resolvable module configuration for '${conventionConfiguration.name}': ${moduleConfiguration.name}") + return moduleConfiguration + } + + Configuration compileModulePathConfiguration = createResolvableModuleConfiguration(sourceSet.compileClasspathConfigurationName) + compileModulePathConfiguration.extendsFrom(moduleCompileOnly, moduleImplementation) + + Configuration runtimeModulePathConfiguration = createResolvableModuleConfiguration(sourceSet.runtimeClasspathConfigurationName) + runtimeModulePathConfiguration.extendsFrom(moduleRuntimeOnly, moduleImplementation) + + // Create and register a source set extension for manipulating classpath/ module-path + ModularPathsExtension modularPaths = new ModularPathsExtension(project, sourceSet, + compileModulePathConfiguration, + runtimeModulePathConfiguration) + sourceSet.extensions.add("modularPaths", modularPaths) + + // Customized the JavaCompile for this source set so that it has proper module path. + tasks.named(sourceSet.getCompileJavaTaskName()).configure({ JavaCompile task -> + task.dependsOn modularPaths.compileModulePathConfiguration + + // Add modular dependencies and their transitive dependencies to module path. + task.options.compilerArgumentProviders.add((CommandLineArgumentProvider) { + def modularPathFiles = modularPaths.compileModulePathConfiguration.files + def extraArgs = [] + if (!modularPathFiles.isEmpty()) { + if (!modularPaths.hasModuleDescriptor()) { + // We're compiling a non-module so we'll bring everything on module path in + // otherwise things wouldn't be part of the resolved module graph. + extraArgs += ["--add-modules", "ALL-MODULE-PATH"] + } + + extraArgs += ["--module-path", modularPathFiles.join(File.pathSeparator)] + } + + task.logger.info("Module path for ${task.path}:\n " + modularPathFiles.sort().join("\n ")) + + return extraArgs + }) + + // LUCENE-10304: if we modify the classpath here, IntelliJ no longer sees the dependencies as compile-time + // dependencies, don't know why. + if (!rootProject.ext.isIdea) { + // Modify the default classpath by removing anything already placed on module path. + // This could be done in a fancier way but a set difference is just fine for us here. Use a lazy + // provider to delay computation of the actual path. + task.classpath = files({ -> + def trimmedClasspath = sourceSet.compileClasspath - modularPaths.compileModulePathConfiguration + task.logger.info("Class path for ${task.path}:\n " + trimmedClasspath.files.sort().join("\n ")) + return trimmedClasspath + }) + } + }) + } + + // + // Configure the (default) test task to use module paths. + // + // There is no explicit connection between source sets and test tasks so there is no way (?) + // to do this automatically, convention-style. + + // This closure can be used to configure a different task, with a different source set, should we + // have the need for it. + Closure configureTestTaskForSourceSet = { Test task, SourceSet sourceSet -> + task.configure { + Configuration modulePath = task.project.configurations.maybeCreate( + moduleConfigurationNameFor(sourceSet.getRuntimeClasspathConfigurationName())) + + task.dependsOn modulePath + + // Add modular dependencies and their transitive dependencies to module path. + task.jvmArgumentProviders.add((CommandLineArgumentProvider) { + def extraArgs = [] + + // Determine whether the source set classes themselves should be appended + // to classpath or module path. + boolean sourceSetIsAModule = sourceSet.modularPaths.hasModuleDescriptor() + + if (!modulePath.isEmpty() || sourceSetIsAModule) { + if (sourceSetIsAModule) { + // Add source set outputs to module path. + extraArgs += ["--module-path", (modulePath + sourceSet.output.classesDirs).files.join(File.pathSeparator)] + // Ideally, we should only add the sourceset's module here, everything else would be resolved via the + // module descriptor. But this would require parsing the module descriptor and may cause JVM version conflicts + // so keeping it simple. + extraArgs += ["--add-modules", "ALL-MODULE-PATH"] + } else { + extraArgs += ["--module-path", modulePath.files.join(File.pathSeparator)] + // In this case we're running a non-module against things on the module path so let's bring in + // everything on module path into the resolution graph. + extraArgs += ["--add-modules", "ALL-MODULE-PATH"] + } + } + + task.logger.info("Module path for ${task.path}:\n " + modulePath.files.sort().join("\n ")) + + return extraArgs + }) + + + // Modify the default classpath by removing anything already placed on module path. + // This could be done in a fancier way but a set difference is just fine for us here. Use a lazy + // provider to delay computation of the actual path. + task.classpath = files({ -> + def trimmedClasspath = sourceSet.runtimeClasspath - modulePath + + boolean sourceSetIsAModule = sourceSet.modularPaths.hasModuleDescriptor() + if (sourceSetIsAModule) { + // also subtract the sourceSet's output directories. + trimmedClasspath = trimmedClasspath - sourceSet.output.classesDirs + } + + task.logger.info("Class path for ${task.path}:\n " + trimmedClasspath.files.sort().join("\n ")) + return trimmedClasspath + }) + } + } + + // Configure (tasks.test, sourceSets.test) + tasks.matching { it.name == "test" }.all { Test task -> + configureTestTaskForSourceSet(task, task.project.sourceSets.test) + } + + // Configure module versions. + tasks.withType(JavaCompile).configureEach { task -> + // TODO: LUCENE-10267: workaround for gradle bug. Remove when the corresponding issue is fixed. + task.options.compilerArgumentProviders.add((CommandLineArgumentProvider) { -> + if (task.getClasspath().isEmpty()) { + return ["--module-version", project.version.toString()] + } else { + return [] + } + }) + + task.options.javaModuleVersion.set(provider { + return project.version.toString() + }) + } + } +} + + +class ModularPathsExtension { + Project project + SourceSet sourceSet + Configuration compileModulePathConfiguration + Configuration runtimeModulePathConfiguration + + ModularPathsExtension(Project project, SourceSet sourceSet, + Configuration compileModulePathConfiguration, + Configuration runtimeModulePathConfiguration) { + this.project = project + this.sourceSet = sourceSet + this.compileModulePathConfiguration = compileModulePathConfiguration + this.runtimeModulePathConfiguration = runtimeModulePathConfiguration + } + + boolean hasModuleDescriptor() { + return sourceSet.allJava.srcDirs.stream() + .map(dir -> new File(dir, "module-info.java")) + .anyMatch(file -> file.exists()) + } +} \ No newline at end of file diff --git a/gradle/maven/publications.gradle b/gradle/maven/publications.gradle index 32422cdf509..cc9bc9682d0 100644 --- a/gradle/maven/publications.gradle +++ b/gradle/maven/publications.gradle @@ -31,15 +31,19 @@ configure(rootProject) { ext { mavenProjects = project(":lucene").subprojects.findAll {subproject -> - return !(subproject.path in [ - // Exclude distribution assembly & documentation. + def excluded = [ + // Exclude distribution assembly, tests & documentation. ":lucene:distribution", ":lucene:documentation", // Exclude the parent container project for analysis modules (no artifacts). ":lucene:analysis", // Exclude the native module. ":lucene:misc:native" - ]) + ] + + // Exclude all subprojects that are modular test projects and those explicitly + // excluded above. + return !(subproject.path.endsWith(".tests") || subproject.path in excluded) } } } diff --git a/gradle/testing/randomization.gradle b/gradle/testing/randomization.gradle index fc6c991875d..938ca396db2 100644 --- a/gradle/testing/randomization.gradle +++ b/gradle/testing/randomization.gradle @@ -164,7 +164,9 @@ allprojects { // Enable security manager, if requested. We could move the selection of security manager and security policy // to each project's build/ configuration but it seems compact enough to keep it here for now. if (Boolean.parseBoolean(testOptionsResolved["tests.useSecurityManager"])) { - if (project.path == ":lucene:replicator") { + if (project.path.endsWith(".tests")) { + // LUCENE-10301: for now, do not use the security manager for modular tests (test framework is not available). + } else if (project.path == ":lucene:replicator") { systemProperty 'java.security.manager', "org.apache.lucene.util.TestSecurityManager" systemProperty 'java.security.policy', file("${resources}/policies/replicator-tests.policy") } else if (project.path.startsWith(":lucene")) { diff --git a/gradle/validation/ecj-lint.gradle b/gradle/validation/ecj-lint.gradle index 398c26e10be..591eb8464e0 100644 --- a/gradle/validation/ecj-lint.gradle +++ b/gradle/validation/ecj-lint.gradle @@ -35,9 +35,10 @@ allprojects { // with a non-empty java.srcDirs. These tasks are then // attached to project's "ecjLint" task. def lintTasks = sourceSets.collect { sourceSet -> - def srcDirs = sourceSet.java.srcDirs.findAll { dir -> dir.exists() } + def srcDirs = sourceSet.java.sourceDirectories + .filter { dir -> dir.exists() } - tasks.create(sourceSet.getTaskName("ecjLint", null), JavaExec, {task -> + tasks.create(sourceSet.getTaskName("ecjLint", null), JavaExec, {JavaExec task -> // This dependency is on a configuration; technically it causes // all dependencies to be resolved before this task executes // (this includes scheduling tasks that compile the @@ -60,6 +61,24 @@ allprojects { def tmpDst = getTemporaryDir() workingDir tmpDst + // Place input files in an external file to dodge command line argument + // limits. We could pass a directory but ecj seems to be buggy: when it + // encounters a module-info.java file it no longer compiles other source files. + def inputsFile = file("${tmpDst}/ecj-inputs.txt") + // escape filename accoring to ECJ's rules: + // https://github.com/eclipse/aspectj.eclipse.jdt.core/blob/a05312e746b9bc2b48b4b039f6e7b5e061b5b393/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java#L1533-L1537 + // Basically surround all whitespace by quotes: + def escapeFileName = { String s -> s.replaceAll(/ +/, /"$0"/) } + inputsFile.setText( + srcDirs.collectMany { dir -> + project.fileTree(dir: dir, include: "**/*.java" ).files + } + // Try to sort all input files; a side-effect of this should be that module-info.java + // is placed first on the list, which works around ECJ bug: + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=569833 + .sort() + .collect {file -> escapeFileName(file.absolutePath.toString())}.join("\n"), "UTF-8") + args += [ "-d", "none" ] // Compilation environment. @@ -72,22 +91,41 @@ allprojects { args += [ "-enableJavadoc" ] args += [ "-properties", file("${resources}/ecj.javadocs.prefs").absolutePath ] - doFirst { - tmpDst.mkdirs() + // We depend on modular paths. + def modularPaths = sourceSet.modularPaths + dependsOn modularPaths.compileModulePathConfiguration - // Add classpath locations at execution time (can't resolve the + task.argumentProviders.add((CommandLineArgumentProvider) { + // Add modular dependencies and their transitive dependencies to module path. + def modularPathFiles = modularPaths.compileModulePathConfiguration.files + def extraArgs = [] + if (!modularPathFiles.isEmpty()) { + if (!modularPaths.hasModuleDescriptor()) { + // We're compiling a non-module so we'll bring everything on module path in + // otherwise things wouldn't be part of the resolved module graph. + extraArgs += ["--add-modules", "ALL-MODULE-PATH"] + } + + extraArgs += ["--module-path", modularPathFiles.join(File.pathSeparator)] + } + + // Add classpath locations in a lazy provider (can't resolve the // configuration at evaluation time). Filter out non-existing entries // (output folders for non-existing input source dirs like resources). def cpath = sourceSet.compileClasspath.filter { p -> p.exists() } + cpath = cpath - modularPathFiles if (!cpath.isEmpty()) { - args += ["-classpath", cpath.asPath] + extraArgs += ["-classpath", cpath.join(File.pathSeparator)] } - // Add source location(s). Ideally we'd provide a set of files as in: - // args += sourceSet.java.files - // but this exceeds max allowed command line size. So we pass source - // directories instead: - args += srcDirs + // Add source location(s) in an external file to avoid command line argument limits. + extraArgs += ["@" + inputsFile.absolutePath] + + return extraArgs + }) + + doFirst { + tmpDst.mkdirs() } }) } diff --git a/gradle/validation/ecj-lint/ecj.javadocs.prefs b/gradle/validation/ecj-lint/ecj.javadocs.prefs index a5352aa1971..25d527a7278 100644 --- a/gradle/validation/ecj-lint/ecj.javadocs.prefs +++ b/gradle/validation/ecj-lint/ecj.javadocs.prefs @@ -17,7 +17,8 @@ org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.doc.comment.support=enabled -org.eclipse.jdt.core.compiler.problem.APILeak=error +# TODO: disabled because we do have api leaks in modules +org.eclipse.jdt.core.compiler.problem.APILeak=ignore org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=error org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error org.eclipse.jdt.core.compiler.problem.assertIdentifier=error @@ -120,7 +121,8 @@ org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=error org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore -org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=error +# TODO: ideally, we shouldn't rely on these... but we do. +org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled @@ -144,4 +146,4 @@ org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=11 org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled org.eclipse.jdt.core.compiler.taskPriorities=HIGH -org.eclipse.jdt.core.compiler.taskTags=nocommit +org.eclipse.jdt.core.compiler.taskTags=nocommit \ No newline at end of file diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index efa587bf50a..568c280172c 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -45,6 +45,9 @@ API Changes New Features --------------------- +* LUCENE-10255: Lucene JARs are now proper modules, with module descriptors and dependency information. + (Chris Hegarty, Uwe Schindler, Tomoko Uchida, Dawid Weiss) + * LUCENE-10223: Add interval function support to StandardQueryParser. Add min-should-match operator support to StandardQueryParser. Update and clean up package documentation in flexible query parser module. (Dawid Weiss, Alan Woodward) diff --git a/lucene/analysis/common/build.gradle b/lucene/analysis/common/build.gradle index 6fba70adb2c..1815041f46f 100644 --- a/lucene/analysis/common/build.gradle +++ b/lucene/analysis/common/build.gradle @@ -20,7 +20,7 @@ apply plugin: 'java-library' description = 'Analyzers for indexing content in different languages and domains' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/common/src/java/module-info.java b/lucene/analysis/common/src/java/module-info.java new file mode 100644 index 00000000000..e736a9532f0 --- /dev/null +++ b/lucene/analysis/common/src/java/module-info.java @@ -0,0 +1,222 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Lucene Analysis Common. */ +module org.apache.lucene.analysis.common { + requires java.xml; + requires org.apache.lucene.core; + + exports org.apache.lucene.analysis.ar; + exports org.apache.lucene.analysis.bg; + exports org.apache.lucene.analysis.bn; + exports org.apache.lucene.analysis.boost; + exports org.apache.lucene.analysis.br; + exports org.apache.lucene.analysis.ca; + exports org.apache.lucene.analysis.charfilter; + exports org.apache.lucene.analysis.cjk; + exports org.apache.lucene.analysis.ckb; + exports org.apache.lucene.analysis.classic; + exports org.apache.lucene.analysis.commongrams; + exports org.apache.lucene.analysis.compound.hyphenation; + exports org.apache.lucene.analysis.compound; + exports org.apache.lucene.analysis.core; + exports org.apache.lucene.analysis.custom; + exports org.apache.lucene.analysis.cz; + exports org.apache.lucene.analysis.da; + exports org.apache.lucene.analysis.de; + exports org.apache.lucene.analysis.el; + exports org.apache.lucene.analysis.email; + exports org.apache.lucene.analysis.en; + exports org.apache.lucene.analysis.es; + exports org.apache.lucene.analysis.et; + exports org.apache.lucene.analysis.eu; + exports org.apache.lucene.analysis.fa; + exports org.apache.lucene.analysis.fi; + exports org.apache.lucene.analysis.fr; + exports org.apache.lucene.analysis.ga; + exports org.apache.lucene.analysis.gl; + exports org.apache.lucene.analysis.hi; + exports org.apache.lucene.analysis.hu; + exports org.apache.lucene.analysis.hunspell; + exports org.apache.lucene.analysis.hy; + exports org.apache.lucene.analysis.id; + exports org.apache.lucene.analysis.in; + exports org.apache.lucene.analysis.it; + exports org.apache.lucene.analysis.lt; + exports org.apache.lucene.analysis.lv; + exports org.apache.lucene.analysis.minhash; + exports org.apache.lucene.analysis.miscellaneous; + exports org.apache.lucene.analysis.ne; + exports org.apache.lucene.analysis.ngram; + exports org.apache.lucene.analysis.nl; + exports org.apache.lucene.analysis.no; + exports org.apache.lucene.analysis.path; + exports org.apache.lucene.analysis.pattern; + exports org.apache.lucene.analysis.payloads; + exports org.apache.lucene.analysis.pt; + exports org.apache.lucene.analysis.query; + exports org.apache.lucene.analysis.reverse; + exports org.apache.lucene.analysis.ro; + exports org.apache.lucene.analysis.ru; + exports org.apache.lucene.analysis.shingle; + exports org.apache.lucene.analysis.sinks; + exports org.apache.lucene.analysis.snowball; + exports org.apache.lucene.analysis.sr; + exports org.apache.lucene.analysis.sv; + exports org.apache.lucene.analysis.synonym; + exports org.apache.lucene.analysis.ta; + exports org.apache.lucene.analysis.te; + exports org.apache.lucene.analysis.th; + exports org.apache.lucene.analysis.tr; + exports org.apache.lucene.analysis.util; + exports org.apache.lucene.analysis.wikipedia; + exports org.apache.lucene.collation.tokenattributes; + exports org.apache.lucene.collation; + exports org.tartarus.snowball.ext; + exports org.tartarus.snowball; + + provides org.apache.lucene.analysis.CharFilterFactory with + org.apache.lucene.analysis.charfilter.HTMLStripCharFilterFactory, + org.apache.lucene.analysis.charfilter.MappingCharFilterFactory, + org.apache.lucene.analysis.cjk.CJKWidthCharFilterFactory, + org.apache.lucene.analysis.fa.PersianCharFilterFactory, + org.apache.lucene.analysis.pattern.PatternReplaceCharFilterFactory; + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.tr.ApostropheFilterFactory, + org.apache.lucene.analysis.ar.ArabicNormalizationFilterFactory, + org.apache.lucene.analysis.ar.ArabicStemFilterFactory, + org.apache.lucene.analysis.bg.BulgarianStemFilterFactory, + org.apache.lucene.analysis.boost.DelimitedBoostTokenFilterFactory, + org.apache.lucene.analysis.bn.BengaliNormalizationFilterFactory, + org.apache.lucene.analysis.bn.BengaliStemFilterFactory, + org.apache.lucene.analysis.br.BrazilianStemFilterFactory, + org.apache.lucene.analysis.cjk.CJKBigramFilterFactory, + org.apache.lucene.analysis.cjk.CJKWidthFilterFactory, + org.apache.lucene.analysis.ckb.SoraniNormalizationFilterFactory, + org.apache.lucene.analysis.ckb.SoraniStemFilterFactory, + org.apache.lucene.analysis.classic.ClassicFilterFactory, + org.apache.lucene.analysis.commongrams.CommonGramsFilterFactory, + org.apache.lucene.analysis.commongrams.CommonGramsQueryFilterFactory, + org.apache.lucene.analysis.compound.DictionaryCompoundWordTokenFilterFactory, + org.apache.lucene.analysis.compound.HyphenationCompoundWordTokenFilterFactory, + org.apache.lucene.analysis.core.DecimalDigitFilterFactory, + org.apache.lucene.analysis.core.LowerCaseFilterFactory, + org.apache.lucene.analysis.core.StopFilterFactory, + org.apache.lucene.analysis.core.TypeTokenFilterFactory, + org.apache.lucene.analysis.core.UpperCaseFilterFactory, + org.apache.lucene.analysis.cz.CzechStemFilterFactory, + org.apache.lucene.analysis.de.GermanLightStemFilterFactory, + org.apache.lucene.analysis.de.GermanMinimalStemFilterFactory, + org.apache.lucene.analysis.de.GermanNormalizationFilterFactory, + org.apache.lucene.analysis.de.GermanStemFilterFactory, + org.apache.lucene.analysis.el.GreekLowerCaseFilterFactory, + org.apache.lucene.analysis.el.GreekStemFilterFactory, + org.apache.lucene.analysis.en.EnglishMinimalStemFilterFactory, + org.apache.lucene.analysis.en.EnglishPossessiveFilterFactory, + org.apache.lucene.analysis.en.KStemFilterFactory, + org.apache.lucene.analysis.en.PorterStemFilterFactory, + org.apache.lucene.analysis.es.SpanishLightStemFilterFactory, + org.apache.lucene.analysis.es.SpanishMinimalStemFilterFactory, + org.apache.lucene.analysis.es.SpanishPluralStemFilterFactory, + org.apache.lucene.analysis.fa.PersianNormalizationFilterFactory, + org.apache.lucene.analysis.fi.FinnishLightStemFilterFactory, + org.apache.lucene.analysis.fr.FrenchLightStemFilterFactory, + org.apache.lucene.analysis.fr.FrenchMinimalStemFilterFactory, + org.apache.lucene.analysis.ga.IrishLowerCaseFilterFactory, + org.apache.lucene.analysis.gl.GalicianMinimalStemFilterFactory, + org.apache.lucene.analysis.gl.GalicianStemFilterFactory, + org.apache.lucene.analysis.hi.HindiNormalizationFilterFactory, + org.apache.lucene.analysis.hi.HindiStemFilterFactory, + org.apache.lucene.analysis.hu.HungarianLightStemFilterFactory, + org.apache.lucene.analysis.hunspell.HunspellStemFilterFactory, + org.apache.lucene.analysis.id.IndonesianStemFilterFactory, + org.apache.lucene.analysis.in.IndicNormalizationFilterFactory, + org.apache.lucene.analysis.it.ItalianLightStemFilterFactory, + org.apache.lucene.analysis.lv.LatvianStemFilterFactory, + org.apache.lucene.analysis.minhash.MinHashFilterFactory, + org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilterFactory, + org.apache.lucene.analysis.miscellaneous.CapitalizationFilterFactory, + org.apache.lucene.analysis.miscellaneous.CodepointCountFilterFactory, + org.apache.lucene.analysis.miscellaneous.ConcatenateGraphFilterFactory, + org.apache.lucene.analysis.miscellaneous.DateRecognizerFilterFactory, + org.apache.lucene.analysis.miscellaneous.DelimitedTermFrequencyTokenFilterFactory, + org.apache.lucene.analysis.miscellaneous.DropIfFlaggedFilterFactory, + org.apache.lucene.analysis.miscellaneous.FingerprintFilterFactory, + org.apache.lucene.analysis.miscellaneous.FixBrokenOffsetsFilterFactory, + org.apache.lucene.analysis.miscellaneous.HyphenatedWordsFilterFactory, + org.apache.lucene.analysis.miscellaneous.KeepWordFilterFactory, + org.apache.lucene.analysis.miscellaneous.KeywordMarkerFilterFactory, + org.apache.lucene.analysis.miscellaneous.KeywordRepeatFilterFactory, + org.apache.lucene.analysis.miscellaneous.LengthFilterFactory, + org.apache.lucene.analysis.miscellaneous.LimitTokenCountFilterFactory, + org.apache.lucene.analysis.miscellaneous.LimitTokenOffsetFilterFactory, + org.apache.lucene.analysis.miscellaneous.LimitTokenPositionFilterFactory, + org.apache.lucene.analysis.miscellaneous.RemoveDuplicatesTokenFilterFactory, + org.apache.lucene.analysis.miscellaneous.StemmerOverrideFilterFactory, + org.apache.lucene.analysis.miscellaneous.ProtectedTermFilterFactory, + org.apache.lucene.analysis.miscellaneous.TrimFilterFactory, + org.apache.lucene.analysis.miscellaneous.TruncateTokenFilterFactory, + org.apache.lucene.analysis.miscellaneous.TypeAsSynonymFilterFactory, + org.apache.lucene.analysis.miscellaneous.WordDelimiterFilterFactory, + org.apache.lucene.analysis.miscellaneous.WordDelimiterGraphFilterFactory, + org.apache.lucene.analysis.miscellaneous.ScandinavianFoldingFilterFactory, + org.apache.lucene.analysis.miscellaneous.ScandinavianNormalizationFilterFactory, + org.apache.lucene.analysis.ngram.EdgeNGramFilterFactory, + org.apache.lucene.analysis.ngram.NGramFilterFactory, + org.apache.lucene.analysis.no.NorwegianLightStemFilterFactory, + org.apache.lucene.analysis.no.NorwegianMinimalStemFilterFactory, + org.apache.lucene.analysis.no.NorwegianNormalizationFilterFactory, + org.apache.lucene.analysis.pattern.PatternReplaceFilterFactory, + org.apache.lucene.analysis.pattern.PatternCaptureGroupFilterFactory, + org.apache.lucene.analysis.pattern.PatternTypingFilterFactory, + org.apache.lucene.analysis.payloads.DelimitedPayloadTokenFilterFactory, + org.apache.lucene.analysis.payloads.NumericPayloadTokenFilterFactory, + org.apache.lucene.analysis.payloads.TokenOffsetPayloadTokenFilterFactory, + org.apache.lucene.analysis.payloads.TypeAsPayloadTokenFilterFactory, + org.apache.lucene.analysis.pt.PortugueseLightStemFilterFactory, + org.apache.lucene.analysis.pt.PortugueseMinimalStemFilterFactory, + org.apache.lucene.analysis.pt.PortugueseStemFilterFactory, + org.apache.lucene.analysis.reverse.ReverseStringFilterFactory, + org.apache.lucene.analysis.ru.RussianLightStemFilterFactory, + org.apache.lucene.analysis.shingle.ShingleFilterFactory, + org.apache.lucene.analysis.shingle.FixedShingleFilterFactory, + org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory, + org.apache.lucene.analysis.sr.SerbianNormalizationFilterFactory, + org.apache.lucene.analysis.sv.SwedishLightStemFilterFactory, + org.apache.lucene.analysis.sv.SwedishMinimalStemFilterFactory, + org.apache.lucene.analysis.synonym.SynonymFilterFactory, + org.apache.lucene.analysis.synonym.SynonymGraphFilterFactory, + org.apache.lucene.analysis.core.FlattenGraphFilterFactory, + org.apache.lucene.analysis.te.TeluguNormalizationFilterFactory, + org.apache.lucene.analysis.te.TeluguStemFilterFactory, + org.apache.lucene.analysis.tr.TurkishLowerCaseFilterFactory, + org.apache.lucene.analysis.util.ElisionFilterFactory; + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.classic.ClassicTokenizerFactory, + org.apache.lucene.analysis.core.KeywordTokenizerFactory, + org.apache.lucene.analysis.core.LetterTokenizerFactory, + org.apache.lucene.analysis.core.WhitespaceTokenizerFactory, + org.apache.lucene.analysis.email.UAX29URLEmailTokenizerFactory, + org.apache.lucene.analysis.ngram.EdgeNGramTokenizerFactory, + org.apache.lucene.analysis.ngram.NGramTokenizerFactory, + org.apache.lucene.analysis.path.PathHierarchyTokenizerFactory, + org.apache.lucene.analysis.pattern.PatternTokenizerFactory, + org.apache.lucene.analysis.pattern.SimplePatternSplitTokenizerFactory, + org.apache.lucene.analysis.pattern.SimplePatternTokenizerFactory, + org.apache.lucene.analysis.th.ThaiTokenizerFactory, + org.apache.lucene.analysis.wikipedia.WikipediaTokenizerFactory; +} diff --git a/lucene/analysis/icu/build.gradle b/lucene/analysis/icu/build.gradle index 2eab9633077..e76b32789a1 100644 --- a/lucene/analysis/icu/build.gradle +++ b/lucene/analysis/icu/build.gradle @@ -20,10 +20,10 @@ apply plugin: 'java-library' description = 'Analysis integration with ICU (International Components for Unicode)' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') - api 'com.ibm.icu:icu4j' + moduleApi 'com.ibm.icu:icu4j' testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/icu/src/java/module-info.java b/lucene/analysis/icu/src/java/module-info.java new file mode 100644 index 00000000000..c901af4bd20 --- /dev/null +++ b/lucene/analysis/icu/src/java/module-info.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Analysis integration with ICU */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.analysis.icu { + requires com.ibm.icu; + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.icu; + exports org.apache.lucene.analysis.icu.segmentation; + exports org.apache.lucene.analysis.icu.tokenattributes; + + provides org.apache.lucene.analysis.CharFilterFactory with + org.apache.lucene.analysis.icu.ICUNormalizer2CharFilterFactory; + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.icu.segmentation.ICUTokenizerFactory; + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.icu.ICUFoldingFilterFactory, + org.apache.lucene.analysis.icu.ICUNormalizer2FilterFactory, + org.apache.lucene.analysis.icu.ICUTransformFilterFactory; +} diff --git a/lucene/analysis/kuromoji/build.gradle b/lucene/analysis/kuromoji/build.gradle index af2bfa5ff93..07fc0b0fe31 100644 --- a/lucene/analysis/kuromoji/build.gradle +++ b/lucene/analysis/kuromoji/build.gradle @@ -20,8 +20,8 @@ apply plugin: 'java-library' description = 'Japanese Morphological Analyzer' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/kuromoji/src/java/module-info.java b/lucene/analysis/kuromoji/src/java/module-info.java new file mode 100644 index 00000000000..7c829fd4f2e --- /dev/null +++ b/lucene/analysis/kuromoji/src/java/module-info.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Japanese Morphological Analyzer */ +module org.apache.lucene.analysis.kuromoji { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.ja; + exports org.apache.lucene.analysis.ja.completion; + exports org.apache.lucene.analysis.ja.dict; + exports org.apache.lucene.analysis.ja.tokenattributes; + exports org.apache.lucene.analysis.ja.util; + + provides org.apache.lucene.analysis.CharFilterFactory with + org.apache.lucene.analysis.ja.JapaneseIterationMarkCharFilterFactory; + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.ja.JapaneseTokenizerFactory; + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.ja.JapaneseBaseFormFilterFactory, + org.apache.lucene.analysis.ja.JapaneseCompletionFilterFactory, + org.apache.lucene.analysis.ja.JapaneseKatakanaStemFilterFactory, + org.apache.lucene.analysis.ja.JapaneseNumberFilterFactory, + org.apache.lucene.analysis.ja.JapanesePartOfSpeechStopFilterFactory, + org.apache.lucene.analysis.ja.JapaneseReadingFormFilterFactory; +} diff --git a/lucene/analysis/morfologik.tests/build.gradle b/lucene/analysis/morfologik.tests/build.gradle new file mode 100644 index 00000000000..9cd6720fa1c --- /dev/null +++ b/lucene/analysis/morfologik.tests/build.gradle @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'java-library' + +description = 'Module tests for :lucene:analysis:morfologik' + +dependencies { + moduleTestImplementation project(':lucene:analysis:morfologik') + moduleTestImplementation("junit:junit", { + exclude group: "org.hamcrest" + }) + moduleTestImplementation "org.hamcrest:hamcrest" +} diff --git a/lucene/analysis/morfologik.tests/src/test/module-info.java b/lucene/analysis/morfologik.tests/src/test/module-info.java new file mode 100644 index 00000000000..15642a9421f --- /dev/null +++ b/lucene/analysis/morfologik.tests/src/test/module-info.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Test module for {@code org.apache.lucene.analysis.morfologik}. */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.analysis.morfologik.tests { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + requires org.apache.lucene.analysis.morfologik; + requires junit; + + exports org.apache.lucene.analysis.morfologik.tests; +} diff --git a/lucene/analysis/morfologik.tests/src/test/org/apache/lucene/analysis/morfologik/tests/TestMorfologikAnalyzer.java b/lucene/analysis/morfologik.tests/src/test/org/apache/lucene/analysis/morfologik/tests/TestMorfologikAnalyzer.java new file mode 100644 index 00000000000..c2933fc7f28 --- /dev/null +++ b/lucene/analysis/morfologik.tests/src/test/org/apache/lucene/analysis/morfologik/tests/TestMorfologikAnalyzer.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.analysis.morfologik.tests; + +import org.apache.lucene.analysis.morfologik.MorfologikAnalyzer; +import org.apache.lucene.analysis.uk.UkrainianMorfologikAnalyzer; +import org.apache.lucene.index.IndexWriter; +import org.junit.Assert; +import org.junit.Test; + +public class TestMorfologikAnalyzer { + @Test + public void testMorfologikAnalyzerLoads() { + var analyzer = new MorfologikAnalyzer(); + Assert.assertNotNull(analyzer); + } + + @Test + public void testUkrainianMorfologikAnalyzerLoads() { + var analyzer = new UkrainianMorfologikAnalyzer(); + Assert.assertNotNull(analyzer); + } + + @Test + public void testWeAreModule() { + Assert.assertTrue(this.getClass().getModule().isNamed()); + } + + @Test + public void testLuceneIsAModule() { + Assert.assertTrue(IndexWriter.class.getModule().isNamed()); + } +} diff --git a/lucene/analysis/morfologik/build.gradle b/lucene/analysis/morfologik/build.gradle index 153515fa113..03d7c098d93 100644 --- a/lucene/analysis/morfologik/build.gradle +++ b/lucene/analysis/morfologik/build.gradle @@ -20,13 +20,12 @@ apply plugin: 'java-library' description = 'Analyzer for dictionary stemming, built-in Polish dictionary' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') + moduleApi 'org.carrot2:morfologik-stemming' - api 'org.carrot2:morfologik-stemming' - - implementation 'org.carrot2:morfologik-polish' - implementation 'ua.net.nlp:morfologik-ukrainian-search' + moduleImplementation 'org.carrot2:morfologik-polish' + moduleImplementation 'ua.net.nlp:morfologik-ukrainian-search' testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/morfologik/src/java/module-info.java b/lucene/analysis/morfologik/src/java/module-info.java new file mode 100644 index 00000000000..3268d4b59d2 --- /dev/null +++ b/lucene/analysis/morfologik/src/java/module-info.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Analyzer for dictionary stemming, built-in Polish dictionary */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.analysis.morfologik { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + requires org.carrot2.morfologik.stemming; + requires org.carrot2.morfologik.polish; + requires morfologik.ukrainian.search; + + exports org.apache.lucene.analysis.morfologik; + exports org.apache.lucene.analysis.uk; + + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.morfologik.MorfologikFilterFactory; +} diff --git a/lucene/analysis/morfologik/src/java/org/apache/lucene/analysis/uk/UkrainianMorfologikAnalyzer.java b/lucene/analysis/morfologik/src/java/org/apache/lucene/analysis/uk/UkrainianMorfologikAnalyzer.java index 425a55c6e63..b80ccb69f6c 100644 --- a/lucene/analysis/morfologik/src/java/org/apache/lucene/analysis/uk/UkrainianMorfologikAnalyzer.java +++ b/lucene/analysis/morfologik/src/java/org/apache/lucene/analysis/uk/UkrainianMorfologikAnalyzer.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.Reader; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; +import java.util.Objects; import morfologik.stemming.Dictionary; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.CharArraySet; @@ -42,12 +43,9 @@ import org.apache.lucene.util.IOUtils; * @since 6.2.0 */ public final class UkrainianMorfologikAnalyzer extends StopwordAnalyzerBase { - + private final Dictionary dictionary; private final CharArraySet stemExclusionSet; - /** File containing default Ukrainian stopwords. */ - public static final String DEFAULT_STOPWORD_FILE = "stopwords.txt"; - private static final NormalizeCharMap NORMALIZER_MAP; static { @@ -67,47 +65,72 @@ public final class UkrainianMorfologikAnalyzer extends StopwordAnalyzerBase { NORMALIZER_MAP = builder.build(); } - /** - * Returns an unmodifiable instance of the default stop words set. - * - * @return default stop words set. - */ - public static CharArraySet getDefaultStopSet() { - return DefaultSetHolder.DEFAULT_STOP_SET; + /** Returns a lazy singleton with the default Ukrainian resources. */ + private static volatile DefaultResources defaultResources; + + private static DefaultResources getDefaultResources() { + if (defaultResources == null) { + synchronized (DefaultResources.class) { + try { + CharArraySet wordList; + try (var is = UkrainianMorfologikAnalyzer.class.getResourceAsStream("stopwords.txt")) { + if (is == null) { + throw new IOException("Could not locate the required stopwords resource."); + } + wordList = + WordlistLoader.getSnowballWordSet( + IOUtils.getDecodingReader(is, StandardCharsets.UTF_8)); + } + + // First, try to look up the resource module by name. + Dictionary dictionary; + Module ourModule = DefaultResources.class.getModule(); + if (ourModule.isNamed() && ourModule.getLayer() != null) { + var module = + ourModule + .getLayer() + .findModule("morfologik.ukrainian.search") + .orElseThrow( + () -> + new IOException( + "Can't find the resource module: morfologik.ukrainian.search")); + + try (var fsaStream = module.getResourceAsStream("ua/net/nlp/ukrainian.dict"); + var metaStream = module.getResourceAsStream("ua/net/nlp/ukrainian.info")) { + dictionary = Dictionary.read(fsaStream, metaStream); + } + } else { + dictionary = + Dictionary.read( + Objects.requireNonNull( + UkrainianMorfologikAnalyzer.class + .getClassLoader() + .getResource("ua/net/nlp/ukrainian.dict"), + "Could not locate the required Ukrainian dictionary resource.")); + } + defaultResources = new DefaultResources(wordList, dictionary); + } catch (IOException e) { + throw new UncheckedIOException( + "Could not load the required resources for the Ukrainian analyzer.", e); + } + } + } + return defaultResources; } - /** - * Atomically loads the DEFAULT_STOP_SET and DICTIONARY in a lazy fashion once the outer class - * accesses the static final set the first time.; - */ - private static class DefaultSetHolder { - static final CharArraySet DEFAULT_STOP_SET; - static final Dictionary DICTIONARY; + private static class DefaultResources { + final CharArraySet stopSet; + final Dictionary dictionary; - static { - try { - DEFAULT_STOP_SET = - WordlistLoader.getSnowballWordSet( - IOUtils.getDecodingReader( - UkrainianMorfologikAnalyzer.class, - DEFAULT_STOPWORD_FILE, - StandardCharsets.UTF_8)); - DICTIONARY = - Dictionary.read( - UkrainianMorfologikAnalyzer.class - .getClassLoader() - .getResource("ua/net/nlp/ukrainian.dict")); - } catch (IOException ex) { - // default set should always be present as it is part of the - // distribution (JAR) - throw new UncheckedIOException("Unable to load analyzer resources", ex); - } + private DefaultResources(CharArraySet stopSet, Dictionary dictionary) { + this.stopSet = stopSet; + this.dictionary = dictionary; } } - /** Builds an analyzer with the default stop words: {@link #DEFAULT_STOPWORD_FILE}. */ + /** Builds an analyzer with the default stop words. */ public UkrainianMorfologikAnalyzer() { - this(DefaultSetHolder.DEFAULT_STOP_SET); + this(getDefaultResources().stopSet); } /** @@ -129,6 +152,7 @@ public final class UkrainianMorfologikAnalyzer extends StopwordAnalyzerBase { public UkrainianMorfologikAnalyzer(CharArraySet stopwords, CharArraySet stemExclusionSet) { super(stopwords); this.stemExclusionSet = CharArraySet.unmodifiableSet(CharArraySet.copy(stemExclusionSet)); + this.dictionary = getDefaultResources().dictionary; } @Override @@ -155,7 +179,7 @@ public final class UkrainianMorfologikAnalyzer extends StopwordAnalyzerBase { result = new SetKeywordMarkerFilter(result, stemExclusionSet); } - result = new MorfologikFilter(result, DefaultSetHolder.DICTIONARY); + result = new MorfologikFilter(result, dictionary); return new TokenStreamComponents(source, result); } } diff --git a/lucene/analysis/nori/build.gradle b/lucene/analysis/nori/build.gradle index 430673ce583..079cf50010e 100644 --- a/lucene/analysis/nori/build.gradle +++ b/lucene/analysis/nori/build.gradle @@ -20,8 +20,8 @@ apply plugin: 'java-library' description = 'Korean Morphological Analyzer' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/nori/src/java/module-info.java b/lucene/analysis/nori/src/java/module-info.java new file mode 100644 index 00000000000..9dd085b5a5d --- /dev/null +++ b/lucene/analysis/nori/src/java/module-info.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Korean Morphological Analyzer */ +module org.apache.lucene.analysis.nori { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.ko; + exports org.apache.lucene.analysis.ko.dict; + exports org.apache.lucene.analysis.ko.tokenattributes; + exports org.apache.lucene.analysis.ko.util; + + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.ko.KoreanTokenizerFactory; + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.ko.KoreanPartOfSpeechStopFilterFactory, + org.apache.lucene.analysis.ko.KoreanReadingFormFilterFactory; +} diff --git a/lucene/analysis/opennlp/build.gradle b/lucene/analysis/opennlp/build.gradle index c4672c06abd..3fee61a188e 100644 --- a/lucene/analysis/opennlp/build.gradle +++ b/lucene/analysis/opennlp/build.gradle @@ -20,9 +20,9 @@ apply plugin: 'java-library' description = 'OpenNLP Library Integration' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') - api 'org.apache.opennlp:opennlp-tools' + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') + moduleApi 'org.apache.opennlp:opennlp-tools' testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/opennlp/src/java/module-info.java b/lucene/analysis/opennlp/src/java/module-info.java new file mode 100644 index 00000000000..c63ecfaa387 --- /dev/null +++ b/lucene/analysis/opennlp/src/java/module-info.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** OpenNLP Library Integration */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.analysis.opennlp { + requires org.apache.opennlp.tools; + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.opennlp; + exports org.apache.lucene.analysis.opennlp.tools; + + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.opennlp.OpenNLPTokenizerFactory; + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.opennlp.OpenNLPChunkerFilterFactory, + org.apache.lucene.analysis.opennlp.OpenNLPLemmatizerFilterFactory, + org.apache.lucene.analysis.opennlp.OpenNLPPOSFilterFactory; +} diff --git a/lucene/analysis/phonetic/build.gradle b/lucene/analysis/phonetic/build.gradle index 0f716e82b4a..e5595cb2d76 100644 --- a/lucene/analysis/phonetic/build.gradle +++ b/lucene/analysis/phonetic/build.gradle @@ -20,10 +20,10 @@ apply plugin: 'java-library' description = 'Analyzer for indexing phonetic signatures (for sounds-alike search)' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') - implementation 'commons-codec:commons-codec' + moduleImplementation 'commons-codec:commons-codec' testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/phonetic/src/java/module-info.java b/lucene/analysis/phonetic/src/java/module-info.java new file mode 100644 index 00000000000..706251af4ca --- /dev/null +++ b/lucene/analysis/phonetic/src/java/module-info.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Analyzer for indexing phonetic signatures */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.analysis.phonetic { + requires org.apache.commons.codec; + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.phonetic; + + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.phonetic.BeiderMorseFilterFactory, + org.apache.lucene.analysis.phonetic.DoubleMetaphoneFilterFactory, + org.apache.lucene.analysis.phonetic.PhoneticFilterFactory; +} diff --git a/lucene/analysis/smartcn/build.gradle b/lucene/analysis/smartcn/build.gradle index 8d5eeb1f42d..960be700e71 100644 --- a/lucene/analysis/smartcn/build.gradle +++ b/lucene/analysis/smartcn/build.gradle @@ -20,8 +20,8 @@ apply plugin: 'java-library' description = 'Analyzer for indexing Chinese' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/smartcn/src/java/module-info.java b/lucene/analysis/smartcn/src/java/module-info.java new file mode 100644 index 00000000000..44f4eb53002 --- /dev/null +++ b/lucene/analysis/smartcn/src/java/module-info.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Analyzer for indexing Chinese */ +module org.apache.lucene.analysis.smartcn { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.cn.smart; + exports org.apache.lucene.analysis.cn.smart.hhmm; + + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory; +} diff --git a/lucene/analysis/stempel/build.gradle b/lucene/analysis/stempel/build.gradle index 3b80f9f7f88..32991597fd7 100644 --- a/lucene/analysis/stempel/build.gradle +++ b/lucene/analysis/stempel/build.gradle @@ -20,8 +20,8 @@ apply plugin: 'java-library' description = 'Analyzer for indexing Polish' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') testImplementation project(':lucene:test-framework') } diff --git a/lucene/analysis/stempel/src/java/module-info.java b/lucene/analysis/stempel/src/java/module-info.java new file mode 100644 index 00000000000..d5595483c78 --- /dev/null +++ b/lucene/analysis/stempel/src/java/module-info.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Analyzer for indexing Polish */ +module org.apache.lucene.analysis.stempel { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.analysis.pl; + exports org.apache.lucene.analysis.stempel; + exports org.egothor.stemmer; + + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.analysis.stempel.StempelPolishStemFilterFactory; +} diff --git a/lucene/backward-codecs/build.gradle b/lucene/backward-codecs/build.gradle index aa4730207eb..d5e25d92c49 100644 --- a/lucene/backward-codecs/build.gradle +++ b/lucene/backward-codecs/build.gradle @@ -20,7 +20,7 @@ apply plugin: 'java-library' description = 'Codecs for older versions of Lucene' -dependencies { - api project(':lucene:core') +dependencies { + moduleApi project(':lucene:core') testImplementation project(':lucene:test-framework') } diff --git a/lucene/backward-codecs/src/java/module-info.java b/lucene/backward-codecs/src/java/module-info.java new file mode 100644 index 00000000000..5dfe4efb4ab --- /dev/null +++ b/lucene/backward-codecs/src/java/module-info.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Codecs for older versions of Lucene */ +module org.apache.lucene.backward_codecs { + requires org.apache.lucene.core; + + exports org.apache.lucene.backward_codecs; + exports org.apache.lucene.backward_codecs.lucene40.blocktree; + exports org.apache.lucene.backward_codecs.lucene50; + exports org.apache.lucene.backward_codecs.lucene50.compressing; + exports org.apache.lucene.backward_codecs.lucene60; + exports org.apache.lucene.backward_codecs.lucene70; + exports org.apache.lucene.backward_codecs.lucene80; + exports org.apache.lucene.backward_codecs.lucene84; + exports org.apache.lucene.backward_codecs.lucene86; + exports org.apache.lucene.backward_codecs.lucene87; + exports org.apache.lucene.backward_codecs.packed; + exports org.apache.lucene.backward_codecs.store; + + provides org.apache.lucene.codecs.DocValuesFormat with + org.apache.lucene.backward_codecs.lucene80.Lucene80DocValuesFormat; + provides org.apache.lucene.codecs.PostingsFormat with + org.apache.lucene.backward_codecs.lucene50.Lucene50PostingsFormat, + org.apache.lucene.backward_codecs.lucene84.Lucene84PostingsFormat; + provides org.apache.lucene.codecs.Codec with + org.apache.lucene.backward_codecs.lucene80.Lucene80Codec, + org.apache.lucene.backward_codecs.lucene84.Lucene84Codec, + org.apache.lucene.backward_codecs.lucene86.Lucene86Codec, + org.apache.lucene.backward_codecs.lucene87.Lucene87Codec; +} diff --git a/lucene/benchmark/build.gradle b/lucene/benchmark/build.gradle index 67b1644f3de..9da51c36229 100644 --- a/lucene/benchmark/build.gradle +++ b/lucene/benchmark/build.gradle @@ -22,23 +22,23 @@ plugins { description = 'Lucene benchmarking module' dependencies { - implementation project(':lucene:core') + moduleImplementation project(':lucene:core') - implementation project(':lucene:analysis:common') - implementation project(':lucene:facet') - implementation project(':lucene:highlighter') - implementation project(':lucene:queries') - implementation project(':lucene:spatial-extras') - implementation project(':lucene:queryparser') + moduleImplementation project(':lucene:analysis:common') + moduleImplementation project(':lucene:facet') + moduleImplementation project(':lucene:highlighter') + moduleImplementation project(':lucene:queries') + moduleImplementation project(':lucene:spatial-extras') + moduleImplementation project(':lucene:queryparser') - implementation "org.apache.commons:commons-compress" - implementation "com.ibm.icu:icu4j" - implementation "org.locationtech.spatial4j:spatial4j" - implementation("net.sourceforge.nekohtml:nekohtml", { + moduleImplementation "org.apache.commons:commons-compress" + moduleImplementation "com.ibm.icu:icu4j" + moduleImplementation "org.locationtech.spatial4j:spatial4j" + moduleImplementation ("net.sourceforge.nekohtml:nekohtml", { exclude module: "xml-apis" }) - runtimeOnly project(':lucene:analysis:icu') + moduleRuntimeOnly project(':lucene:analysis:icu') testImplementation project(':lucene:test-framework') } diff --git a/lucene/benchmark/src/java/module-info.java b/lucene/benchmark/src/java/module-info.java new file mode 100644 index 00000000000..f3dfac9b704 --- /dev/null +++ b/lucene/benchmark/src/java/module-info.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.benchmark { + requires java.xml; + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + requires org.apache.lucene.facet; + requires org.apache.lucene.highlighter; + requires org.apache.lucene.queries; + requires org.apache.lucene.queryparser; + requires org.apache.lucene.spatial_extras; + requires spatial4j; + + exports org.apache.lucene.benchmark; + exports org.apache.lucene.benchmark.byTask; + exports org.apache.lucene.benchmark.byTask.feeds; + exports org.apache.lucene.benchmark.byTask.programmatic; + exports org.apache.lucene.benchmark.byTask.stats; + exports org.apache.lucene.benchmark.byTask.tasks; + exports org.apache.lucene.benchmark.byTask.utils; + exports org.apache.lucene.benchmark.quality; + exports org.apache.lucene.benchmark.quality.trec; + exports org.apache.lucene.benchmark.quality.utils; + exports org.apache.lucene.benchmark.utils; +} diff --git a/lucene/classification/build.gradle b/lucene/classification/build.gradle index 736dfb305a7..8566cdbf146 100644 --- a/lucene/classification/build.gradle +++ b/lucene/classification/build.gradle @@ -20,10 +20,10 @@ apply plugin: 'java-library' description = 'Classification module for Lucene' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:queries') - implementation project(':lucene:grouping') + moduleImplementation project(':lucene:queries') + moduleImplementation project(':lucene:grouping') testImplementation project(':lucene:test-framework') testImplementation project(':lucene:analysis:common') diff --git a/lucene/classification/src/java/module-info.java b/lucene/classification/src/java/module-info.java new file mode 100644 index 00000000000..4817d8a21ce --- /dev/null +++ b/lucene/classification/src/java/module-info.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Classification module for Lucene */ +module org.apache.lucene.classification { + requires org.apache.lucene.core; + requires org.apache.lucene.queries; + requires org.apache.lucene.grouping; + + exports org.apache.lucene.classification; + exports org.apache.lucene.classification.document; + exports org.apache.lucene.classification.utils; +} diff --git a/lucene/codecs/build.gradle b/lucene/codecs/build.gradle index ad26aae2d94..92e0782c9c0 100644 --- a/lucene/codecs/build.gradle +++ b/lucene/codecs/build.gradle @@ -20,6 +20,6 @@ apply plugin: 'java-library' description = 'Lucene codecs and postings formats' dependencies { - implementation project(':lucene:core') + moduleImplementation project(':lucene:core') testImplementation project(':lucene:test-framework') } diff --git a/lucene/codecs/src/java/module-info.java b/lucene/codecs/src/java/module-info.java new file mode 100644 index 00000000000..73f53fbf96b --- /dev/null +++ b/lucene/codecs/src/java/module-info.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Lucene codecs and postings formats */ +module org.apache.lucene.codecs { + requires org.apache.lucene.core; + + exports org.apache.lucene.codecs.blockterms; + exports org.apache.lucene.codecs.blocktreeords; + exports org.apache.lucene.codecs.bloom; + exports org.apache.lucene.codecs.memory; + exports org.apache.lucene.codecs.simpletext; + exports org.apache.lucene.codecs.uniformsplit; + exports org.apache.lucene.codecs.uniformsplit.sharedterms; + + provides org.apache.lucene.codecs.PostingsFormat with + org.apache.lucene.codecs.blocktreeords.BlockTreeOrdsPostingsFormat, + org.apache.lucene.codecs.bloom.BloomFilteringPostingsFormat, + org.apache.lucene.codecs.memory.DirectPostingsFormat, + org.apache.lucene.codecs.memory.FSTPostingsFormat, + org.apache.lucene.codecs.uniformsplit.UniformSplitPostingsFormat, + org.apache.lucene.codecs.uniformsplit.sharedterms.STUniformSplitPostingsFormat; + provides org.apache.lucene.codecs.Codec with + org.apache.lucene.codecs.simpletext.SimpleTextCodec; +} diff --git a/lucene/core/src/java/module-info.java b/lucene/core/src/java/module-info.java new file mode 100644 index 00000000000..931d4cbac2d --- /dev/null +++ b/lucene/core/src/java/module-info.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Lucene Core. */ +module org.apache.lucene.core { + requires jdk.unsupported; // this is needed for MMapDirectory to unmap + + exports org.apache.lucene.analysis; + exports org.apache.lucene.analysis.standard; + exports org.apache.lucene.analysis.tokenattributes; + exports org.apache.lucene.codecs; + exports org.apache.lucene.codecs.compressing; + exports org.apache.lucene.codecs.lucene90; + exports org.apache.lucene.codecs.lucene90.blocktree; + exports org.apache.lucene.codecs.lucene90.compressing; + exports org.apache.lucene.codecs.perfield; + exports org.apache.lucene.document; + exports org.apache.lucene.geo; + exports org.apache.lucene.index; + exports org.apache.lucene.search; + exports org.apache.lucene.search.comparators; + exports org.apache.lucene.search.similarities; + exports org.apache.lucene.store; + exports org.apache.lucene.util; + exports org.apache.lucene.util.automaton; + exports org.apache.lucene.util.bkd; + exports org.apache.lucene.util.compress; + exports org.apache.lucene.util.fst; + exports org.apache.lucene.util.graph; + exports org.apache.lucene.util.hnsw; + exports org.apache.lucene.util.hppc; + exports org.apache.lucene.util.mutable; + exports org.apache.lucene.util.packed; + + provides org.apache.lucene.analysis.TokenizerFactory with + org.apache.lucene.analysis.standard.StandardTokenizerFactory; + provides org.apache.lucene.codecs.Codec with + org.apache.lucene.codecs.lucene90.Lucene90Codec; + provides org.apache.lucene.codecs.DocValuesFormat with + org.apache.lucene.codecs.lucene90.Lucene90DocValuesFormat; + provides org.apache.lucene.codecs.KnnVectorsFormat with + org.apache.lucene.codecs.lucene90.Lucene90HnswVectorsFormat; + provides org.apache.lucene.codecs.PostingsFormat with + org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat; + provides org.apache.lucene.index.SortFieldProvider with + org.apache.lucene.search.SortField.Provider, + org.apache.lucene.search.SortedNumericSortField.Provider, + org.apache.lucene.search.SortedSetSortField.Provider; + + uses org.apache.lucene.analysis.CharFilterFactory; + uses org.apache.lucene.analysis.TokenFilterFactory; + uses org.apache.lucene.analysis.TokenizerFactory; + uses org.apache.lucene.codecs.Codec; + uses org.apache.lucene.codecs.DocValuesFormat; + uses org.apache.lucene.codecs.KnnVectorsFormat; + uses org.apache.lucene.codecs.PostingsFormat; + uses org.apache.lucene.index.SortFieldProvider; +} diff --git a/lucene/demo/build.gradle b/lucene/demo/build.gradle index 3624328785a..70fd1df8248 100644 --- a/lucene/demo/build.gradle +++ b/lucene/demo/build.gradle @@ -20,12 +20,12 @@ apply plugin: 'java-library' description = 'Simple example code for Apache Lucene' dependencies { - implementation project(':lucene:core') - implementation project(':lucene:facet') - implementation project(':lucene:queries') - implementation project(':lucene:analysis:common') - implementation project(':lucene:queryparser') - implementation project(':lucene:expressions') + moduleImplementation project(':lucene:core') + moduleImplementation project(':lucene:facet') + moduleImplementation project(':lucene:queries') + moduleImplementation project(':lucene:analysis:common') + moduleImplementation project(':lucene:queryparser') + moduleImplementation project(':lucene:expressions') testImplementation project(':lucene:test-framework') } diff --git a/lucene/demo/src/java/module-info.java b/lucene/demo/src/java/module-info.java new file mode 100644 index 00000000000..13549a56385 --- /dev/null +++ b/lucene/demo/src/java/module-info.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Simple example code for Apache Lucene */ +module org.apache.lucene.demo { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + requires org.apache.lucene.facet; + requires org.apache.lucene.queries; + requires org.apache.lucene.queryparser; + requires org.apache.lucene.expressions; + + exports org.apache.lucene.demo; + exports org.apache.lucene.demo.facet; + exports org.apache.lucene.demo.knn; +} diff --git a/lucene/distribution.tests/build.gradle b/lucene/distribution.tests/build.gradle new file mode 100644 index 00000000000..30c4ae136cc --- /dev/null +++ b/lucene/distribution.tests/build.gradle @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id 'java-library' +} + +configurations { + // This is a configuration that references an 'folder-expanded' binary distribution + // tests will run against. The distribution is slightly trimmed (no docs, licenses) + // because we don't test these parts of the distribution anyway. + binaryDistribution +} + +dependencies { + binaryDistribution project(path: ":lucene:distribution", configuration: "binaryDirForTests") + + moduleTestImplementation("com.carrotsearch.randomizedtesting:randomizedtesting-runner", { + exclude group: "junit" + }) + + moduleTestImplementation("junit:junit", { + exclude group: "org.hamcrest" + }) + moduleTestImplementation "org.hamcrest:hamcrest" + moduleTestImplementation "org.assertj:assertj-core" +} + +test { + dependsOn configurations.binaryDistribution + + // We need to pass the system property using a lazy provider, not supported at the moment: + // https://github.com/gradle/gradle/issues/12247 + // so we'll use a workaround and pass command-line arguments directly. + jvmArgumentProviders.add(new CommandLineArgumentProvider() { + @Override + Iterable asArguments() { + return [ + "-Dlucene.distribution.dir=${configurations.binaryDistribution.singleFile.absolutePath }", + "-Dlucene.distribution.version=${project.version}" + ] + } + }) + + doFirst { + logger.lifecycle("Testing binary distribution at: ${configurations.binaryDistribution.singleFile}") + } +} \ No newline at end of file diff --git a/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java b/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java new file mode 100644 index 00000000000..56270899060 --- /dev/null +++ b/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java @@ -0,0 +1,295 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.distribution; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.Assumptions; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Sanity checks concerning the distribution's binary artifacts (modules). + * + *

We do not want this module to depend on any Lucene classes (including the test + * framework) so that there is no risk of accidental classpath space pollution. This also means the + * default {@code LuceneTestCase} configuration setup is not used (you have to annotate test for + * JUnit, for example). + */ +public class TestModularLayer { + /** A path to a directory with an expanded Lucene distribution. */ + private static final String DISTRIBUTION_PROPERTY = "lucene.distribution.dir"; + + /** The expected distribution version of Lucene modules. */ + private static final String VERSION_PROPERTY = "lucene.distribution.version"; + + /** Only core Lucene modules, no third party modules. */ + private static Set allCoreModules; + + /** {@link ModuleFinder} resolving only the Lucene modules. */ + private static ModuleFinder coreModulesFinder; + + /** Ensure Lucene classes are not directly visible. */ + @BeforeClass + public static void checkLuceneNotInClasspath() { + Assertions.assertThatThrownBy( + () -> { + Class.forName("org.apache.lucene.index.IndexWriter"); + }) + .isInstanceOf(ClassNotFoundException.class); + } + + /** + * We accept external properties that point to the assembled set of distribution modules and to + * their expected version. These properties are collected and passed by gradle but can be provided + * manually (for IDE launches). + */ + @BeforeClass + public static void checkModulePathProvided() { + String modulesPropertyValue = System.getProperty(DISTRIBUTION_PROPERTY); + if (modulesPropertyValue == null) { + throw new AssertionError(DISTRIBUTION_PROPERTY + " property is required for this test."); + } + + Path modulesPath = Paths.get(modulesPropertyValue).resolve("modules"); + if (!Files.isDirectory(modulesPath)) { + throw new AssertionError( + DISTRIBUTION_PROPERTY + + " property does not point to a directory where this path is present: " + + modulesPath.toAbsolutePath()); + } + + Path thirdPartyModulesPath = Paths.get(modulesPropertyValue).resolve("modules-thirdparty"); + if (!Files.isDirectory(thirdPartyModulesPath)) { + throw new AssertionError( + DISTRIBUTION_PROPERTY + + " property does not point to a directory where this path is present: " + + thirdPartyModulesPath.toAbsolutePath()); + } + + coreModulesFinder = ModuleFinder.of(modulesPath); + allCoreModules = coreModulesFinder.findAll(); + } + + @AfterClass + public static void cleanup() { + allCoreModules = null; + coreModulesFinder = null; + } + + /** Make sure all published module names remain constant, even if we reorganize the build. */ + @Test + public void testExpectedDistributionModuleNames() { + Assertions.assertThat( + allCoreModules.stream().map(module -> module.descriptor().name()).sorted()) + .containsExactly( + "org.apache.lucene.analysis.common", + "org.apache.lucene.analysis.icu", + "org.apache.lucene.analysis.kuromoji", + "org.apache.lucene.analysis.morfologik", + "org.apache.lucene.analysis.nori", + "org.apache.lucene.analysis.opennlp", + "org.apache.lucene.analysis.phonetic", + "org.apache.lucene.analysis.smartcn", + "org.apache.lucene.analysis.stempel", + "org.apache.lucene.backward_codecs", + "org.apache.lucene.benchmark", + "org.apache.lucene.classification", + "org.apache.lucene.codecs", + "org.apache.lucene.core", + "org.apache.lucene.demo", + "org.apache.lucene.expressions", + "org.apache.lucene.facet", + "org.apache.lucene.grouping", + "org.apache.lucene.highlighter", + "org.apache.lucene.join", + "org.apache.lucene.luke", + "org.apache.lucene.memory", + "org.apache.lucene.misc", + "org.apache.lucene.monitor", + "org.apache.lucene.queries", + "org.apache.lucene.queryparser", + "org.apache.lucene.replicator", + "org.apache.lucene.sandbox", + "org.apache.lucene.spatial3d", + "org.apache.lucene.spatial_extras", + "org.apache.lucene.suggest"); + } + + /** Make sure we don't publish automatic modules. */ + @Test + public void testAllCoreModulesAreNamedModules() { + Assertions.assertThat(allCoreModules) + .allSatisfy( + module -> { + Assertions.assertThat(module.descriptor().isAutomatic()) + .as(module.descriptor().name()) + .isFalse(); + }); + } + + /** Ensure all modules have the same (expected) version. */ + @Test + public void testAllModulesHaveExpectedVersion() { + String luceneBuildVersion = System.getProperty(VERSION_PROPERTY); + Assumptions.assumeThat(luceneBuildVersion).isNotNull(); + for (var module : allCoreModules) { + Assertions.assertThat(module.descriptor().rawVersion().orElse(null)) + .as("Version of module: " + module.descriptor().name()) + .isEqualTo(luceneBuildVersion); + } + } + + /** Ensure SPIs are equal for the module and classpath layer. */ + @Test + public void testModularAndClasspathProvidersAreConsistent() throws IOException { + for (var module : allCoreModules) { + TreeMap> modularProviders = getModularServiceProviders(module); + TreeMap> classpathProviders = getClasspathServiceProviders(module); + + // Compare services first so that the exception is shorter. + Assertions.assertThat(modularProviders.keySet()) + .as("Modular services in module: " + module.descriptor().name()) + .containsExactlyInAnyOrderElementsOf(classpathProviders.keySet()); + + // We're sure the services correspond to each other. Now, for each service, compare the + // providers. + for (var service : modularProviders.keySet()) { + Assertions.assertThat(modularProviders.get(service)) + .as( + "Modular providers of service " + + service + + " in module: " + + module.descriptor().name()) + .containsExactlyInAnyOrderElementsOf(classpathProviders.get(service)); + } + } + } + + private TreeMap> getClasspathServiceProviders(ModuleReference module) + throws IOException { + TreeMap> services = new TreeMap<>(); + Pattern serviceEntryPattern = Pattern.compile("META-INF/services/(?.+)"); + try (ModuleReader reader = module.open(); + Stream entryStream = reader.list()) { + List serviceProviderEntryList = + entryStream + .filter(entry -> serviceEntryPattern.matcher(entry).find()) + .collect(Collectors.toList()); + + for (String entry : serviceProviderEntryList) { + List implementations; + try (InputStream is = reader.open(entry).get()) { + implementations = + Arrays.stream(new String(is.readAllBytes(), StandardCharsets.UTF_8).split("\n")) + .map(String::trim) + .filter(line -> !line.isBlank() && !line.startsWith("#")) + .collect(Collectors.toList()); + } + + Matcher matcher = serviceEntryPattern.matcher(entry); + if (!matcher.find()) { + throw new AssertionError("Impossible."); + } + String service = matcher.group("serviceName"); + services.computeIfAbsent(service, k -> new TreeSet<>()).addAll(implementations); + } + } + + return services; + } + + private static TreeMap> getModularServiceProviders( + ModuleReference module) { + return module.descriptor().provides().stream() + .collect( + Collectors.toMap( + ModuleDescriptor.Provides::service, + provides -> new TreeSet<>(provides.providers()), + (k, v) -> { + throw new RuntimeException(); + }, + TreeMap::new)); + } + + /** + * Ensure all exported packages in the descriptor are in sync with the module's Java classes. + * + *

This test should be progressively tuned so that certain internal packages are hidden in the + * module layer. + */ + @Test + public void testAllOpenPackagesInSync() throws IOException { + for (var module : allCoreModules) { + Set jarPackages = getJarPackages(module); + + if (module.descriptor().name().equals("org.apache.lucene.luke")) { + jarPackages.removeIf( + entry -> { + // Luke's packages are not exported. + return entry.startsWith("org.apache.lucene.luke"); + }); + } + + Set moduleExports = module.descriptor().exports(); + Assertions.assertThat(moduleExports) + .as("Exported packages in module: " + module.descriptor().name()) + .allSatisfy( + export -> { + Assertions.assertThat(export.targets()) + .as("We only support unqualified exports for now?") + .isEmpty(); + }) + .map(ModuleDescriptor.Exports::source) + .containsExactlyInAnyOrderElementsOf(jarPackages); + } + } + + private Set getJarPackages(ModuleReference module) throws IOException { + try (ModuleReader reader = module.open()) { + return reader + .list() + .filter( + entry -> + !entry.startsWith("META-INF/") + && !entry.equals("module-info.class") + && !entry.endsWith("/")) + .map(entry -> entry.replaceAll("/[^/]+$", "")) + .map(entry -> entry.replace('/', '.')) + .collect(Collectors.toCollection(TreeSet::new)); + } + } +} diff --git a/lucene/distribution/binary-release.gradle b/lucene/distribution/binary-release.gradle index c06bb1a8777..be2ae6005ea 100644 --- a/lucene/distribution/binary-release.gradle +++ b/lucene/distribution/binary-release.gradle @@ -28,6 +28,8 @@ configure(project(":lucene:distribution")) { jars jarsTestFramework jarsThirdParty + + binaryDirForTests } dependencies { DependencyHandler handler -> @@ -63,7 +65,6 @@ configure(project(":lucene:distribution")) { } } - task assembleBinaryTgz(type: Tar) { description "Assemble binary Lucene artifact as a .tgz file." @@ -73,6 +74,26 @@ configure(project(":lucene:distribution")) { reproducibleFileOrder = true compression = Compression.GZIP + // Internal archive folder for all files. + into "lucene-${rootProject.version}/" + } + + task assembleBinaryDirForTests(type: Sync) { + description "Assemble a subset of the binary Lucene distribution as an expanded directory for tests." + + destinationDir file("${packageBaseName}-itests") + } + + artifacts { + binaryDirForTests tasks.assembleBinaryDirForTests.destinationDir, { + builtBy tasks.assembleBinaryDirForTests + } + } + + // Configure distribution content for archives and stand-alone directories. + // This is split into binaries and other artifacts to speed up distribution + // tests. + Closure distributionBinaryContent = { AbstractCopyTask task -> // Manually correct posix permissions (matters when assembling archives on Windows). filesMatching(["**/*.sh", "**/*.bat"]) { copy -> copy.setMode(0755) @@ -83,6 +104,21 @@ configure(project(":lucene:distribution")) { filteringCharset = 'UTF-8' }) + // Binary modules (Lucene). + from(configurations.jars, { + into 'modules' + }) + from(configurations.jarsTestFramework, { + into 'modules-test-framework' + }) + + // Binary modules (with dependencies). Don't duplicate project artifacts. + from((configurations.jarsThirdParty - configurations.jars), { + into 'modules-thirdparty' + }) + } + + Closure distributionOtherContent = { AbstractCopyTask task -> // Cherry-pick certain files from the root. from(project(':').projectDir, { include "LICENSE.txt" @@ -102,21 +138,14 @@ configure(project(":lucene:distribution")) { from(configurations.docs, { into 'docs' }) + } - // Binary modules (Lucene). - from(configurations.jars, { - into 'modules' - }) - from(configurations.jarsTestFramework, { - into 'modules-test-framework' - }) + [tasks.assembleBinaryTgz].each { Task task -> + task.configure distributionBinaryContent + task.configure distributionOtherContent + } - // Binary modules (with dependencies). Don't duplicate project artifacts. - from((configurations.jarsThirdParty - configurations.jars), { - into 'modules-thirdparty' - }) - - // Internal archive folder for all files. - into "lucene-${rootProject.version}/" + [tasks.assembleBinaryDirForTests].each { Task task -> + task.configure distributionBinaryContent } } diff --git a/lucene/distribution/src/binary-release/bin/luke.cmd b/lucene/distribution/src/binary-release/bin/luke.cmd index b4591aedafe..ee5d06ccbb4 100644 --- a/lucene/distribution/src/binary-release/bin/luke.cmd +++ b/lucene/distribution/src/binary-release/bin/luke.cmd @@ -17,5 +17,5 @@ SETLOCAL SET MODULES=%~dp0.. -start javaw --module-path "%MODULES%\modules;%MODULES%\modules-thirdparty" --add-modules jdk.unsupported --module org.apache.lucene.luke +start javaw --module-path "%MODULES%\modules;%MODULES%\modules-thirdparty" --module org.apache.lucene.luke ENDLOCAL diff --git a/lucene/distribution/src/binary-release/bin/luke.sh b/lucene/distribution/src/binary-release/bin/luke.sh index 053eddacd80..b934f4eb082 100644 --- a/lucene/distribution/src/binary-release/bin/luke.sh +++ b/lucene/distribution/src/binary-release/bin/luke.sh @@ -17,4 +17,4 @@ MODULES=`dirname "$0"`/.. MODULES=`cd "$MODULES" && pwd` -java --module-path "$MODULES/modules:$MODULES/modules-thirdparty" --add-modules jdk.unsupported --module org.apache.lucene.luke +java --module-path "$MODULES/modules:$MODULES/modules-thirdparty" --module org.apache.lucene.luke diff --git a/lucene/expressions/build.gradle b/lucene/expressions/build.gradle index 7ba76a7f3a9..6823ae68782 100644 --- a/lucene/expressions/build.gradle +++ b/lucene/expressions/build.gradle @@ -20,21 +20,14 @@ apply plugin: 'java-library' description = 'Dynamically computed values to sort/facet/search on based on a pluggable grammar' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:codecs') + moduleImplementation project(':lucene:codecs') - implementation 'org.antlr:antlr4-runtime' + moduleImplementation 'org.antlr:antlr4-runtime' - // It is awkward that we force-omit the intermediate dependency here... - // The dependency chain is: - // asm-commons -> asm-tree -> asm - // Should we really go through these hoops? - implementation 'org.ow2.asm:asm' - implementation('org.ow2.asm:asm-commons', { - exclude group: "org.ow2.asm", module: "asm-tree" - exclude group: "org.ow2.asm", module: "asm-analysis" - }) + moduleImplementation 'org.ow2.asm:asm' + moduleImplementation 'org.ow2.asm:asm-commons' testImplementation project(':lucene:test-framework') } diff --git a/lucene/expressions/src/java/module-info.java b/lucene/expressions/src/java/module-info.java new file mode 100644 index 00000000000..108f4532483 --- /dev/null +++ b/lucene/expressions/src/java/module-info.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.expressions { + requires org.objectweb.asm; + requires org.objectweb.asm.commons; + requires antlr4.runtime; + requires org.apache.lucene.core; + requires org.apache.lucene.codecs; + + exports org.apache.lucene.expressions; + exports org.apache.lucene.expressions.js; +} diff --git a/lucene/facet/build.gradle b/lucene/facet/build.gradle index b4f3ac588ac..1b16f94d574 100644 --- a/lucene/facet/build.gradle +++ b/lucene/facet/build.gradle @@ -20,10 +20,10 @@ apply plugin: 'java-library' description = 'Faceted indexing and search capabilities' -dependencies { - api project(':lucene:core') +dependencies { + moduleApi project(':lucene:core') - implementation 'com.carrotsearch:hppc' + moduleImplementation 'com.carrotsearch:hppc' testImplementation project(':lucene:test-framework') testImplementation project(':lucene:queries') diff --git a/lucene/facet/src/java/module-info.java b/lucene/facet/src/java/module-info.java new file mode 100644 index 00000000000..26859cce6a4 --- /dev/null +++ b/lucene/facet/src/java/module-info.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Faceted indexing and search capabilities */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.facet { + requires java.logging; + requires com.carrotsearch.hppc; + requires org.apache.lucene.core; + + exports org.apache.lucene.facet; + exports org.apache.lucene.facet.range; + exports org.apache.lucene.facet.sortedset; + exports org.apache.lucene.facet.taxonomy; + exports org.apache.lucene.facet.taxonomy.directory; + exports org.apache.lucene.facet.taxonomy.writercache; +} diff --git a/lucene/grouping/build.gradle b/lucene/grouping/build.gradle index 6e719645c7e..7035a11c692 100644 --- a/lucene/grouping/build.gradle +++ b/lucene/grouping/build.gradle @@ -21,9 +21,9 @@ apply plugin: 'java-library' description = 'Collectors for grouping search results' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:queries') + moduleImplementation project(':lucene:queries') testImplementation project(':lucene:test-framework') } diff --git a/lucene/grouping/src/java/module-info.java b/lucene/grouping/src/java/module-info.java new file mode 100644 index 00000000000..0f9665eb827 --- /dev/null +++ b/lucene/grouping/src/java/module-info.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Collectors for grouping search results */ +module org.apache.lucene.grouping { + requires org.apache.lucene.core; + requires org.apache.lucene.queries; + + exports org.apache.lucene.search.grouping; +} diff --git a/lucene/highlighter/build.gradle b/lucene/highlighter/build.gradle index 6bd842690da..105f1dee539 100644 --- a/lucene/highlighter/build.gradle +++ b/lucene/highlighter/build.gradle @@ -21,10 +21,10 @@ apply plugin: 'java-library' description = 'Highlights search keywords in results' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:queries') - implementation project(':lucene:memory') + moduleImplementation project(':lucene:queries') + moduleImplementation project(':lucene:memory') testImplementation project(':lucene:test-framework') testImplementation project(':lucene:analysis:common') diff --git a/lucene/highlighter/src/java/module-info.java b/lucene/highlighter/src/java/module-info.java new file mode 100644 index 00000000000..64da8b5cd9f --- /dev/null +++ b/lucene/highlighter/src/java/module-info.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Highlights search keywords in results */ +module org.apache.lucene.highlighter { + requires org.apache.lucene.core; + requires org.apache.lucene.queries; + requires org.apache.lucene.memory; + + exports org.apache.lucene.search.highlight; + exports org.apache.lucene.search.matchhighlight; + exports org.apache.lucene.search.uhighlight; + exports org.apache.lucene.search.vectorhighlight; +} diff --git a/lucene/join/build.gradle b/lucene/join/build.gradle index 143daa13711..d8c2eabc52d 100644 --- a/lucene/join/build.gradle +++ b/lucene/join/build.gradle @@ -20,6 +20,6 @@ apply plugin: 'java-library' description = 'Index-time and Query-time joins for normalized content' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') testImplementation project(':lucene:test-framework') } \ No newline at end of file diff --git a/lucene/join/src/java/module-info.java b/lucene/join/src/java/module-info.java new file mode 100644 index 00000000000..80d2261b5a5 --- /dev/null +++ b/lucene/join/src/java/module-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Index-time and Query-time joins for normalized content */ +module org.apache.lucene.join { + requires org.apache.lucene.core; + + exports org.apache.lucene.search.join; +} diff --git a/lucene/licenses/asm-analysis-7.2.jar.sha1 b/lucene/licenses/asm-analysis-7.2.jar.sha1 new file mode 100644 index 00000000000..b0a8b7b83ed --- /dev/null +++ b/lucene/licenses/asm-analysis-7.2.jar.sha1 @@ -0,0 +1 @@ +b6e6abe057f23630113f4167c34bda7086691258 diff --git a/lucene/licenses/asm-tree-7.2.jar.sha1 b/lucene/licenses/asm-tree-7.2.jar.sha1 new file mode 100644 index 00000000000..077d6f9c411 --- /dev/null +++ b/lucene/licenses/asm-tree-7.2.jar.sha1 @@ -0,0 +1 @@ +3a23cc36edaf8fc5a89cb100182758ccb5991487 diff --git a/lucene/licenses/assertj-core-3.21.0.jar.sha1 b/lucene/licenses/assertj-core-3.21.0.jar.sha1 new file mode 100644 index 00000000000..91082594e4f --- /dev/null +++ b/lucene/licenses/assertj-core-3.21.0.jar.sha1 @@ -0,0 +1 @@ +27a14d6d22c4e3d58f799fb2a5ca8eaf53e6942a diff --git a/lucene/licenses/assertj-core-LICENSE-ASL.txt b/lucene/licenses/assertj-core-LICENSE-ASL.txt new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/lucene/licenses/assertj-core-LICENSE-ASL.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/lucene/licenses/assertj-core-NOTICE.txt b/lucene/licenses/assertj-core-NOTICE.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lucene/luke/build.gradle b/lucene/luke/build.gradle index fe556ca9527..6def3e6d88b 100644 --- a/lucene/luke/build.gradle +++ b/lucene/luke/build.gradle @@ -25,25 +25,25 @@ ext { } dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:codecs') - implementation project(':lucene:backward-codecs') - implementation project(':lucene:analysis:common') - implementation project(':lucene:queries') - implementation project(':lucene:queryparser') - implementation project(':lucene:misc') + moduleImplementation project(':lucene:codecs') + moduleImplementation project(':lucene:backward-codecs') + moduleImplementation project(':lucene:analysis:common') + moduleImplementation project(':lucene:queries') + moduleImplementation project(':lucene:queryparser') + moduleImplementation project(':lucene:misc') - implementation project(":lucene:highlighter") - implementation project(':lucene:analysis:icu') - implementation project(':lucene:analysis:kuromoji') - implementation project(':lucene:analysis:morfologik') - implementation project(':lucene:analysis:nori') - implementation project(':lucene:analysis:opennlp') - implementation project(':lucene:analysis:phonetic') - implementation project(':lucene:analysis:smartcn') - implementation project(':lucene:analysis:stempel') - implementation project(':lucene:suggest') + moduleImplementation project(":lucene:highlighter") + moduleImplementation project(':lucene:analysis:icu') + moduleImplementation project(':lucene:analysis:kuromoji') + moduleImplementation project(':lucene:analysis:morfologik') + moduleImplementation project(':lucene:analysis:nori') + moduleImplementation project(':lucene:analysis:opennlp') + moduleImplementation project(':lucene:analysis:phonetic') + moduleImplementation project(':lucene:analysis:smartcn') + moduleImplementation project(':lucene:analysis:stempel') + moduleImplementation project(':lucene:suggest') testImplementation project(':lucene:test-framework') } @@ -55,6 +55,11 @@ tasks.withType(Jar) { } } +// Configure the main class and version attribute for the module system. +tasks.compileJava.configure { + options.javaModuleMainClass.set("org.apache.lucene.luke.app.desktop.LukeMain") +} + // Process UTF8 property files to unicode escapes. tasks.withType(ProcessResources).configureEach { task -> task.filesMatching("**/messages*.properties", { @@ -105,8 +110,13 @@ task standaloneAssemble(type: Sync) { into standaloneDistDir doLast { - logger.lifecycle("Standalone Luke distribution assembled. You can run it with:\n" - + "java -jar " + file("${standaloneDistDir}/${standaloneJar.archiveFileName.get()}")) + logger.lifecycle( + """ +Standalone Luke distribution assembled. You can run it with: +java -jar "${standaloneDistDir}/${standaloneJar.archiveFileName.get()}" +java --module-path "${standaloneDistDir}" -m org.apache.lucene.luke + """ + ) } } @@ -141,3 +151,4 @@ task run() { } } } + diff --git a/lucene/luke/src/java/module-info.java b/lucene/luke/src/java/module-info.java new file mode 100644 index 00000000000..101d4ae3f8b --- /dev/null +++ b/lucene/luke/src/java/module-info.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Luke : Lucene toolbox project. */ +module org.apache.lucene.luke { + requires java.desktop; + requires java.logging; + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + requires org.apache.lucene.queries; + requires org.apache.lucene.queryparser; + requires org.apache.lucene.misc; +} diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java index f64ec18bd2c..cd78468e3d6 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java @@ -20,8 +20,8 @@ package org.apache.lucene.luke.app.desktop; import static org.apache.lucene.luke.app.desktop.util.ExceptionHandler.handle; import java.awt.GraphicsEnvironment; -import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.util.concurrent.SynchronousQueue; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; @@ -48,19 +48,19 @@ public class LukeMain { return frame; } - private static void createAndShowGUI() { + /** @return Returns {@code true} if GUI startup and initialization was successful. */ + private static boolean createAndShowGUI() { // uncaught error handler MessageBroker messageBroker = MessageBroker.getInstance(); - Thread.setDefaultUncaughtExceptionHandler((thread, cause) -> handle(cause, messageBroker)); - try { + Thread.setDefaultUncaughtExceptionHandler((thread, cause) -> handle(cause, messageBroker)); + frame = new LukeWindowProvider().get(); frame.setLocation(200, 100); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); - // show open index dialog OpenIndexDialogFactory openIndexDialogFactory = OpenIndexDialogFactory.getInstance(); new DialogOpener<>(openIndexDialogFactory) .open( @@ -68,9 +68,12 @@ public class LukeMain { 600, 420, (factory) -> {}); - } catch (IOException e) { + + return true; + } catch (Throwable e) { messageBroker.showUnknownErrorMessage(); log.log(Level.SEVERE, "Cannot initialize components.", e); + return false; } } @@ -86,6 +89,19 @@ public class LukeMain { GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment(); genv.registerFont(FontUtils.createElegantIconFont()); - javax.swing.SwingUtilities.invokeLater(LukeMain::createAndShowGUI); + var guiThreadResult = new SynchronousQueue(); + javax.swing.SwingUtilities.invokeLater( + () -> { + try { + guiThreadResult.put(createAndShowGUI()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + + if (Boolean.FALSE.equals(guiThreadResult.take())) { + Logger.getGlobal().log(Level.SEVERE, "Luke could not start."); + Runtime.getRuntime().exit(1); + } } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/FontUtils.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/FontUtils.java index 02c201ea448..90f5c2c6b42 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/FontUtils.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/FontUtils.java @@ -27,9 +27,7 @@ import javax.swing.JLabel; /** Font utilities */ public class FontUtils { - - public static final String TTF_RESOURCE_NAME = - "org/apache/lucene/luke/app/desktop/font/ElegantIcons.ttf"; + private static final String TTF_RESOURCE_NAME = "ElegantIcons.ttf"; @SuppressWarnings("unchecked") public static JLabel toLinkText(JLabel label) { @@ -42,7 +40,7 @@ public class FontUtils { } public static Font createElegantIconFont() throws IOException, FontFormatException { - InputStream is = FontUtils.class.getClassLoader().getResourceAsStream(TTF_RESOURCE_NAME); + InputStream is = FontUtils.class.getResourceAsStream(TTF_RESOURCE_NAME); return Font.createFont(Font.TRUETYPE_FONT, is); } diff --git a/lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/font/ElegantIcons.ttf b/lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/util/ElegantIcons.ttf similarity index 100% rename from lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/font/ElegantIcons.ttf rename to lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/util/ElegantIcons.ttf diff --git a/lucene/memory/build.gradle b/lucene/memory/build.gradle index 0d3bc1f7b03..eb6626e6d4d 100644 --- a/lucene/memory/build.gradle +++ b/lucene/memory/build.gradle @@ -21,7 +21,7 @@ apply plugin: 'java-library' description = 'Single-document in-memory index implementation' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') testImplementation project(':lucene:test-framework') testImplementation project(':lucene:queryparser') diff --git a/lucene/memory/src/java/module-info.java b/lucene/memory/src/java/module-info.java new file mode 100644 index 00000000000..1d4f84a0588 --- /dev/null +++ b/lucene/memory/src/java/module-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Single-document in-memory index implementation */ +module org.apache.lucene.memory { + requires org.apache.lucene.core; + + exports org.apache.lucene.index.memory; +} diff --git a/lucene/misc/build.gradle b/lucene/misc/build.gradle index efed4f25408..b9d76265d5a 100644 --- a/lucene/misc/build.gradle +++ b/lucene/misc/build.gradle @@ -20,7 +20,7 @@ apply plugin: 'java-library' description = 'Index tools and other miscellaneous code' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') testImplementation project(':lucene:test-framework') nativeDeps project(":lucene:misc:native") diff --git a/lucene/misc/src/java/module-info.java b/lucene/misc/src/java/module-info.java new file mode 100644 index 00000000000..269e6b0d220 --- /dev/null +++ b/lucene/misc/src/java/module-info.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Index tools and other miscellaneous code */ +module org.apache.lucene.misc { + requires org.apache.lucene.core; + + exports org.apache.lucene.misc; + exports org.apache.lucene.misc.document; + exports org.apache.lucene.misc.index; + exports org.apache.lucene.misc.search; + exports org.apache.lucene.misc.store; + exports org.apache.lucene.misc.util; + exports org.apache.lucene.misc.util.fst; +} diff --git a/lucene/monitor/build.gradle b/lucene/monitor/build.gradle index 3dd65a4da7a..ff6677f3704 100644 --- a/lucene/monitor/build.gradle +++ b/lucene/monitor/build.gradle @@ -20,10 +20,10 @@ apply plugin: 'java-library' description = 'Reverse-search implementation for monitoring and classification' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:memory') - implementation project(':lucene:analysis:common') + moduleImplementation project(':lucene:memory') + moduleImplementation project(':lucene:analysis:common') testImplementation project(':lucene:queryparser') testImplementation project(':lucene:test-framework') diff --git a/lucene/monitor/src/java/module-info.java b/lucene/monitor/src/java/module-info.java new file mode 100644 index 00000000000..71b70f03c7b --- /dev/null +++ b/lucene/monitor/src/java/module-info.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Reverse-search implementation for monitoring and classification */ +module org.apache.lucene.monitor { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + requires org.apache.lucene.memory; + + exports org.apache.lucene.monitor; +} diff --git a/lucene/queries/build.gradle b/lucene/queries/build.gradle index bd56a4dd50c..d0cc010ad77 100644 --- a/lucene/queries/build.gradle +++ b/lucene/queries/build.gradle @@ -20,7 +20,7 @@ apply plugin: 'java-library' description = 'Filters and Queries that add to core Lucene' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') testImplementation project(':lucene:test-framework') testImplementation project(':lucene:expressions') diff --git a/lucene/queries/src/java/module-info.java b/lucene/queries/src/java/module-info.java new file mode 100644 index 00000000000..ae3ff4d0712 --- /dev/null +++ b/lucene/queries/src/java/module-info.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Filters and Queries that add to core Lucene */ +module org.apache.lucene.queries { + requires org.apache.lucene.core; + + exports org.apache.lucene.queries; + exports org.apache.lucene.queries.function; + exports org.apache.lucene.queries.function.docvalues; + exports org.apache.lucene.queries.function.valuesource; + exports org.apache.lucene.queries.intervals; + exports org.apache.lucene.queries.mlt; + exports org.apache.lucene.queries.payloads; + exports org.apache.lucene.queries.spans; +} diff --git a/lucene/queryparser/build.gradle b/lucene/queryparser/build.gradle index 077eb245bc8..b50b565e2f7 100644 --- a/lucene/queryparser/build.gradle +++ b/lucene/queryparser/build.gradle @@ -20,9 +20,9 @@ apply plugin: 'java-library' description = 'Query parsers and parsing framework' dependencies { - api project(':lucene:core') - api project(':lucene:queries') - api project(':lucene:sandbox') + moduleApi project(':lucene:core') + moduleApi project(':lucene:queries') + moduleApi project(':lucene:sandbox') testImplementation project(':lucene:test-framework') } diff --git a/lucene/queryparser/src/java/module-info.java b/lucene/queryparser/src/java/module-info.java new file mode 100644 index 00000000000..3dab16dcd6f --- /dev/null +++ b/lucene/queryparser/src/java/module-info.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Query parsers and parsing framework */ +module org.apache.lucene.queryparser { + requires java.xml; + requires org.apache.lucene.core; + requires org.apache.lucene.queries; + requires org.apache.lucene.sandbox; + + exports org.apache.lucene.queryparser.charstream; + exports org.apache.lucene.queryparser.classic; + exports org.apache.lucene.queryparser.complexPhrase; + exports org.apache.lucene.queryparser.ext; + exports org.apache.lucene.queryparser.flexible.core; + exports org.apache.lucene.queryparser.flexible.core.builders; + exports org.apache.lucene.queryparser.flexible.core.config; + exports org.apache.lucene.queryparser.flexible.core.messages; + exports org.apache.lucene.queryparser.flexible.core.nodes; + exports org.apache.lucene.queryparser.flexible.core.parser; + exports org.apache.lucene.queryparser.flexible.core.processors; + exports org.apache.lucene.queryparser.flexible.core.util; + exports org.apache.lucene.queryparser.flexible.messages; + exports org.apache.lucene.queryparser.flexible.precedence; + exports org.apache.lucene.queryparser.flexible.precedence.processors; + exports org.apache.lucene.queryparser.flexible.standard; + exports org.apache.lucene.queryparser.flexible.standard.builders; + exports org.apache.lucene.queryparser.flexible.standard.config; + exports org.apache.lucene.queryparser.flexible.standard.nodes; + exports org.apache.lucene.queryparser.flexible.standard.nodes.intervalfn; + exports org.apache.lucene.queryparser.flexible.standard.parser; + exports org.apache.lucene.queryparser.flexible.standard.processors; + exports org.apache.lucene.queryparser.simple; + exports org.apache.lucene.queryparser.surround.parser; + exports org.apache.lucene.queryparser.surround.query; + exports org.apache.lucene.queryparser.xml; + exports org.apache.lucene.queryparser.xml.builders; +} diff --git a/lucene/replicator/build.gradle b/lucene/replicator/build.gradle index c51feb0ba34..d3dfc07e3b3 100644 --- a/lucene/replicator/build.gradle +++ b/lucene/replicator/build.gradle @@ -20,15 +20,15 @@ apply plugin: 'java-library' description = 'Lucene index files replication utility' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') - implementation project(':lucene:facet') + moduleImplementation project(':lucene:facet') - implementation('org.apache.httpcomponents:httpclient', { + moduleImplementation('org.apache.httpcomponents:httpclient', { exclude group: "commons-codec", module: "commons-codec" }) - implementation 'javax.servlet:javax.servlet-api' + moduleImplementation 'javax.servlet:javax.servlet-api' testImplementation 'org.eclipse.jetty:jetty-server' testImplementation('org.eclipse.jetty:jetty-servlet', { diff --git a/lucene/replicator/src/java/module-info.java b/lucene/replicator/src/java/module-info.java new file mode 100644 index 00000000000..d44b9adfa9f --- /dev/null +++ b/lucene/replicator/src/java/module-info.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Lucene index files replication utility */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.replicator { + requires javax.servlet.api; + requires org.apache.httpcomponents.httpclient; + requires org.apache.lucene.core; + requires org.apache.lucene.facet; + + exports org.apache.lucene.replicator; + exports org.apache.lucene.replicator.http; + exports org.apache.lucene.replicator.nrt; +} diff --git a/lucene/sandbox/build.gradle b/lucene/sandbox/build.gradle index a1a64d1d603..b7e8018ea64 100644 --- a/lucene/sandbox/build.gradle +++ b/lucene/sandbox/build.gradle @@ -20,7 +20,7 @@ apply plugin: 'java-library' description = 'Various third party contributions and new ideas' dependencies { - api project(':lucene:core') - api project(':lucene:queries') + moduleApi project(':lucene:core') + moduleApi project(':lucene:queries') testImplementation project(':lucene:test-framework') } diff --git a/lucene/sandbox/src/java/module-info.java b/lucene/sandbox/src/java/module-info.java new file mode 100644 index 00000000000..6d195445fbe --- /dev/null +++ b/lucene/sandbox/src/java/module-info.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Various third party contributions and new ideas */ +module org.apache.lucene.sandbox { + requires org.apache.lucene.core; + requires org.apache.lucene.queries; + + exports org.apache.lucene.payloads; + exports org.apache.lucene.sandbox.codecs.idversion; + exports org.apache.lucene.sandbox.document; + exports org.apache.lucene.sandbox.queries; + exports org.apache.lucene.sandbox.search; + + provides org.apache.lucene.codecs.PostingsFormat with + org.apache.lucene.sandbox.codecs.idversion.IDVersionPostingsFormat; +} diff --git a/lucene/spatial-extras/build.gradle b/lucene/spatial-extras/build.gradle index 252056b9d8f..34fa10e13e7 100644 --- a/lucene/spatial-extras/build.gradle +++ b/lucene/spatial-extras/build.gradle @@ -20,16 +20,16 @@ apply plugin: 'java-library' description = 'Geospatial search' dependencies { - api project(':lucene:core') - api project(':lucene:spatial3d') + moduleApi project(':lucene:core') + moduleApi project(':lucene:spatial3d') - api 'org.locationtech.spatial4j:spatial4j' - api 'io.sgr:s2-geometry-library-java' + moduleApi 'org.locationtech.spatial4j:spatial4j' + moduleApi 'io.sgr:s2-geometry-library-java' testImplementation project(':lucene:test-framework') testImplementation testFixtures(project(':lucene:spatial3d')) - testImplementation 'org.locationtech.jts:jts-core' + moduleTestImplementation 'org.locationtech.jts:jts-core' testImplementation 'org.locationtech.spatial4j:spatial4j::tests' } diff --git a/lucene/spatial-extras/src/java/module-info.java b/lucene/spatial-extras/src/java/module-info.java new file mode 100644 index 00000000000..2464761b4b5 --- /dev/null +++ b/lucene/spatial-extras/src/java/module-info.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Geospatial search */ +@SuppressWarnings({"requires-automatic"}) +module org.apache.lucene.spatial_extras { + requires java.logging; + requires spatial4j; + requires s2.geometry.library.java; + requires org.apache.lucene.core; + requires org.apache.lucene.spatial3d; + + exports org.apache.lucene.spatial; + exports org.apache.lucene.spatial.bbox; + exports org.apache.lucene.spatial.composite; + exports org.apache.lucene.spatial.prefix; + exports org.apache.lucene.spatial.prefix.tree; + exports org.apache.lucene.spatial.query; + exports org.apache.lucene.spatial.serialized; + exports org.apache.lucene.spatial.spatial4j; + exports org.apache.lucene.spatial.util; + exports org.apache.lucene.spatial.vector; +} diff --git a/lucene/spatial3d/build.gradle b/lucene/spatial3d/build.gradle index db2064c9396..219d0293dc2 100644 --- a/lucene/spatial3d/build.gradle +++ b/lucene/spatial3d/build.gradle @@ -21,7 +21,7 @@ apply plugin: 'java-test-fixtures' description = '3D spatial planar geometry APIs' dependencies { - api project(':lucene:core') + moduleApi project(':lucene:core') testFixturesApi project(':lucene:test-framework') testImplementation project(':lucene:test-framework') diff --git a/lucene/spatial3d/src/java/module-info.java b/lucene/spatial3d/src/java/module-info.java new file mode 100644 index 00000000000..9bffb23a468 --- /dev/null +++ b/lucene/spatial3d/src/java/module-info.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** 3D spatial planar geometry APIs */ +module org.apache.lucene.spatial3d { + requires org.apache.lucene.core; + + exports org.apache.lucene.spatial3d; + exports org.apache.lucene.spatial3d.geom; +} diff --git a/lucene/suggest/build.gradle b/lucene/suggest/build.gradle index 54a559624da..3afccd85686 100644 --- a/lucene/suggest/build.gradle +++ b/lucene/suggest/build.gradle @@ -20,8 +20,8 @@ apply plugin: 'java-library' description = 'Auto-suggest and Spellchecking support' dependencies { - api project(':lucene:core') - api project(':lucene:analysis:common') + moduleApi project(':lucene:core') + moduleApi project(':lucene:analysis:common') testImplementation project(':lucene:test-framework') } diff --git a/lucene/suggest/src/java/module-info.java b/lucene/suggest/src/java/module-info.java new file mode 100644 index 00000000000..4444a9dd2f1 --- /dev/null +++ b/lucene/suggest/src/java/module-info.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Auto-suggest and Spellchecking support */ +module org.apache.lucene.suggest { + requires org.apache.lucene.core; + requires org.apache.lucene.analysis.common; + + exports org.apache.lucene.search.spell; + exports org.apache.lucene.search.suggest; + exports org.apache.lucene.search.suggest.analyzing; + exports org.apache.lucene.search.suggest.document; + exports org.apache.lucene.search.suggest.fst; + exports org.apache.lucene.search.suggest.tst; + + provides org.apache.lucene.codecs.PostingsFormat with + org.apache.lucene.search.suggest.document.Completion50PostingsFormat, + org.apache.lucene.search.suggest.document.Completion84PostingsFormat, + org.apache.lucene.search.suggest.document.Completion90PostingsFormat; + provides org.apache.lucene.analysis.TokenFilterFactory with + org.apache.lucene.search.suggest.analyzing.SuggestStopFilterFactory; +} diff --git a/settings.gradle b/settings.gradle index e965095654c..2d48e4194dc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,7 @@ include "lucene:analysis:common" include "lucene:analysis:icu" include "lucene:analysis:kuromoji" include "lucene:analysis:morfologik" +include "lucene:analysis:morfologik.tests" include "lucene:analysis:nori" include "lucene:analysis:opennlp" include "lucene:analysis:phonetic" @@ -41,6 +42,9 @@ include "lucene:classification" include "lucene:codecs" include "lucene:core" include "lucene:demo" +include "lucene:distribution" +include "lucene:distribution.tests" +include "lucene:documentation" include "lucene:expressions" include "lucene:facet" include "lucene:grouping" @@ -55,9 +59,7 @@ include "lucene:queries" include "lucene:queryparser" include "lucene:replicator" include "lucene:sandbox" -include "lucene:spatial-extras" include "lucene:spatial3d" +include "lucene:spatial-extras" include "lucene:suggest" include "lucene:test-framework" -include "lucene:documentation" -include "lucene:distribution" diff --git a/versions.lock b/versions.lock index 87c5b3f55d2..c596e6e0fa8 100644 --- a/versions.lock +++ b/versions.lock @@ -18,12 +18,15 @@ org.carrot2:morfologik-polish:2.1.8 (1 constraints: 0d050036) org.carrot2:morfologik-stemming:2.1.8 (2 constraints: 1112dc0c) org.hamcrest:hamcrest:2.2 (1 constraints: a8041f2c) org.locationtech.spatial4j:spatial4j:0.8 (1 constraints: ac041f2c) -org.ow2.asm:asm:7.2 (2 constraints: 900e3e5e) +org.ow2.asm:asm:7.2 (3 constraints: 2717d96b) +org.ow2.asm:asm-analysis:7.2 (1 constraints: e409d9a5) org.ow2.asm:asm-commons:7.2 (1 constraints: ad042e2c) +org.ow2.asm:asm-tree:7.2 (2 constraints: 2f14468c) ua.net.nlp:morfologik-ukrainian-search:4.9.1 (1 constraints: 10051b36) xerces:xercesImpl:2.12.0 (2 constraints: 1f14b675) [Test dependencies] +org.assertj:assertj-core:3.21.0 (1 constraints: 38053c3b) org.eclipse.jetty:jetty-continuation:9.4.41.v20210516 (1 constraints: 7907fe7c) org.eclipse.jetty:jetty-http:9.4.41.v20210516 (1 constraints: f60f2ccd) org.eclipse.jetty:jetty-io:9.4.41.v20210516 (2 constraints: 141f4566) diff --git a/versions.props b/versions.props index c0103925617..995a7dc8ddb 100644 --- a/versions.props +++ b/versions.props @@ -11,6 +11,7 @@ org.antlr:antlr4*=4.5.1-1 org.apache.commons:commons-compress=1.19 org.apache.httpcomponents:httpclient=4.5.13 org.apache.opennlp:opennlp-tools=1.9.1 +org.assertj:*=3.21.0 org.carrot2:morfologik-*=2.1.8 org.eclipse.jetty:*=9.4.41.v20210516 org.hamcrest:*=2.2 @@ -18,4 +19,4 @@ org.locationtech.jts:jts-core=1.17.0 org.locationtech.spatial4j:*=0.8 org.ow2.asm:*=7.2 ua.net.nlp:morfologik-ukrainian-search=4.9.1 -xerces:xercesImpl=2.12.0 +xerces:xercesImpl=2.12.0 \ No newline at end of file