From caad50304abda4f0f2b585216bf823be60f08cbe Mon Sep 17 00:00:00 2001 From: Lucas Lazogue Date: Mon, 17 Nov 2025 14:14:18 -0300 Subject: [PATCH 1/6] GXflow FullText Search Migration to GitHub --- gxflowfulltextsearch/pom.xml | 73 ++++++ .../genexus/CA/search/AnalyzerManager.java | 26 +++ .../com/genexus/CA/search/IndexManager.java | 27 +++ .../java/com/genexus/CA/search/Indexer.java | 209 ++++++++++++++++++ .../java/com/genexus/CA/search/Logger.java | 7 + .../java/com/genexus/CA/search/Searcher.java | 49 ++++ pom.xml | 1 + 7 files changed, 392 insertions(+) create mode 100644 gxflowfulltextsearch/pom.xml create mode 100644 gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java create mode 100644 gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java create mode 100644 gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java create mode 100644 gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java create mode 100644 gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java diff --git a/gxflowfulltextsearch/pom.xml b/gxflowfulltextsearch/pom.xml new file mode 100644 index 000000000..01aab85c2 --- /dev/null +++ b/gxflowfulltextsearch/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + + com.genexus + parent + ${revision}${changelist} + + + gxflowfulltextsearch + GXflow FullText Search + + + + org.apache.commons + commons-collections4 + 4.1 + + + org.apache.commons + commons-compress + 1.27.1 + + + commons-logging + commons-logging + 1.2 + + + org.apache.pdfbox + fontbox + 3.0.3 + + + org.apache.pdfbox + pdfbox + 3.0.3 + + + org.apache.lucene + lucene-core + 2.2.0 + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + + + + + GXflowFullTextSearch + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + + + + diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java new file mode 100644 index 000000000..bfdfdf594 --- /dev/null +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java @@ -0,0 +1,26 @@ +package com.genexus.CA.search; + +import java.util.HashMap; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; + +public class AnalyzerManager { + private static HashMap hash = new HashMap(); + + public static Analyzer getAnalyzer(String lang) { + Analyzer analyzer = null; + if (hash.containsKey(lang)) { + analyzer = (Analyzer)hash.get(lang); + } else { + if (lang.equals("spa")) { + analyzer = new StandardAnalyzer(); + } else { + analyzer = new StandardAnalyzer(); + } + + hash.put(lang, analyzer); + } + + return (Analyzer)analyzer; + } +} diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java new file mode 100644 index 000000000..532ba430e --- /dev/null +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java @@ -0,0 +1,27 @@ +package com.genexus.CA.search; + +import java.util.HashMap; + +public class IndexManager { + private static HashMap hash = new HashMap(); + + public static void addContent(String dir, String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { + getIndexer(dir).addContent(uri, lang, title, summary, fromFile, body, filePath); + } + + public static void deleteContent(String dir, String uri) { + getIndexer(dir).deleteContent(uri); + } + + private static synchronized Indexer getIndexer(String dir) { + Indexer indexer = null; + if (hash.containsKey(dir)) { + indexer = (Indexer)hash.get(dir); + } else { + indexer = new Indexer(dir); + hash.put(dir, indexer); + } + + return indexer; + } +} diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java new file mode 100644 index 000000000..bcd7f06e9 --- /dev/null +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java @@ -0,0 +1,209 @@ +package com.genexus.CA.search; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.Field.Index; +import org.apache.lucene.document.Field.Store; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.text.PDFTextStripper; +import org.apache.pdfbox.text.PDFTextStripperByArea; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFParagraph; + +public final class Indexer { + private String indexDirectory = "."; + private static final int IDX = 1; + private static final int DLT = 2; + + protected Indexer(String directory) { + this.indexDirectory = directory; + if (!this.indexExists(directory)) { + try { + this.indexDirectory = directory; + IndexWriter writer = new IndexWriter(directory, new StandardAnalyzer(), true); + writer.close(); + } catch (Exception var3) { + Logger.print(var3.toString()); + } + } + + } + + protected void addContent(String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { + Document doc = null; + doc = new Document(); + String content = ""; + if (fromFile == 1) { + try { + if (this.isMicrosoftExtension(filePath)) { + FileInputStream file = new FileInputStream(filePath); + XWPFDocument reader = new XWPFDocument(file); + List data = reader.getParagraphs(); + + XWPFParagraph p; + for(Iterator var14 = data.iterator(); var14.hasNext(); content = content + p.getText()) { + p = (XWPFParagraph)var14.next(); + } + } else if (this.isPdfExtension(filePath)) { + PDDocument document = Loader.loadPDF(new File(filePath)); + new PDFTextStripperByArea(); + PDFTextStripper tStripper = new PDFTextStripper(); + content = content + tStripper.getText(document); + } else if (this.isTxtExtension(filePath)) { + File txt = new File(filePath); + + String st; + for(BufferedReader br = new BufferedReader(new FileReader(txt)); (st = br.readLine()) != null; content = content + st) { + } + } + } catch (IOException var16) { + var16.printStackTrace(); + } + } + + if (doc != null) { + if (this.documentExists(uri, lang)) { + this.indexOperation(2, lang, (Document)null, uri.toLowerCase()); + } + + doc.add(new Field("uri", uri, Store.YES, Index.UN_TOKENIZED)); + doc.add(new Field("content", content, Store.YES, Index.TOKENIZED)); + + try { + this.indexOperation(1, lang, doc, (String)null); + } catch (Exception var15) { + Logger.print(var15.toString()); + } + } + + } + + protected void deleteContent(String uri) { + try { + this.indexOperation(2, (String)null, (Document)null, uri.toLowerCase()); + } catch (Exception var3) { + Logger.print(var3.toString()); + } + + } + + protected synchronized void indexOperation(int op, String lang, Document doc, String uri) { + switch(op) { + case 1: + try { + IndexWriter writer = new IndexWriter(this.getIndexDirectory(), AnalyzerManager.getAnalyzer(lang), false); + writer.addDocument(doc); + writer.optimize(); + writer.close(); + } catch (Exception var9) { + Logger.print(var9.toString()); + } + break; + case 2: + try { + Term term = null; + int docId = 0; + if (lang == null) { + term = new Term("uri", uri); + } else { + docId = this.getDocumentId(uri, lang); + } + + IndexReader reader = IndexReader.open(this.getIndexDirectory()); + if (lang == null) { + reader.deleteDocuments(term); + } else if (docId != -1) { + reader.deleteDocument(docId); + } + + reader.close(); + } catch (Exception var8) { + Logger.print(var8.toString()); + } + } + + } + + public String getIndexDirectory() { + return this.indexDirectory; + } + + private boolean indexExists(String dir) { + try { + new IndexSearcher(dir); + return true; + } catch (IOException var3) { + return false; + } + } + + private boolean documentExists(String uri, String lang) { + boolean value = false; + + try { + IndexSearcher searcher = new IndexSearcher(this.indexDirectory); + BooleanQuery query = new BooleanQuery(); + query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); + query.add(new TermQuery(new Term("language", lang)), Occur.MUST); + Hits hits = searcher.search(query); + searcher.close(); + if (hits.length() > 0) { + value = true; + } + } catch (IOException var7) { + Logger.print(var7.toString()); + } + + return value; + } + + private int getDocumentId(String uri, String lang) { + int value = -1; + + try { + IndexSearcher searcher = new IndexSearcher(this.indexDirectory); + BooleanQuery query = new BooleanQuery(); + query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); + query.add(new TermQuery(new Term("language", lang)), Occur.MUST); + Hits hits = searcher.search(query); + if (hits.length() > 0) { + value = hits.id(0); + } + + searcher.close(); + } catch (IOException var7) { + Logger.print(var7.toString()); + } + + return value; + } + + private boolean isMicrosoftExtension(String filePath) { + return filePath.endsWith(".doc") || filePath.endsWith(".docx") || filePath.endsWith(".xls") || filePath.endsWith(".xlsx") || filePath.endsWith(".ppt") || filePath.endsWith(".pptx"); + } + + private boolean isPdfExtension(String filePath) { + return filePath.endsWith(".pdf"); + } + + private boolean isTxtExtension(String filePath) { + return filePath.endsWith(".txt") || filePath.endsWith(".html"); + } +} diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java new file mode 100644 index 000000000..1b646cec9 --- /dev/null +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java @@ -0,0 +1,7 @@ +package com.genexus.CA.search; + +public class Logger { + public static void print(String str) { + System.err.println("CASearch:" + str); + } +} diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java new file mode 100644 index 000000000..e5336f53c --- /dev/null +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java @@ -0,0 +1,49 @@ +package com.genexus.CA.search; + +import org.apache.lucene.document.Document; +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.MultiFieldQueryParser; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.BooleanClause.Occur; + +public class Searcher { + public static String search(String dir, String lang, String query, int maxResults, int from) { + StringBuffer buff = new StringBuffer(); + + try { + IndexSearcher searcher = new IndexSearcher(dir); + String[] fields = new String[]{"title", "content"}; + Occur[] clauses = new Occur[]{Occur.SHOULD, Occur.SHOULD}; + Query q = MultiFieldQueryParser.parse(query, fields, clauses, AnalyzerManager.getAnalyzer(lang)); + if (!lang.equals("IND")) { + Query q2 = new TermQuery(new Term("language", lang)); + BooleanQuery bq = new BooleanQuery(); + bq.add((Query)q, Occur.MUST); + bq.add(q2, Occur.MUST); + q = bq; + } + + Hits hits = searcher.search((Query)q); + String time = ""; + int max = hits.length(); + buff.append(""); + buff.append(""); + + for(int i = 0; i < max; ++i) { + buff.append(""); + Document doc = hits.doc(i); + buff.append("" + doc.getField("uri").stringValue() + ""); + buff.append(""); + } + } catch (Exception var15) { + Logger.print(var15.toString()); + } + + buff.append(""); + return buff.toString(); + } +} diff --git a/pom.xml b/pom.xml index 07596c207..2552ce949 100644 --- a/pom.xml +++ b/pom.xml @@ -127,6 +127,7 @@ gxftps gamutils gamtotp + gxflowfulltextsearch From 79234155c8b7dba7963f01928c128f5c08906104 Mon Sep 17 00:00:00 2001 From: Lucas Lazogue Date: Tue, 18 Nov 2025 14:11:15 -0300 Subject: [PATCH 2/6] centralize dependency versions and remove redundant deps --- gxflowfulltextsearch/pom.xml | 23 ++++------------------- gxsearch/pom.xml | 6 +++--- java/pom.xml | 4 ++-- pom.xml | 4 ++++ 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/gxflowfulltextsearch/pom.xml b/gxflowfulltextsearch/pom.xml index 01aab85c2..e5973ce18 100644 --- a/gxflowfulltextsearch/pom.xml +++ b/gxflowfulltextsearch/pom.xml @@ -15,32 +15,22 @@ org.apache.commons commons-collections4 - 4.1 - - - org.apache.commons - commons-compress - 1.27.1 + ${commons.collections4.version} commons-logging commons-logging - 1.2 - - - org.apache.pdfbox - fontbox - 3.0.3 + ${commons.logging.version} org.apache.pdfbox pdfbox - 3.0.3 + ${pdfbox.version} org.apache.lucene lucene-core - 2.2.0 + ${lucene.version} org.apache.poi @@ -52,11 +42,6 @@ poi-ooxml ${poi.version} - - org.apache.poi - poi-ooxml-schemas - 4.1.2 - diff --git a/gxsearch/pom.xml b/gxsearch/pom.xml index 51abb16ea..2c4ba8012 100644 --- a/gxsearch/pom.xml +++ b/gxsearch/pom.xml @@ -32,17 +32,17 @@ org.apache.lucene lucene-core - 2.2.0 + ${lucene.version} org.apache.lucene lucene-highlighter - 2.2.0 + ${lucene.version} org.apache.lucene lucene-spellchecker - 2.2.0 + ${lucene.version} com.github.jtidy diff --git a/java/pom.xml b/java/pom.xml index e3c4e5750..c897b8cfc 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -37,7 +37,7 @@ org.apache.commons commons-collections4 - 4.1 + ${commons.collections4.version} org.apache.logging.log4j @@ -110,7 +110,7 @@ org.apache.pdfbox pdfbox - 3.0.3 + ${pdfbox.version} org.jsoup diff --git a/pom.xml b/pom.xml index 2552ce949..c8e66393f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,10 @@ 3.0.4 UTF-8 5.4.1 + 3.0.3 + 2.2.0 + 4.1 + 1.2 2.16.2 4.13.2 2.35.6 From 28d56d2859b58e54be5cac1352ea99ae7a3b3034 Mon Sep 17 00:00:00 2001 From: Lucas Lazogue Date: Tue, 18 Nov 2025 14:59:55 -0300 Subject: [PATCH 3/6] Delete Logger class and use log4j --- gxflowfulltextsearch/pom.xml | 5 + .../genexus/CA/search/AnalyzerManager.java | 2 +- .../com/genexus/CA/search/IndexManager.java | 2 +- .../java/com/genexus/CA/search/Indexer.java | 91 +++++++++---------- .../java/com/genexus/CA/search/Logger.java | 7 -- .../java/com/genexus/CA/search/Searcher.java | 66 +++++++------- 6 files changed, 86 insertions(+), 87 deletions(-) delete mode 100644 gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java diff --git a/gxflowfulltextsearch/pom.xml b/gxflowfulltextsearch/pom.xml index e5973ce18..ea5c5856d 100644 --- a/gxflowfulltextsearch/pom.xml +++ b/gxflowfulltextsearch/pom.xml @@ -42,6 +42,11 @@ poi-ooxml ${poi.version} + + org.apache.logging.log4j + log4j-core + ${log4j.version} + diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java index bfdfdf594..7e121a34c 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java @@ -5,7 +5,7 @@ import org.apache.lucene.analysis.standard.StandardAnalyzer; public class AnalyzerManager { - private static HashMap hash = new HashMap(); + private static final HashMap hash = new HashMap(); public static Analyzer getAnalyzer(String lang) { Analyzer analyzer = null; diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java index 532ba430e..6b24e00e9 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java @@ -3,7 +3,7 @@ import java.util.HashMap; public class IndexManager { - private static HashMap hash = new HashMap(); + private static final HashMap hash = new HashMap(); public static void addContent(String dir, String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { getIndexer(dir).addContent(uri, lang, title, summary, fromFile, body, filePath); diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java index bcd7f06e9..f04416b02 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java @@ -1,12 +1,13 @@ package com.genexus.CA.search; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; import java.util.Iterator; import java.util.List; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -32,6 +33,8 @@ public final class Indexer { private static final int IDX = 1; private static final int DLT = 2; + private static final Logger logger = LogManager.getLogger("Indexer.class"); + protected Indexer(String directory) { this.indexDirectory = directory; if (!this.indexExists(directory)) { @@ -40,7 +43,7 @@ protected Indexer(String directory) { IndexWriter writer = new IndexWriter(directory, new StandardAnalyzer(), true); writer.close(); } catch (Exception var3) { - Logger.print(var3.toString()); + logger.error(var3.getMessage(), var3); } } @@ -58,40 +61,32 @@ protected void addContent(String uri, String lang, String title, String summary, List data = reader.getParagraphs(); XWPFParagraph p; - for(Iterator var14 = data.iterator(); var14.hasNext(); content = content + p.getText()) { - p = (XWPFParagraph)var14.next(); + for(Iterator var14 = data.iterator(); var14.hasNext(); content = content + p.getText()) { + p = var14.next(); } } else if (this.isPdfExtension(filePath)) { PDDocument document = Loader.loadPDF(new File(filePath)); new PDFTextStripperByArea(); PDFTextStripper tStripper = new PDFTextStripper(); content = content + tStripper.getText(document); - } else if (this.isTxtExtension(filePath)) { - File txt = new File(filePath); - - String st; - for(BufferedReader br = new BufferedReader(new FileReader(txt)); (st = br.readLine()) != null; content = content + st) { - } } } catch (IOException var16) { var16.printStackTrace(); } } - if (doc != null) { - if (this.documentExists(uri, lang)) { - this.indexOperation(2, lang, (Document)null, uri.toLowerCase()); - } + if (this.documentExists(uri, lang)) { + this.indexOperation(2, lang, (Document) null, uri.toLowerCase()); + } - doc.add(new Field("uri", uri, Store.YES, Index.UN_TOKENIZED)); - doc.add(new Field("content", content, Store.YES, Index.TOKENIZED)); + doc.add(new Field("uri", uri, Store.YES, Index.UN_TOKENIZED)); + doc.add(new Field("content", content, Store.YES, Index.TOKENIZED)); - try { - this.indexOperation(1, lang, doc, (String)null); - } catch (Exception var15) { - Logger.print(var15.toString()); - } - } + try { + this.indexOperation(1, lang, doc, (String)null); + } catch (Exception var15) { + logger.error(var15.getMessage(), var15); + } } @@ -99,7 +94,7 @@ protected void deleteContent(String uri) { try { this.indexOperation(2, (String)null, (Document)null, uri.toLowerCase()); } catch (Exception var3) { - Logger.print(var3.toString()); + logger.error(var3.getMessage(), var3); } } @@ -113,7 +108,7 @@ protected synchronized void indexOperation(int op, String lang, Document doc, St writer.optimize(); writer.close(); } catch (Exception var9) { - Logger.print(var9.toString()); + logger.error(var9.getMessage(), var9); } break; case 2: @@ -135,7 +130,7 @@ protected synchronized void indexOperation(int op, String lang, Document doc, St reader.close(); } catch (Exception var8) { - Logger.print(var8.toString()); + logger.error(var8.getMessage(), var8); } } @@ -157,19 +152,10 @@ private boolean indexExists(String dir) { private boolean documentExists(String uri, String lang) { boolean value = false; - try { - IndexSearcher searcher = new IndexSearcher(this.indexDirectory); - BooleanQuery query = new BooleanQuery(); - query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); - query.add(new TermQuery(new Term("language", lang)), Occur.MUST); - Hits hits = searcher.search(query); - searcher.close(); - if (hits.length() > 0) { - value = true; - } - } catch (IOException var7) { - Logger.print(var7.toString()); - } + Hits hits = getHits(uri, lang); + if (hits.length() > 0) { + value = true; + } return value; } @@ -178,18 +164,12 @@ private int getDocumentId(String uri, String lang) { int value = -1; try { - IndexSearcher searcher = new IndexSearcher(this.indexDirectory); - BooleanQuery query = new BooleanQuery(); - query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); - query.add(new TermQuery(new Term("language", lang)), Occur.MUST); - Hits hits = searcher.search(query); + Hits hits = this.getHits(uri, lang); if (hits.length() > 0) { value = hits.id(0); } - - searcher.close(); } catch (IOException var7) { - Logger.print(var7.toString()); + logger.error(var7.getMessage(), var7); } return value; @@ -199,6 +179,23 @@ private boolean isMicrosoftExtension(String filePath) { return filePath.endsWith(".doc") || filePath.endsWith(".docx") || filePath.endsWith(".xls") || filePath.endsWith(".xlsx") || filePath.endsWith(".ppt") || filePath.endsWith(".pptx"); } + private Hits getHits(String uri, String lang) { + IndexSearcher searcher = null; + Hits hits = null; + try { + searcher = new IndexSearcher(this.indexDirectory); + BooleanQuery query = new BooleanQuery(); + query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); + query.add(new TermQuery(new Term("language", lang)), Occur.MUST); + hits = searcher.search(query); + searcher.close(); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + + return hits; + } + private boolean isPdfExtension(String filePath) { return filePath.endsWith(".pdf"); } diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java deleted file mode 100644 index 1b646cec9..000000000 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Logger.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.genexus.CA.search; - -public class Logger { - public static void print(String str) { - System.err.println("CASearch:" + str); - } -} diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java index e5336f53c..2c2549303 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java @@ -1,5 +1,7 @@ package com.genexus.CA.search; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.MultiFieldQueryParser; @@ -11,39 +13,41 @@ import org.apache.lucene.search.BooleanClause.Occur; public class Searcher { - public static String search(String dir, String lang, String query, int maxResults, int from) { - StringBuffer buff = new StringBuffer(); + private static final Logger logger = LogManager.getLogger("Searcher.class"); - try { - IndexSearcher searcher = new IndexSearcher(dir); - String[] fields = new String[]{"title", "content"}; - Occur[] clauses = new Occur[]{Occur.SHOULD, Occur.SHOULD}; - Query q = MultiFieldQueryParser.parse(query, fields, clauses, AnalyzerManager.getAnalyzer(lang)); - if (!lang.equals("IND")) { - Query q2 = new TermQuery(new Term("language", lang)); - BooleanQuery bq = new BooleanQuery(); - bq.add((Query)q, Occur.MUST); - bq.add(q2, Occur.MUST); - q = bq; - } + public static String search(String dir, String lang, String query, int maxResults, int from) { + StringBuilder buff = new StringBuilder(); - Hits hits = searcher.search((Query)q); - String time = ""; - int max = hits.length(); - buff.append(""); - buff.append(""); + try { + IndexSearcher searcher = new IndexSearcher(dir); + String[] fields = new String[]{"title", "content"}; + Occur[] clauses = new Occur[]{Occur.SHOULD, Occur.SHOULD}; + Query q = MultiFieldQueryParser.parse(query, fields, clauses, AnalyzerManager.getAnalyzer(lang)); + if (!lang.equals("IND")) { + Query q2 = new TermQuery(new Term("language", lang)); + BooleanQuery bq = new BooleanQuery(); + bq.add((Query) q, Occur.MUST); + bq.add(q2, Occur.MUST); + q = bq; + } - for(int i = 0; i < max; ++i) { - buff.append(""); - Document doc = hits.doc(i); - buff.append("" + doc.getField("uri").stringValue() + ""); - buff.append(""); - } - } catch (Exception var15) { - Logger.print(var15.toString()); - } + Hits hits = searcher.search((Query) q); + String time = ""; + int max = hits.length(); + buff.append(""); + buff.append(""); - buff.append(""); - return buff.toString(); - } + for (int i = 0; i < max; ++i) { + buff.append(""); + Document doc = hits.doc(i); + buff.append("").append(doc.getField("uri").stringValue()).append(""); + buff.append(""); + } + } catch (Exception var15) { + logger.error(var15.getMessage(), var15); + } + + buff.append(""); + return buff.toString(); + } } From 884e5f1d21608be80357b525c4ea1fa6a76dae57 Mon Sep 17 00:00:00 2001 From: Lucas Lazogue Date: Thu, 22 Jan 2026 12:37:06 -0300 Subject: [PATCH 4/6] Refactorize code --- .../genexus/CA/search/AnalyzerManager.java | 33 ++- .../com/genexus/CA/search/IndexManager.java | 31 +-- .../java/com/genexus/CA/search/Indexer.java | 249 +++++++++++------- .../java/com/genexus/CA/search/Searcher.java | 108 ++++++-- 4 files changed, 272 insertions(+), 149 deletions(-) diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java index 7e121a34c..d8df364a1 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/AnalyzerManager.java @@ -1,26 +1,25 @@ package com.genexus.CA.search; -import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; public class AnalyzerManager { - private static final HashMap hash = new HashMap(); - - public static Analyzer getAnalyzer(String lang) { - Analyzer analyzer = null; - if (hash.containsKey(lang)) { - analyzer = (Analyzer)hash.get(lang); - } else { - if (lang.equals("spa")) { - analyzer = new StandardAnalyzer(); - } else { - analyzer = new StandardAnalyzer(); - } + private static final Map ANALYZERS = new ConcurrentHashMap<>(); - hash.put(lang, analyzer); - } + static { + ANALYZERS.put("default", new StandardAnalyzer()); + // In the future, when the Lucene version is updated, specific analyzers for different languages can be added here. + // For example, for Spanish: + // ANALYZERS.put("es", new org.apache.lucene.analysis.es.SpanishAnalyzer()); + } - return (Analyzer)analyzer; - } + public static Analyzer getAnalyzer(String lang) { + if (lang == null || lang.trim().isEmpty()) { + return ANALYZERS.get("default"); + } + return ANALYZERS.getOrDefault(lang, ANALYZERS.get("default")); + } } diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java index 6b24e00e9..f2f26768f 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/IndexManager.java @@ -1,27 +1,20 @@ package com.genexus.CA.search; -import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class IndexManager { - private static final HashMap hash = new HashMap(); + private static final Map INDEXERS = new ConcurrentHashMap<>(); - public static void addContent(String dir, String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { - getIndexer(dir).addContent(uri, lang, title, summary, fromFile, body, filePath); - } + public static void addContent(String dir, String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { + getIndexer(dir).addContent(uri, lang, title, summary, fromFile, body, filePath); + } - public static void deleteContent(String dir, String uri) { - getIndexer(dir).deleteContent(uri); - } + public static void deleteContent(String dir, String uri) { + getIndexer(dir).deleteContent(uri); + } - private static synchronized Indexer getIndexer(String dir) { - Indexer indexer = null; - if (hash.containsKey(dir)) { - indexer = (Indexer)hash.get(dir); - } else { - indexer = new Indexer(dir); - hash.put(dir, indexer); - } - - return indexer; - } + private static Indexer getIndexer(String dir) { + return INDEXERS.computeIfAbsent(dir, Indexer::new); + } } diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java index f04416b02..f4b982ac4 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Indexer.java @@ -1,13 +1,16 @@ package com.genexus.CA.search; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.Iterator; -import java.util.List; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -24,94 +27,106 @@ import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; -import org.apache.pdfbox.text.PDFTextStripperByArea; + import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; public final class Indexer { private String indexDirectory = "."; - private static final int IDX = 1; - private static final int DLT = 2; + private static final int OPERATION_INDEX = 1; + private static final int OPERATION_DELETE = 2; - private static final Logger logger = LogManager.getLogger("Indexer.class"); + private static final Logger logger = LogManager.getLogger(Indexer.class); - protected Indexer(String directory) { - this.indexDirectory = directory; - if (!this.indexExists(directory)) { + Indexer(String directory) { + this.indexDirectory = normalizeIndexDirectory(directory); + if (!this.indexExists(this.indexDirectory)) { try { - this.indexDirectory = directory; - IndexWriter writer = new IndexWriter(directory, new StandardAnalyzer(), true); + IndexWriter writer = new IndexWriter(this.indexDirectory, new StandardAnalyzer(), true); writer.close(); - } catch (Exception var3) { - logger.error(var3.getMessage(), var3); + } catch (Exception e) { + logger.error("Error creating index directory: {}", this.indexDirectory, e); } } } - protected void addContent(String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { - Document doc = null; - doc = new Document(); - String content = ""; - if (fromFile == 1) { - try { - if (this.isMicrosoftExtension(filePath)) { - FileInputStream file = new FileInputStream(filePath); - XWPFDocument reader = new XWPFDocument(file); - List data = reader.getParagraphs(); - - XWPFParagraph p; - for(Iterator var14 = data.iterator(); var14.hasNext(); content = content + p.getText()) { - p = var14.next(); - } - } else if (this.isPdfExtension(filePath)) { - PDDocument document = Loader.loadPDF(new File(filePath)); - new PDFTextStripperByArea(); - PDFTextStripper tStripper = new PDFTextStripper(); - content = content + tStripper.getText(document); - } - } catch (IOException var16) { - var16.printStackTrace(); - } - } + void addContent(String uri, String lang, String title, String summary, byte fromFile, String body, String filePath) { + Document doc = new Document(); + StringBuilder contentBuilder = new StringBuilder(); + boolean fileContentRead = false; + String normalizedUri = normalizeUri(uri); + String normalizedLang = normalizeLang(lang); - if (this.documentExists(uri, lang)) { - this.indexOperation(2, lang, (Document) null, uri.toLowerCase()); - } + if (fromFile == 1 && filePath != null && !filePath.trim().isEmpty()) { + String lowerFilePath = filePath.toLowerCase(); + try { + if (this.isDocxExtension(lowerFilePath)) { + try (FileInputStream file = new FileInputStream(filePath); XWPFDocument reader = new XWPFDocument(file)) { + for (XWPFParagraph p : reader.getParagraphs()) { + contentBuilder.append(p.getText()).append(" "); + } + fileContentRead = true; + } + } else if (this.isPdfExtension(lowerFilePath)) { + try (PDDocument document = Loader.loadPDF(new File(filePath))) { + PDFTextStripper tStripper = new PDFTextStripper(); + contentBuilder.append(tStripper.getText(document)); + fileContentRead = true; + } + } else if (this.isTxtExtension(lowerFilePath)) { + contentBuilder.append(readTextFile(filePath)); + fileContentRead = true; + } + } catch (IOException e) { + logger.error("Error reading file content from: {}", filePath, e); + } + } - doc.add(new Field("uri", uri, Store.YES, Index.UN_TOKENIZED)); - doc.add(new Field("content", content, Store.YES, Index.TOKENIZED)); + if (body != null && !body.isEmpty() && !fileContentRead) { + contentBuilder.append(body); + } + + String content = contentBuilder.toString(); - try { - this.indexOperation(1, lang, doc, (String)null); - } catch (Exception var15) { - logger.error(var15.getMessage(), var15); - } + this.indexOperation(OPERATION_DELETE, normalizedLang, null, normalizedUri); + doc.add(new Field("uri", normalizedUri, Store.YES, Index.UN_TOKENIZED)); + doc.add(new Field("language", normalizedLang, Store.YES, Index.UN_TOKENIZED)); + doc.add(new Field("title", title == null ? "" : title, Store.YES, Index.TOKENIZED)); + doc.add(new Field("summary", summary == null ? "" : summary, Store.YES, Index.TOKENIZED)); + doc.add(new Field("content", content, Store.YES, Index.TOKENIZED)); + + try { + this.indexOperation(OPERATION_INDEX, normalizedLang, doc, null); + } catch (Exception e) { + logger.error("Error indexing content. uri={}, lang={}", normalizedUri, normalizedLang, e); + } } - protected void deleteContent(String uri) { + void deleteContent(String uri) { try { - this.indexOperation(2, (String)null, (Document)null, uri.toLowerCase()); - } catch (Exception var3) { - logger.error(var3.getMessage(), var3); + this.indexOperation(OPERATION_DELETE, null, null, normalizeUri(uri)); + } catch (Exception e) { + logger.error("Error deleting content. uri={}", uri, e); } } - protected synchronized void indexOperation(int op, String lang, Document doc, String uri) { + private synchronized void indexOperation(int op, String lang, Document doc, String uri) { switch(op) { - case 1: + case OPERATION_INDEX: try { IndexWriter writer = new IndexWriter(this.getIndexDirectory(), AnalyzerManager.getAnalyzer(lang), false); writer.addDocument(doc); - writer.optimize(); + // writer.optimize(); // This is a costly operation and should not be done for every document. writer.close(); - } catch (Exception var9) { - logger.error(var9.getMessage(), var9); + } catch (Exception e) { + logger.error("Error indexing document. uri={}, lang={}", uri, lang, e); } break; - case 2: + case OPERATION_DELETE: + IndexReader reader = null; try { Term term = null; int docId = 0; @@ -121,16 +136,23 @@ protected synchronized void indexOperation(int op, String lang, Document doc, St docId = this.getDocumentId(uri, lang); } - IndexReader reader = IndexReader.open(this.getIndexDirectory()); + reader = IndexReader.open(this.getIndexDirectory()); if (lang == null) { reader.deleteDocuments(term); } else if (docId != -1) { reader.deleteDocument(docId); } - reader.close(); - } catch (Exception var8) { - logger.error(var8.getMessage(), var8); + } catch (Exception e) { + logger.error("Error deleting document. uri={}, lang={}", uri, lang, e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + logger.error("Error closing IndexReader", e); + } + } } } @@ -140,67 +162,98 @@ public String getIndexDirectory() { return this.indexDirectory; } + private String normalizeIndexDirectory(String dir) { + if (dir == null || dir.trim().isEmpty()) { + return "."; + } + return new File(dir).getAbsolutePath(); + } + private boolean indexExists(String dir) { try { new IndexSearcher(dir); return true; - } catch (IOException var3) { + } catch (IOException e) { return false; } } - private boolean documentExists(String uri, String lang) { - boolean value = false; + private int getDocumentId(String uri, String lang) { + int documentId = -1; - Hits hits = getHits(uri, lang); - if (hits.length() > 0) { - value = true; - } + try { + Hits hits = this.getHits(uri, lang); + if (hits.length() > 0) { + documentId = hits.id(0); + } + } catch (IOException e) { + logger.error("Error getting document id. uri={}, lang={}", uri, lang, e); + } - return value; + return documentId; } - private int getDocumentId(String uri, String lang) { - int value = -1; + private boolean isDocxExtension(String filePath) { + return filePath.toLowerCase().endsWith(".docx"); + } + private Hits getHits(String uri, String lang) { + IndexSearcher searcher = null; + Hits hits = null; try { - Hits hits = this.getHits(uri, lang); - if (hits.length() > 0) { - value = hits.id(0); + searcher = new IndexSearcher(this.indexDirectory); + BooleanQuery query = new BooleanQuery(); + query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); + if (lang != null && !lang.trim().isEmpty()) { + query.add(new TermQuery(new Term("language", lang)), Occur.MUST); + } + hits = searcher.search(query); + } catch (IOException e) { + logger.error("Error searching hits. uri={}, lang={}", uri, lang, e); + } finally { + if (searcher != null) { + try { + searcher.close(); + } catch (IOException e) { + logger.error("Error closing IndexSearcher", e); + } } - } catch (IOException var7) { - logger.error(var7.getMessage(), var7); } - return value; + return hits; } - private boolean isMicrosoftExtension(String filePath) { - return filePath.endsWith(".doc") || filePath.endsWith(".docx") || filePath.endsWith(".xls") || filePath.endsWith(".xlsx") || filePath.endsWith(".ppt") || filePath.endsWith(".pptx"); + private String normalizeUri(String uri) { + if (uri == null) { + return ""; + } + return uri.trim().toLowerCase(); } - private Hits getHits(String uri, String lang) { - IndexSearcher searcher = null; - Hits hits = null; - try { - searcher = new IndexSearcher(this.indexDirectory); - BooleanQuery query = new BooleanQuery(); - query.add(new TermQuery(new Term("uri", uri)), Occur.MUST); - query.add(new TermQuery(new Term("language", lang)), Occur.MUST); - hits = searcher.search(query); - searcher.close(); - } catch (IOException e) { - logger.error(e.getMessage(), e); - } - - return hits; + private String normalizeLang(String lang) { + if (lang == null) { + return ""; + } + return lang.trim().toLowerCase(); + } + + private String readTextFile(String filePath) throws IOException { + StringBuilder builder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(filePath)), StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append(' '); + } + } + return builder.toString(); } private boolean isPdfExtension(String filePath) { - return filePath.endsWith(".pdf"); + return filePath.toLowerCase().endsWith(".pdf"); } private boolean isTxtExtension(String filePath) { - return filePath.endsWith(".txt") || filePath.endsWith(".html"); + String lowerFilePath = filePath.toLowerCase(); + return lowerFilePath.endsWith(".txt") || lowerFilePath.endsWith(".html"); } } diff --git a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java index 2c2549303..676627357 100644 --- a/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java +++ b/gxflowfulltextsearch/src/main/java/com/genexus/CA/search/Searcher.java @@ -5,6 +5,8 @@ import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.MultiFieldQueryParser; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; @@ -13,41 +15,117 @@ import org.apache.lucene.search.BooleanClause.Occur; public class Searcher { - private static final Logger logger = LogManager.getLogger("Searcher.class"); + private static final Logger logger = LogManager.getLogger(Searcher.class); + + private static String escapeXml(String text) { + if (text == null) { + return ""; + } + return text.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) + .replace("'", "'"); + } public static String search(String dir, String lang, String query, int maxResults, int from) { StringBuilder buff = new StringBuilder(); + long startTime = System.currentTimeMillis(); + + if (from < 0) { + logger.warn("Search 'from' cannot be negative. Using 0 instead. from={}", from); + from = 0; + } + if (maxResults < 0) { + logger.warn("Search 'maxResults' cannot be negative. Using 0 instead. maxResults={}", maxResults); + maxResults = 0; + } + if (!indexExists(dir)) { + buff.append(""); + return buff.toString(); + } + + IndexSearcher searcher = null; try { - IndexSearcher searcher = new IndexSearcher(dir); - String[] fields = new String[]{"title", "content"}; - Occur[] clauses = new Occur[]{Occur.SHOULD, Occur.SHOULD}; - Query q = MultiFieldQueryParser.parse(query, fields, clauses, AnalyzerManager.getAnalyzer(lang)); - if (!lang.equals("IND")) { + searcher = new IndexSearcher(dir); + String[] fields = new String[]{"title", "content", "summary"}; + Occur[] clauses = new Occur[]{Occur.SHOULD, Occur.SHOULD, Occur.SHOULD}; + + Query q; + try { + q = MultiFieldQueryParser.parse(query, fields, clauses, AnalyzerManager.getAnalyzer(lang)); + } catch (ParseException e) { + try { + String escapedQuery = QueryParser.escape(query); + q = MultiFieldQueryParser.parse(escapedQuery, fields, clauses, AnalyzerManager.getAnalyzer(lang)); + logger.warn("Query had invalid syntax. Escaped version was used: {}", escapedQuery, e); + } catch (ParseException escapedException) { + logger.warn("Could not parse query, falling back to TermQuery: " + query, escapedException); + q = new TermQuery(new Term("content", query)); + } + } + + if (lang != null && !lang.trim().isEmpty() && !"IND".equalsIgnoreCase(lang)) { Query q2 = new TermQuery(new Term("language", lang)); BooleanQuery bq = new BooleanQuery(); - bq.add((Query) q, Occur.MUST); + bq.add(q, Occur.MUST); bq.add(q2, Occur.MUST); q = bq; } - Hits hits = searcher.search((Query) q); - String time = ""; - int max = hits.length(); + Hits hits = searcher.search(q); + int totalHits = hits.length(); + + long endTime = System.currentTimeMillis(); + String time = String.valueOf(endTime - startTime); + buff.append(""); - buff.append(""); + buff.append(""); - for (int i = 0; i < max; ++i) { + int end = Math.min(totalHits, from + maxResults); + for (int i = from; i < end; i++) { buff.append(""); Document doc = hits.doc(i); - buff.append("").append(doc.getField("uri").stringValue()).append(""); + String uri = doc.getField("uri").stringValue(); + buff.append("").append(escapeXml(uri)).append(""); buff.append(""); } - } catch (Exception var15) { - logger.error(var15.getMessage(), var15); + } catch (Exception e) { + logger.error("Error during search", e); + // Return an empty but valid XML in case of error + buff.setLength(0); // Clear buffer + buff.append(""); + return buff.toString(); + } finally { + if (searcher != null) { + try { + searcher.close(); + } catch (Exception e) { + logger.error("Error closing IndexSearcher", e); + } + } } buff.append(""); return buff.toString(); } + + private static boolean indexExists(String dir) { + IndexSearcher searcher = null; + try { + searcher = new IndexSearcher(dir); + return true; + } catch (Exception e) { + return false; + } finally { + if (searcher != null) { + try { + searcher.close(); + } catch (Exception e) { + logger.warn("Error closing IndexSearcher during indexExists check", e); + } + } + } + } } From 9440967fe14caed35c23c26e6ec13e78d81b6463 Mon Sep 17 00:00:00 2001 From: Lucas Lazogue Date: Thu, 22 Jan 2026 12:47:54 -0300 Subject: [PATCH 5/6] fix bad merge --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aa6260d88..d996afcc0 100644 --- a/pom.xml +++ b/pom.xml @@ -120,7 +120,7 @@ gxcloudstorage-googlecloudstorage gxcloudstorage-azureblob gxcloudstorage-ibmcos - gxcloudstorage-testsgxcloudstorage-tests gxobservability gxcloudstorage-awss3-v2 gxcompress From 8103a7c88e89eb09a851747d7f3ba1a6aec77a32 Mon Sep 17 00:00:00 2001 From: Lucas Lazogue Date: Fri, 23 Jan 2026 12:08:20 -0300 Subject: [PATCH 6/6] Trigger Build