LUCENE-10313: merge log4j-less Luke.

This commit is contained in:
Dawid Weiss 2021-12-16 15:47:52 +01:00
commit 9917092bf8
48 changed files with 489 additions and 767 deletions

1
.gitattributes vendored
View File

@ -1,5 +1,6 @@
# Ignore all differences in line endings for the lock file.
versions.lock text eol=lf
versions.props text eol=lf
# Gradle files are always in LF.
*.gradle text eol=lf

View File

@ -74,6 +74,13 @@
<revision>9.0.0</revision>
</Version>
</release>
<release>
<Version>
<name>lucene-8.11.1</name>
<created>2021-12-16</created>
<revision>8.11.1</revision>
</Version>
</release>
<release>
<Version>
<name>lucene-8.11.0</name>

View File

@ -67,7 +67,7 @@ from consolemenu.screen import Screen
from scriptutil import BranchType, Version, download, run
# Lucene-to-Java version mapping
java_versions = {6: 8, 7: 8, 8: 8, 9: 11}
java_versions = {6: 8, 7: 8, 8: 8, 9: 11, 10: 11}
editor = None
# Edit this to add other global jinja2 variables or filters

View File

@ -71,6 +71,10 @@ New Features
Improvements
---------------------
* LUCENE-10313: use java util logging in Luke. Add dynamic log filtering. Drop
the persistent log previously written to ~/.luke.d/luke.log. Configure Java's default
logging handlers to persist Luke logs according to your needs. (Tomoko Uchida, Dawid Weiss)
* LUCENE-10238: Upgrade icu4j dependency to 70.1. (Dawid Weiss)
* LUCENE-9820: Extract BKD tree interface and move intersecting logic to the
@ -111,6 +115,9 @@ Other
* LUCENE-10284: Upgrade morfologik-stemming to 2.1.8. (Dawid Weiss)
* LUCENE-10310: TestXYDocValuesQueries#doRandomDistanceTest does not produce random circles with radius
with '0' value any longer.
======================= Lucene 9.0.0 =======================
New Features
@ -573,6 +580,12 @@ Other
* LUCENE-10024: Catch NoSuchFileException when opening index directory with Luke.
(Michael Wechner, Tomoko Uchida)
======================= Lucene 8.11.1 =======================
Bug Fixes
---------------------
* SOLR-15843: Update Log4J to 2.16 (Mike Drob, janhoy)
======================= Lucene 8.11.0 =======================
API Changes

View File

@ -334,13 +334,18 @@ public class TestBackwardsCompatibility extends LuceneTestCase {
}
}
static final String[] oldNames = {"9.0.0-cfs", "9.0.0-nocfs"};
static final String[] oldNames = {
"9.0.0-cfs", // Force on separate lines
"9.0.0-nocfs",
};
public static String[] getOldNames() {
return oldNames;
}
static final String[] oldSortedNames = {"sorted.9.0.0"};
static final String[] oldSortedNames = {
"sorted.9.0.0", // Force on separate lines
};
public static String[] getOldSortedNames() {
return oldSortedNames;
@ -590,6 +595,8 @@ public class TestBackwardsCompatibility extends LuceneTestCase {
"8.10.1-nocfs",
"8.11.0-cfs",
"8.11.0-nocfs",
"8.11.1-cfs",
"8.11.1-nocfs"
};
static final int MIN_BINARY_SUPPORTED_MAJOR = Version.MIN_SUPPORTED_MAJOR - 1;

View File

@ -222,7 +222,8 @@ public class TestDocValuesFieldExistsQuery extends LuceneTestCase {
for (int i = 0; i < randomNumDocs; i++) {
Document doc = new Document();
if (random().nextBoolean()) {
// ensure we index at least a document with long between 0 and 10
if (i == 0 || random().nextBoolean()) {
doc.add(new LongPoint("long", i));
doc.add(new NumericDocValuesField("long", i));
doc.add(new StringField("string", "value", Store.NO));

View File

@ -17,5 +17,5 @@
SETLOCAL
SET MODULES=%~dp0..
start javaw --module-path "%MODULES%\modules;%MODULES%\modules-thirdparty" --add-modules jdk.unsupported,org.apache.logging.log4j --module org.apache.lucene.luke
start javaw --module-path "%MODULES%\modules;%MODULES%\modules-thirdparty" --add-modules jdk.unsupported --module org.apache.lucene.luke
ENDLOCAL

View File

@ -17,4 +17,4 @@
MODULES=`dirname "$0"`/..
MODULES=`cd "$MODULES" && pwd`
java --module-path "$MODULES/modules:$MODULES/modules-thirdparty" --add-modules jdk.unsupported,org.apache.logging.log4j --module org.apache.lucene.luke
java --module-path "$MODULES/modules:$MODULES/modules-thirdparty" --add-modules jdk.unsupported --module org.apache.lucene.luke

View File

@ -1 +0,0 @@
567ea514dedd8679c429c5b5b39b0d67b6464c3c

View File

@ -1,201 +0,0 @@
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.

View File

@ -1,17 +0,0 @@
Apache Log4j
Copyright 1999-2017 Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
ResolverUtil.java
Copyright 2005-2006 Tim Fennell
Dumbster SMTP test server
Copyright 2004 Jason Paul Kitchen
TypeUtil.java
Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams
picocli (http://picocli.info)
Copyright 2017 Remko Popma

View File

@ -1 +0,0 @@
8eb1fc1914eb2550bf3ddea26917c9a7cbb00593

View File

@ -1,201 +0,0 @@
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.

View File

@ -1,17 +0,0 @@
Apache Log4j
Copyright 1999-2017 Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
ResolverUtil.java
Copyright 2005-2006 Tim Fennell
Dumbster SMTP test server
Copyright 2004 Jason Paul Kitchen
TypeUtil.java
Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams
picocli (http://picocli.info)
Copyright 2017 Remko Popma

View File

@ -27,8 +27,6 @@ ext {
dependencies {
moduleApi project(':lucene:core')
moduleImplementation 'org.apache.logging.log4j:log4j-core'
moduleImplementation project(':lucene:codecs')
moduleImplementation project(':lucene:backward-codecs')
moduleImplementation project(':lucene:analysis:common')

View File

@ -27,7 +27,7 @@ java -jar ${luke.cmd}
or, using Java modules:
```
java --module-path . --add-modules jdk.unsupported,org.apache.logging.log4j --module org.apache.lucene.luke
java --module-path . --add-modules jdk.unsupported --module org.apache.lucene.luke
```
Happy index hacking!

View File

@ -16,7 +16,6 @@
*/
/** Luke : Lucene toolbox project. */
@SuppressWarnings({"requires-automatic"})
module org.apache.lucene.luke {
requires java.desktop;
requires java.logging;
@ -25,6 +24,4 @@ module org.apache.lucene.luke {
requires org.apache.lucene.queries;
requires org.apache.lucene.queryparser;
requires org.apache.lucene.misc;
requires org.apache.logging.log4j;
requires org.apache.logging.log4j.core;
}

View File

@ -20,7 +20,8 @@ package org.apache.lucene.luke.app;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.Logger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.luke.util.LoggerFactory;
/** Abstract handler class */
@ -32,8 +33,8 @@ public abstract class AbstractHandler<T extends Observer> {
public void addObserver(T observer) {
observers.add(observer);
if (log.isDebugEnabled()) {
log.debug("{} registered.", observer.getClass().getName());
if (log.isLoggable(Level.FINE)) {
log.fine(observer.getClass().getName() + " registered.");
}
}

View File

@ -21,7 +21,8 @@ import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.NoSuchFileException;
import java.util.Objects;
import org.apache.logging.log4j.Logger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.luke.app.desktop.PreferencesFactory;
import org.apache.lucene.luke.app.desktop.util.MessageUtils;
@ -75,19 +76,19 @@ public final class IndexHandler extends AbstractHandler<IndexObserver> {
try {
reader = IndexUtils.openIndex(indexPath, dirImpl);
} catch (NoSuchFileException e) {
log.error("Error opening index", e);
log.log(Level.SEVERE, "Error opening index", e);
try {
// remove the non-existing index path from history.
PreferencesFactory.getInstance().removeHistory(indexPath);
} catch (IOException ioe) {
log.error("Preference file is deleted?", ioe);
log.log(Level.SEVERE, "Preference file is deleted?", ioe);
}
throw new LukeException(
MessageUtils.getLocalizedMessage(
"openindex.message.index_path_does_not_exist", indexPath),
e);
} catch (Exception e) {
log.error("Error opening index", e);
log.log(Level.SEVERE, "Error opening index", e);
throw new LukeException(
MessageUtils.getLocalizedMessage("openindex.message.index_path_invalid", indexPath), e);
}

View File

@ -21,11 +21,11 @@ import static org.apache.lucene.luke.app.desktop.util.ExceptionHandler.handle;
import java.awt.GraphicsEnvironment;
import java.lang.invoke.MethodHandles;
import java.nio.file.FileSystems;
import java.util.concurrent.SynchronousQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.UIManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.app.desktop.components.LukeWindowProvider;
import org.apache.lucene.luke.app.desktop.components.dialog.menubar.OpenIndexDialogFactory;
import org.apache.lucene.luke.app.desktop.util.DialogOpener;
@ -36,15 +36,8 @@ import org.apache.lucene.luke.util.LoggerFactory;
/** Entry class for desktop Luke */
public class LukeMain {
public static final String LOG_FILE =
System.getProperty("user.home")
+ FileSystems.getDefault().getSeparator()
+ ".luke.d"
+ FileSystems.getDefault().getSeparator()
+ "luke.log";
static {
LoggerFactory.initGuiLogging(LOG_FILE);
LoggerFactory.initGuiLogging();
}
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@ -79,7 +72,7 @@ public class LukeMain {
return true;
} catch (Throwable e) {
messageBroker.showUnknownErrorMessage();
log.fatal("Cannot initialize components.", e);
log.log(Level.SEVERE, "Cannot initialize components.", e);
return false;
}
}
@ -107,9 +100,7 @@ public class LukeMain {
});
if (Boolean.FALSE.equals(guiThreadResult.take())) {
// Use java logging just in case log4j didn't start up properly.
java.util.logging.Logger.getGlobal()
.severe("Luke could not start because of errors, see the log file: " + LOG_FILE);
Logger.getGlobal().log(Level.SEVERE, "Luke could not start.");
Runtime.getRuntime().exit(1);
}
}

View File

@ -35,6 +35,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import javax.swing.BorderFactory;
@ -154,7 +155,7 @@ public final class DocumentsPanelProvider implements DocumentsTabOperator {
this.tableHeaderRenderer =
new HelpHeaderRenderer(
"About Flags",
"Format: IdfpoNPSB#txxVDtxxxxTx/x",
"Format: IdfpoNPSB#txxVDtxxxxTx/xKxxxx/xxx",
createFlagsHelpDialog(),
helpDialogFactory);
@ -173,7 +174,8 @@ public final class DocumentsPanelProvider implements DocumentsTabOperator {
"#txx - numeric stored values(type, precision)",
"V - term vectors",
"Dtxxxxx - doc values(type)",
"Tx/x - point values(num bytes/dimension)"
"Tx/x - point values(num bytes/dimension)",
"Kxxxx/xxx - knn vector values(dimension/similarity)"
};
JList<String> list = new JList<>(values);
return new JScrollPane(list);
@ -1049,7 +1051,7 @@ public final class DocumentsPanelProvider implements DocumentsTabOperator {
enum Column implements TableColumnInfo {
FIELD("Field", 0, String.class, 150),
FLAGS("Flags", 1, String.class, 200),
FLAGS("Flags", 1, String.class, 220),
NORM("Norm", 2, Long.class, 80),
VALUE("Value", 3, String.class, 500);
@ -1227,6 +1229,27 @@ public final class DocumentsPanelProvider implements DocumentsTabOperator {
sb.append("/");
sb.append(f.getPointDimensionCount());
}
// knn vector values
if (f.getVectorDimension() == 0) {
sb.append("---------");
} else {
sb.append("K");
sb.append(String.format(Locale.ENGLISH, "%04d", f.getVectorDimension()));
sb.append("/");
switch (f.getVectorSimilarity()) {
case COSINE:
sb.append("cos");
break;
case DOT_PRODUCT:
sb.append("dot");
break;
case EUCLIDEAN:
sb.append("euc");
break;
default:
sb.append("???");
}
}
return sb.toString();
}

View File

@ -17,24 +17,26 @@
package org.apache.lucene.luke.app.desktop.components;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import org.apache.lucene.luke.app.desktop.LukeMain;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.HierarchyEvent;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.*;
import org.apache.lucene.luke.app.desktop.util.FontUtils;
import org.apache.lucene.luke.app.desktop.util.MessageUtils;
import org.apache.lucene.luke.util.CircularLogBufferHandler;
import org.apache.lucene.luke.util.LogRecordFormatter;
import org.apache.lucene.luke.util.LoggerFactory;
/** Provider of the Logs panel */
public final class LogsPanelProvider {
private final JTextArea logTextArea;
public LogsPanelProvider(JTextArea logTextArea) {
this.logTextArea = logTextArea;
}
public LogsPanelProvider() {}
public JPanel get() {
JPanel panel = new JPanel(new BorderLayout());
@ -43,14 +45,92 @@ public final class LogsPanelProvider {
JPanel header = new JPanel(new FlowLayout(FlowLayout.LEADING));
header.setOpaque(false);
header.add(new JLabel(MessageUtils.getLocalizedMessage("logs.label.see_also")));
header.add(new JLabel(MessageUtils.getLocalizedMessage("logs.label.level")));
JLabel logPathLabel = new JLabel(LukeMain.LOG_FILE);
header.add(logPathLabel);
JComboBox<Level> logFilter =
new JComboBox<>(
new Level[] {
Level.FINEST,
Level.FINER,
Level.FINE,
Level.CONFIG,
Level.INFO,
Level.WARNING,
Level.SEVERE,
Level.OFF
});
logFilter.setEditable(false);
logFilter.setSelectedItem(Level.INFO);
header.add(logFilter);
var logTextArea = createLogPanel(logFilter);
JButton copyBtn =
new JButton(
FontUtils.elegantIconHtml("&#xe0e6;", MessageUtils.getLocalizedMessage("button.copy")));
copyBtn.setMargin(new Insets(3, 3, 3, 3));
copyBtn.addActionListener(
e -> {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection selection = new StringSelection(logTextArea.getText());
clipboard.setContents(selection, null);
});
header.add(copyBtn);
panel.add(header, BorderLayout.PAGE_START);
panel.add(new JScrollPane(logTextArea), BorderLayout.CENTER);
return panel;
}
/** Prepare the component responsible for displaying logs. */
private JTextArea createLogPanel(JComboBox<Level> logFilter) {
JTextArea logTextArea = new JTextArea();
logTextArea.setEditable(false);
// Hook into live data from the circular log buffer and update the initial state.
Function<CircularLogBufferHandler.ImmutableLogRecord, String> formatter =
new LogRecordFormatter();
CircularLogBufferHandler.LogUpdateListener updater =
records -> {
// Create an immutable copy of the logs to display in the gui thread.
ArrayList<CircularLogBufferHandler.ImmutableLogRecord> clonedCopy =
new ArrayList<>(records);
SwingUtilities.invokeLater(
() -> {
Level level = (Level) Objects.requireNonNull(logFilter.getSelectedItem());
String logContent =
clonedCopy.stream()
.filter(record -> record.getLevel().intValue() >= level.intValue())
.map(formatter::apply)
.collect(Collectors.joining("\n"));
logTextArea.setText(logContent);
});
};
var logBuffer = Objects.requireNonNull(LoggerFactory.circularBuffer);
// Update state on filter change.
logFilter.addActionListener(
e -> {
updater.accept(logBuffer.getLogRecords());
});
// Subscribe to log events and update state only when actually displayed.
logTextArea.addHierarchyListener(
(HierarchyEvent e) -> {
if (e.getComponent() == logTextArea
&& (e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
if (logTextArea.isDisplayable()) {
logBuffer.addUpdateListener(updater);
updater.accept(logBuffer.getLogRecords());
} else {
logBuffer.removeUpdateListener(updater);
}
}
});
return logTextArea;
}
}

View File

@ -17,22 +17,9 @@
package org.apache.lucene.luke.app.desktop.components;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.*;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
import javax.swing.*;
import org.apache.lucene.luke.app.DirectoryHandler;
import org.apache.lucene.luke.app.DirectoryObserver;
import org.apache.lucene.luke.app.IndexHandler;
@ -44,7 +31,6 @@ import org.apache.lucene.luke.app.desktop.PreferencesFactory;
import org.apache.lucene.luke.app.desktop.util.FontUtils;
import org.apache.lucene.luke.app.desktop.util.ImageUtils;
import org.apache.lucene.luke.app.desktop.util.MessageUtils;
import org.apache.lucene.luke.app.desktop.util.TextAreaAppender;
import org.apache.lucene.util.Version;
/** Provider of the root window */
@ -74,14 +60,9 @@ public final class LukeWindowProvider implements LukeWindowOperator {
private JFrame frame = new JFrame();
public LukeWindowProvider() throws IOException {
// prepare log4j appender for Logs tab.
JTextArea logTextArea = new JTextArea();
logTextArea.setEditable(false);
TextAreaAppender.setTextArea(logTextArea);
this.prefs = PreferencesFactory.getInstance();
this.menuBar = new MenuBarProvider().get();
this.tabbedPane = new TabbedPaneProvider(logTextArea).get();
this.tabbedPane = new TabbedPaneProvider().get();
this.messageBroker = MessageBroker.getInstance();
this.tabSwitcher = TabSwitcherProxy.getInstance();

View File

@ -20,7 +20,6 @@ package org.apache.lucene.luke.app.desktop.components;
import java.io.IOException;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import org.apache.lucene.luke.app.DirectoryHandler;
import org.apache.lucene.luke.app.DirectoryObserver;
import org.apache.lucene.luke.app.IndexHandler;
@ -35,7 +34,7 @@ public final class TabbedPaneProvider implements TabSwitcherProxy.TabSwitcher {
private final MessageBroker messageBroker;
private final JTabbedPane tabbedPane = new JTabbedPane();
private final JTabbedPane tabbedPane;
private final JPanel overviewPanel;
@ -49,13 +48,15 @@ public final class TabbedPaneProvider implements TabSwitcherProxy.TabSwitcher {
private final JPanel logsPanel;
public TabbedPaneProvider(JTextArea logTextArea) throws IOException {
public TabbedPaneProvider() throws IOException {
this.tabbedPane = new JTabbedPane();
this.overviewPanel = new OverviewPanelProvider().get();
this.documentsPanel = new DocumentsPanelProvider().get();
this.searchPanel = new SearchPanelProvider().get();
this.analysisPanel = new AnalysisPanelProvider().get();
this.commitsPanel = new CommitsPanelProvider().get();
this.logsPanel = new LogsPanelProvider(logTextArea).get();
this.logsPanel = new LogsPanelProvider().get();
this.messageBroker = MessageBroker.getInstance();

View File

@ -33,6 +33,8 @@ import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.swing.BorderFactory;
@ -51,7 +53,6 @@ import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
@ -399,15 +400,15 @@ public final class AddDocumentDialogFactory
doc.add(toIndexableField(nf));
}
} catch (NumberFormatException ex) {
log.error("Error converting field value", e);
log.log(Level.SEVERE, "Error converting field value", e);
throw new LukeException("Invalid value: " + ex.getMessage(), ex);
} catch (Exception ex) {
log.error("Error converting field value", e);
log.log(Level.SEVERE, "Error converting field value", e);
throw new LukeException(ex.getMessage(), ex);
}
addDocument(doc);
log.info("Added document: {}", doc);
log.info("Added document: " + doc);
}
@SuppressWarnings("unchecked")

View File

@ -29,6 +29,8 @@ import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
@ -39,7 +41,6 @@ import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.index.CheckIndex;
import org.apache.lucene.luke.app.DirectoryHandler;
import org.apache.lucene.luke.app.DirectoryObserver;
@ -304,7 +305,7 @@ public final class CheckIndexDialogFactory implements DialogOpener.DialogFactory
}
status = st;
} catch (Exception e) {
log.error("Error checking index", e);
log.log(Level.SEVERE, "Error checking index", e);
statusLbl.setText(MessageUtils.getLocalizedMessage("message.error.unknown"));
}
}

View File

@ -35,6 +35,8 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
@ -47,7 +49,6 @@ import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.app.IndexHandler;
import org.apache.lucene.luke.app.desktop.Preferences;
import org.apache.lucene.luke.app.desktop.PreferencesFactory;
@ -337,8 +338,8 @@ public class CreateIndexDialogFactory implements DialogOpener.DialogFactory {
IOException ex2) {
}
log.error("Cannot create index", ex);
String message = "See Logs tab or log file for more details.";
log.log(Level.SEVERE, "Cannot create index", ex);
String message = "See Logs tab for more details.";
JOptionPane.showMessageDialog(
dialog, message, "Cannot create index", JOptionPane.ERROR_MESSAGE);
} finally {

View File

@ -31,6 +31,8 @@ import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
@ -42,7 +44,6 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.app.IndexHandler;
import org.apache.lucene.luke.app.IndexObserver;
import org.apache.lucene.luke.app.LukeState;
@ -249,11 +250,11 @@ public final class ExportTermsDialogFactory implements DialogOpener.DialogFactor
try {
filename = toolsModel.exportTerms(directory, field, selectedDelimiter);
} catch (LukeException e) {
log.error("Error while exporting terms from field {}", field, e);
log.log(Level.SEVERE, "Error while exporting terms from field " + field, e);
statusLbl.setText(
MessageUtils.getLocalizedMessage("export.terms.label.error", e.getMessage()));
} catch (Exception e) {
log.error("Error while exporting terms from field {}", field, e);
log.log(Level.SEVERE, "Error while exporting terms from field " + field, e);
statusLbl.setText(MessageUtils.getLocalizedMessage("message.error.unknown"));
throw e;
} finally {

View File

@ -32,6 +32,8 @@ import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
@ -45,7 +47,6 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.app.DirectoryHandler;
import org.apache.lucene.luke.app.IndexHandler;
import org.apache.lucene.luke.app.desktop.Preferences;
@ -336,7 +337,7 @@ public final class OpenIndexDialogFactory implements DialogOpener.DialogFactory
closeDialog();
} catch (LukeException ex) {
String message =
ex.getMessage() + System.lineSeparator() + "See Logs tab or log file for more details.";
ex.getMessage() + System.lineSeparator() + "See Logs tab for more details.";
JOptionPane.showMessageDialog(
dialog, message, "Invalid index path", JOptionPane.ERROR_MESSAGE);
} catch (Throwable cause) {
@ -345,7 +346,7 @@ public final class OpenIndexDialogFactory implements DialogOpener.DialogFactory
MessageUtils.getLocalizedMessage("message.error.unknown"),
"Unknown Error",
JOptionPane.ERROR_MESSAGE);
log.error("Error opening index or directory", cause);
log.log(Level.SEVERE, "Error opening index or directory", cause);
}
}

View File

@ -18,7 +18,8 @@
package org.apache.lucene.luke.app.desktop.util;
import java.lang.invoke.MethodHandles;
import org.apache.logging.log4j.Logger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.luke.app.desktop.MessageBroker;
import org.apache.lucene.luke.models.LukeException;
import org.apache.lucene.luke.util.LoggerFactory;
@ -32,10 +33,10 @@ public final class ExceptionHandler {
if (t instanceof LukeException) {
Throwable cause = t.getCause();
String message = (cause == null) ? t.getMessage() : t.getMessage() + " " + cause.getMessage();
log.warn("Uncaught LukeException", t);
log.log(Level.WARNING, "Uncaught LukeException", t);
messageBroker.showStatusMessage(message);
} else {
log.error("Uncaught Exception", t);
log.log(Level.SEVERE, "Uncaught Exception", t);
messageBroker.showUnknownErrorMessage();
}
}

View File

@ -1,108 +0,0 @@
/*
* 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.luke.app.desktop.util;
import java.io.Serializable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.StringLayout;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
/** Log appender for text areas */
@Plugin(
name = "TextArea",
category = Core.CATEGORY_NAME,
elementType = Appender.ELEMENT_TYPE,
printObject = true)
public final class TextAreaAppender extends AbstractAppender {
private static JTextArea textArea;
private static final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private static final Lock readLock = rwLock.readLock();
private static final Lock writeLock = rwLock.writeLock();
protected TextAreaAppender(
String name,
Filter filter,
org.apache.logging.log4j.core.Layout<? extends Serializable> layout,
final boolean ignoreExceptions) {
super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);
}
public static void setTextArea(JTextArea ta) {
writeLock.lock();
try {
if (textArea != null) {
throw new IllegalStateException("TextArea already set.");
}
textArea = ta;
} finally {
writeLock.unlock();
}
}
@Override
public void append(LogEvent event) {
readLock.lock();
try {
if (textArea == null) {
// just ignore any events logged before the area is available
return;
}
final String message = ((StringLayout) getLayout()).toSerializable(event);
SwingUtilities.invokeLater(
() -> {
textArea.append(message);
});
} finally {
readLock.unlock();
}
}
/**
* Builds TextAreaAppender instances.
*
* @param <B> The type to build
*/
public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
implements org.apache.logging.log4j.core.util.Builder<TextAreaAppender> {
@Override
public TextAreaAppender build() {
return new TextAreaAppender(getName(), getFilter(), getOrCreateLayout(), true);
}
}
@PluginBuilderFactory
public static <B extends Builder<B>> B newBuilder() {
return new Builder<B>().asBuilder();
}
}

View File

@ -26,8 +26,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexCommit;
@ -98,7 +98,7 @@ public final class CommitsImpl extends LukeModel implements Commits {
if (ic == null) {
String msg = String.format(Locale.ENGLISH, "Commit generation %d not exists.", commitGen);
log.warn(msg);
log.warning(msg);
return Optional.empty();
}
@ -111,7 +111,7 @@ public final class CommitsImpl extends LukeModel implements Commits {
if (ic == null) {
String msg = String.format(Locale.ENGLISH, "Commit generation %d not exists.", commitGen);
log.warn(msg);
log.warning(msg);
return Collections.emptyList();
}

View File

@ -26,6 +26,7 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.MultiDocValues;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.VectorSimilarityFunction;
import org.apache.lucene.util.BytesRef;
/** Holder for a document field's information and data. */
@ -54,6 +55,10 @@ public final class DocumentField {
private int pointDimensionCount;
private int pointNumBytes;
// knn vector values
private int vectorDimension;
private VectorSimilarityFunction vectorSimilarity;
static DocumentField of(FieldInfo finfo, IndexReader reader, int docId) throws IOException {
return of(finfo, null, reader, docId);
}
@ -84,6 +89,9 @@ public final class DocumentField {
dfield.pointDimensionCount = finfo.getPointDimensionCount();
dfield.pointNumBytes = finfo.getPointNumBytes();
dfield.vectorDimension = finfo.getVectorDimension();
dfield.vectorSimilarity = finfo.getVectorSimilarityFunction();
if (field != null) {
dfield.isStored = field.fieldType().stored();
dfield.stringValue = field.stringValue();
@ -148,6 +156,14 @@ public final class DocumentField {
return pointNumBytes;
}
public int getVectorDimension() {
return vectorDimension;
}
public VectorSimilarityFunction getVectorSimilarity() {
return vectorSimilarity;
}
@Override
public String toString() {
return "DocumentField{"
@ -164,6 +180,8 @@ public final class DocumentField {
+ dvType
+ ", pointDimensionCount="
+ pointDimensionCount
+ ", vectorDimension="
+ vectorDimension
+ '}';
}

View File

@ -25,7 +25,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import org.apache.logging.log4j.Logger;
import java.util.logging.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.IndexReader;
@ -80,7 +80,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
@Override
public List<DocumentField> getDocumentFields(int docid) {
if (!isLive(docid)) {
log.info("Doc #{} was deleted", docid);
log.info("Doc #" + docid + " was deleted");
return Collections.emptyList();
}
@ -126,7 +126,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
// no such field?
resetCurrentField();
resetTermsIterator();
log.warn("Terms not available for field: {}.", field);
log.warning("Terms not available for field: " + field);
return Optional.empty();
} else {
setCurrentField(field);
@ -135,7 +135,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
if (tenum.next() == null) {
// no term available for this field
resetTermsIterator();
log.warn("No term available for field: {}.", field);
log.warning("No term available for field: " + field);
return Optional.empty();
} else {
return Optional.of(new Term(curField, tenum.term()));
@ -156,7 +156,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
public Optional<Term> nextTerm() {
if (tenum == null) {
// terms enum not initialized
log.warn("Terms enum un-positioned.");
log.warning("Terms enum un-positioned.");
return Optional.empty();
}
@ -164,7 +164,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
if (tenum.next() == null) {
// end of the iterator
resetTermsIterator();
log.info("Reached the end of the term iterator for field: {}.", curField);
log.info("Reached the end of the term iterator for field: " + curField);
return Optional.empty();
} else {
@ -186,7 +186,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
if (curField == null) {
// field is not selected
log.warn("Field not selected.");
log.warning("Field not selected.");
return Optional.empty();
}
@ -197,7 +197,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
if (tenum.seekCeil(new BytesRef(termText)) == TermsEnum.SeekStatus.END) {
// reached to the end of the iterator
resetTermsIterator();
log.info("Reached the end of the term iterator for field: {}.", curField);
log.info("Reached the end of the term iterator for field: " + curField);
return Optional.empty();
} else {
return Optional.of(new Term(curField, tenum.term()));
@ -216,7 +216,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
public Optional<Integer> firstTermDoc() {
if (tenum == null) {
// terms enum is not set
log.warn("Terms enum un-positioned.");
log.warning("Terms enum un-positioned.");
return Optional.empty();
}
@ -226,10 +226,11 @@ public final class DocumentsImpl extends LukeModel implements Documents {
if (penum.nextDoc() == PostingsEnum.NO_MORE_DOCS) {
// no docs available for this term
resetPostingsIterator();
log.warn(
"No docs available for term: {} in field: {}.",
BytesRefUtils.decode(tenum.term()),
curField);
log.warning(
"No docs available for term: "
+ BytesRefUtils.decode(tenum.term())
+ " in field: "
+ curField);
return Optional.empty();
} else {
return Optional.of(penum.docID());
@ -245,7 +246,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
public Optional<Integer> nextTermDoc() {
if (penum == null) {
// postings enum is not initialized
log.warn("Postings enum un-positioned for field: {}.", curField);
log.warning("Postings enum un-positioned for field: " + curField);
return Optional.empty();
}
@ -253,12 +254,11 @@ public final class DocumentsImpl extends LukeModel implements Documents {
if (penum.nextDoc() == PostingsEnum.NO_MORE_DOCS) {
// end of the iterator
resetPostingsIterator();
if (log.isInfoEnabled()) {
log.info(
"Reached the end of the postings iterator for term: {} in field: {}",
BytesRefUtils.decode(tenum.term()),
curField);
}
log.info(
"Reached the end of the postings iterator for term: "
+ BytesRefUtils.decode(tenum.term())
+ " in field: "
+ curField);
return Optional.empty();
} else {
return Optional.of(penum.docID());
@ -274,7 +274,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
public List<TermPosting> getTermPositions() {
if (penum == null) {
// postings enum is not initialized
log.warn("Postings enum un-positioned for field: {}.", curField);
log.warning("Postings enum un-positioned for field: " + curField);
return Collections.emptyList();
}
@ -305,7 +305,7 @@ public final class DocumentsImpl extends LukeModel implements Documents {
public Optional<Integer> getDocFreq() {
if (tenum == null) {
// terms enum is not initialized
log.warn("Terms enum un-positioned for field: {}.", curField);
log.warning("Terms enum un-positioned for field: " + curField);
return Optional.empty();
}

View File

@ -22,8 +22,9 @@ import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import org.apache.logging.log4j.Logger;
import java.util.logging.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
@ -53,7 +54,10 @@ final class TermVectorsAdapter {
Terms termVector = reader.getTermVector(docid, field);
if (termVector == null) {
// no term vector available
log.warn("No term vector indexed for doc: #{} and field: {}", docid, field);
log.warning(
() ->
String.format(
Locale.ROOT, "No term vector indexed for doc: #%s and field: %s", docid, field));
return Collections.emptyList();
}

View File

@ -30,8 +30,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.FieldInfo;
@ -230,7 +230,7 @@ public final class SearchImpl extends LukeModel implements Search {
} else if (type == Float.class || type == Double.class) {
pc = new PointsConfig(NumberFormat.getNumberInstance(Locale.ROOT), type);
} else {
log.warn(
log.warning(
String.format(Locale.ENGLISH, "Ignored invalid number type: %s.", type.getName()));
continue;
}
@ -344,7 +344,7 @@ public final class SearchImpl extends LukeModel implements Search {
if (totalHits.value == 0
|| (totalHits.relation == TotalHits.Relation.EQUAL_TO
&& currentPage * pageSize >= totalHits.value)) {
log.warn("No more next search results are available.");
log.warning("No more next search results are available.");
return Optional.empty();
}
@ -375,7 +375,7 @@ public final class SearchImpl extends LukeModel implements Search {
currentPage -= 1;
if (currentPage < 0) {
log.warn("No more previous search results are available.");
log.warning("No more previous search results are available.");
return Optional.empty();
}
@ -462,7 +462,7 @@ public final class SearchImpl extends LukeModel implements Search {
Objects.requireNonNull(type);
List<SortField> candidates = guessSortTypes(name);
if (candidates.isEmpty()) {
log.warn(String.format(Locale.ENGLISH, "No available sort types for: %s", name));
log.warning(String.format(Locale.ENGLISH, "No available sort types for: %s", name));
return Optional.empty();
}

View File

@ -34,9 +34,10 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.codecs.CodecUtil;
@ -84,7 +85,7 @@ public final class IndexUtils {
DirectoryReader dr = DirectoryReader.open(dir);
readers.add(dr);
} catch (IOException e) {
log.warn("Error opening directory", e);
log.log(Level.WARNING, "Error opening directory", e);
}
return FileVisitResult.CONTINUE;
}
@ -94,14 +95,12 @@ public final class IndexUtils {
throw new RuntimeException("No valid directory at the location: " + indexPath);
}
if (log.isInfoEnabled()) {
log.info(
String.format(
Locale.ENGLISH,
"IndexReaders (%d leaf readers) successfully opened. Index path=%s",
readers.size(),
indexPath));
}
log.info(
String.format(
Locale.ENGLISH,
"IndexReaders (%d leaf readers) successfully opened. Index path=%s",
readers.size(),
indexPath));
if (readers.size() == 1) {
return readers.get(0);
@ -134,11 +133,9 @@ public final class IndexUtils {
public static Directory openDirectory(String dirPath, String dirImpl) throws IOException {
final Path path = FileSystems.getDefault().getPath(Objects.requireNonNull(dirPath));
Directory dir = openDirectory(path, dirImpl);
if (log.isInfoEnabled()) {
log.info(
String.format(
Locale.ENGLISH, "DirectoryReader successfully opened. Directory path=%s", dirPath));
}
log.info(
String.format(
Locale.ENGLISH, "DirectoryReader successfully opened. Directory path=%s", dirPath));
return dir;
}
@ -161,7 +158,7 @@ public final class IndexUtils {
dir = (Directory) constr.newInstance(path, null);
}
} catch (Exception e) {
log.warn("Invalid directory implementation class: {}", dirImpl, e);
log.log(Level.WARNING, "Invalid directory implementation class: " + dirImpl, e);
throw new IllegalArgumentException("Invalid directory implementation class: " + dirImpl);
}
}
@ -180,7 +177,7 @@ public final class IndexUtils {
log.info("Directory successfully closed.");
}
} catch (IOException e) {
log.error("Error closing directory", e);
log.log(Level.SEVERE, "Error closing directory", e);
}
}
@ -201,7 +198,7 @@ public final class IndexUtils {
}
}
} catch (IOException e) {
log.error("Error closing index reader", e);
log.log(Level.SEVERE, "Error closing index reader", e);
}
}

View File

@ -28,7 +28,8 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.Logger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.luke.util.LoggerFactory;
/**
@ -56,10 +57,8 @@ public class MessageFilesParser extends SimpleFileVisitor<Path> {
messages.add(parse(file));
}
}
} catch (
@SuppressWarnings("unused")
IOException e) {
log.warn("Invalid file? {}", file);
} catch (IOException e) {
log.log(Level.WARNING, "Invalid file? " + file, e);
}
return FileVisitResult.CONTINUE;
}

View File

@ -0,0 +1,114 @@
/*
* 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.luke.util;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
/** A {@link Handler} with a bounded buffer of recent log messages. */
public class CircularLogBufferHandler extends Handler {
/** Provides an immutable clone of the required data from a {@link LogRecord} logged elsewhere. */
public static final class ImmutableLogRecord {
private final String loggerName;
private final Level level;
private final String message;
private final Throwable thrown;
private final Instant instant;
public ImmutableLogRecord(LogRecord record) {
this.loggerName = record.getLoggerName();
this.level = record.getLevel();
this.message = record.getMessage();
this.thrown = record.getThrown();
this.instant = record.getInstant();
}
public String getLoggerName() {
return loggerName;
}
public Level getLevel() {
return level;
}
public String getMessage() {
return message;
}
public Throwable getThrown() {
return thrown;
}
public Instant getInstant() {
return instant;
}
}
/** Listeners receiving log state updates. */
public interface LogUpdateListener extends Consumer<Collection<ImmutableLogRecord>> {}
/** A bounded buffer of immutable log records that have been recently logged by the framework. */
private final ArrayDeque<ImmutableLogRecord> buffer = new ArrayDeque<>();
/**
* Listeners interested in receiving log state updates. At the moment listeners receive an
* iterable with all log records in the circular buffer. We could make it incremental for each
* consumer but for Luke it really doesn't matter since the rate of updates is very small.
*/
private final List<LogUpdateListener> listeners = new CopyOnWriteArrayList<>();
@Override
public void publish(LogRecord record) {
synchronized (buffer) {
buffer.addLast(new ImmutableLogRecord(record));
listeners.forEach(c -> c.accept(buffer));
}
}
@Override
public void flush() {
// Ignore.
}
@Override
public void close() throws SecurityException {
// Ignore.
}
public void addUpdateListener(LogUpdateListener listener) {
listeners.add(listener);
}
public void removeUpdateListener(LogUpdateListener listener) {
listeners.remove(listener);
}
/** @return Return a clone of the buffered records so far. */
public List<ImmutableLogRecord> getLogRecords() {
synchronized (buffer) {
return List.copyOf(buffer);
}
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.luke.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.function.Function;
public class LogRecordFormatter
implements Function<CircularLogBufferHandler.ImmutableLogRecord, String> {
@Override
public String apply(CircularLogBufferHandler.ImmutableLogRecord record) {
return String.format(
Locale.ROOT,
"%s [%s] %s: %s",
DateTimeFormatter.ofPattern("HH:mm:ss", Locale.ROOT)
.format(record.getInstant().atZone(ZoneId.systemDefault())),
record.getLevel(),
record.getLoggerName(),
record.getMessage()
+ (record.getThrown() == null ? "" : "\n" + toString(record.getThrown())));
}
private String toString(Throwable t) {
try (StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw)) {
t.printStackTrace(pw);
pw.flush();
return sw.toString();
} catch (IOException e) {
return "Could not dump stack trace: " + e.getMessage();
}
}
}

View File

@ -17,54 +17,28 @@
package org.apache.lucene.luke.util;
import java.nio.charset.StandardCharsets;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.lucene.luke.app.desktop.util.TextAreaAppender;
import java.util.logging.Level;
import java.util.logging.Logger;
/** Logger factory. This programmatically configures logger context (Appenders etc.) */
/** Logger factory. This configures log interceptors for the GUI. */
public class LoggerFactory {
public static CircularLogBufferHandler circularBuffer;
public static void initGuiLogging(String logFile) {
ConfigurationBuilder<BuiltConfiguration> builder =
ConfigurationBuilderFactory.newConfigurationBuilder();
builder.add(builder.newRootLogger(Level.INFO));
LoggerContext context = Configurator.initialize(builder.build());
public static void initGuiLogging() {
if (circularBuffer != null) {
throw new RuntimeException("Double-initialization?");
}
PatternLayout layout =
PatternLayout.newBuilder()
.withPattern("[%d{ISO8601}] %5p (%F:%L) - %m%n")
.withCharset(StandardCharsets.UTF_8)
.build();
circularBuffer = new CircularLogBufferHandler();
circularBuffer.setLevel(Level.FINEST);
Appender fileAppender =
FileAppender.newBuilder()
.setName("File")
.setLayout(layout)
.withFileName(logFile)
.withAppend(false)
.build();
fileAppender.start();
Appender textAreaAppender =
TextAreaAppender.newBuilder().setName("TextArea").setLayout(layout).build();
textAreaAppender.start();
context.getRootLogger().addAppender(fileAppender);
context.getRootLogger().addAppender(textAreaAppender);
context.updateLoggers();
// Only capture events from Lucene logger hierarchy.
var luceneRoot = Logger.getLogger("org.apache.lucene");
luceneRoot.setLevel(Level.FINEST);
luceneRoot.addHandler(circularBuffer);
}
public static Logger getLogger(Class<?> clazz) {
return LogManager.getLogger(clazz);
return Logger.getLogger(clazz.getName());
}
}

View File

@ -280,7 +280,7 @@ commits.label.files=Files
commits.label.segments=Segments (click rows for more details)
commits.label.segdetails=Segment details
# Logs
logs.label.see_also=See also:
logs.label.level=Log level:
# Help dialogs
help.fieldtype.TextField=A field that is indexed and tokenized, without term vectors.\n\n(Example Values)\n- Hello Lucene!
help.fieldtype.StringField=A field that is indexed but not tokenized: the entire String value is indexed as a single token.\n\n(Example Values)\n- Java

View File

@ -68,6 +68,7 @@ public class TestDocumentsImpl extends DocumentsTestBase {
assertEquals(DocValuesType.NONE, f1.getDvType());
assertEquals(0, f1.getPointDimensionCount());
assertEquals(0, f1.getPointNumBytes());
assertEquals(0, f1.getVectorDimension());
DocumentField f2 = fields.get(1);
assertEquals("author", f2.getName());
@ -83,6 +84,7 @@ public class TestDocumentsImpl extends DocumentsTestBase {
assertEquals(DocValuesType.NONE, f2.getDvType());
assertEquals(0, f2.getPointDimensionCount());
assertEquals(0, f2.getPointNumBytes());
assertEquals(0, f2.getVectorDimension());
DocumentField f3 = fields.get(2);
assertEquals("text", f3.getName());
@ -98,6 +100,7 @@ public class TestDocumentsImpl extends DocumentsTestBase {
assertEquals(DocValuesType.NONE, f3.getDvType());
assertEquals(0, f3.getPointDimensionCount());
assertEquals(0, f3.getPointNumBytes());
assertEquals(0, f3.getVectorDimension());
DocumentField f4 = fields.get(3);
assertEquals("subject", f4.getName());
@ -113,6 +116,7 @@ public class TestDocumentsImpl extends DocumentsTestBase {
assertEquals(DocValuesType.SORTED_SET, f4.getDvType());
assertEquals(0, f4.getPointDimensionCount());
assertEquals(0, f4.getPointNumBytes());
assertEquals(0, f4.getVectorDimension());
DocumentField f5 = fields.get(4);
assertEquals("downloads", f5.getName());

View File

@ -1341,9 +1341,10 @@ public abstract class BaseXYPointTestCase extends LuceneTestCase {
IndexSearcher searcher = newSearcher(reader);
for (int i = 0; i < numQueries; i++) {
float x = nextX();
float y = nextY();
float radius = (Float.MAX_VALUE / 2) * random().nextFloat();
XYCircle circle = ShapeTestUtil.nextCircle();
float x = circle.getX();
float y = circle.getY();
float radius = circle.getRadius();
BitSet expected = new BitSet();
for (int doc = 0; doc < reader.maxDoc(); doc++) {

View File

@ -12,8 +12,6 @@ org.antlr:antlr4-runtime:4.5.1-1 (1 constraints: 6a05b240)
org.apache.commons:commons-compress:1.19 (1 constraints: df04fa30)
org.apache.httpcomponents:httpclient:4.5.13 (1 constraints: 3f054e3b)
org.apache.httpcomponents:httpcore:4.4.13 (1 constraints: 591016a2)
org.apache.logging.log4j:log4j-api:2.13.2 (1 constraints: bb0e1b76)
org.apache.logging.log4j:log4j-core:2.13.2 (1 constraints: 3a053a3b)
org.apache.opennlp:opennlp-tools:1.9.1 (1 constraints: 0d050c36)
org.carrot2:morfologik-fsa:2.1.8 (1 constraints: da0d9b36)
org.carrot2:morfologik-polish:2.1.8 (1 constraints: 0d050036)

View File

@ -1,23 +1,21 @@
com.carrotsearch.randomizedtesting:*=2.7.6
com.carrotsearch:hppc=0.9.0
com.google.errorprone:*=2.4.0
com.ibm.icu:icu4j=70.1
commons-codec:commons-codec=1.13
io.sgr:s2-geometry-library-java=1.0.0
javax.servlet:javax.servlet-api=3.1.0
junit:junit=4.13.1
net.sourceforge.nekohtml:nekohtml=1.9.17
org.antlr:antlr4*=4.5.1-1
org.apache.commons:commons-compress=1.19
org.apache.httpcomponents:httpclient=4.5.13
org.apache.logging.log4j:*=2.13.2
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
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
com.carrotsearch.randomizedtesting:*=2.7.6
com.carrotsearch:hppc=0.9.0
com.google.errorprone:*=2.4.0
com.ibm.icu:icu4j=70.1
commons-codec:commons-codec=1.13
io.sgr:s2-geometry-library-java=1.0.0
javax.servlet:javax.servlet-api=3.1.0
junit:junit=4.13.1
net.sourceforge.nekohtml:nekohtml=1.9.17
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.carrot2:morfologik-*=2.1.8
org.eclipse.jetty:*=9.4.41.v20210516
org.hamcrest:*=2.2
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