View Javadoc
1   /*
2    * Copyright 2012-2025 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.util;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.IOException;
20  import java.io.OutputStream;
21  import java.util.function.Function;
22  
23  import org.apache.logging.log4j.LogManager;
24  import org.apache.logging.log4j.Logger;
25  import org.codelibs.fess.opensearch.client.SearchEngineClient;
26  import org.lastaflute.di.exception.IORuntimeException;
27  import org.opensearch.core.xcontent.MediaType;
28  import org.opensearch.core.xcontent.ToXContent;
29  import org.opensearch.core.xcontent.XContentBuilder;
30  import org.opensearch.core.xcontent.XContentHelper;
31  import org.opensearch.search.SearchHit;
32  
33  /**
34   * Utility class for search engine operations and content formatting.
35   * Provides helper methods for working with XContent builders, scrolling through search results,
36   * and converting XContent objects to different output formats.
37   */
38  public final class SearchEngineUtil {
39  
40      private static final Logger logger = LogManager.getLogger(SearchEngineUtil.class);
41  
42      /**
43       * Private constructor to prevent instantiation of this utility class.
44       */
45      private SearchEngineUtil() {
46      }
47  
48      /**
49       * Creates an OutputStream from an XContentBuilder using the provided callback function.
50       *
51       * @param func the callback function to build XContent
52       * @param mediaType the media type for the content builder
53       * @return an OutputStream containing the built content, or an empty ByteArrayOutputStream if an error occurs
54       */
55      public static OutputStream getXContentBuilderOutputStream(final XContentBuilderCallback func, final MediaType mediaType) {
56          try (final XContentBuilder builder = func.apply(mediaType.contentBuilder(), ToXContent.EMPTY_PARAMS)) {
57              builder.flush();
58              return builder.getOutputStream();
59          } catch (final IOException e) {
60              if (logger.isDebugEnabled()) {
61                  logger.debug("Failed to print the output.", e);
62              }
63              return new ByteArrayOutputStream();
64          }
65      }
66  
67      /**
68       * Creates an OutputStream from a ToXContent object with the specified media type.
69       *
70       * @param xContent the content object to convert
71       * @param mediaType the media type for the output
72       * @return an OutputStream containing the converted content
73       */
74      public static OutputStream getXContentOutputStream(final ToXContent xContent, final MediaType mediaType) {
75          return getXContentBuilderOutputStream((builder, params) -> xContent.toXContent(builder, params), mediaType);
76      }
77  
78      /**
79       * Scrolls through all documents in the specified index and applies the callback function to each hit.
80       *
81       * @param index the name of the index to scroll through
82       * @param callback the function to apply to each search hit, returning true to continue or false to stop
83       * @return the number of documents processed
84       */
85      public static long scroll(final String index, final Function<SearchHit, Boolean> callback) {
86          final SearchEngineClient client = ComponentUtil.getSearchEngineClient();
87          return client.<SearchHit> scrollSearch(index, searchRequestBuilder -> true, (searchResponse, hit) -> hit,
88                  hit -> callback.apply(hit));
89      }
90  
91      /**
92       * Converts a ToXContent object to its string representation using the specified media type.
93       *
94       * @param xContent the content object to convert
95       * @param mediaType the media type for the conversion
96       * @return the string representation of the content
97       * @throws IORuntimeException if an IO error occurs during conversion
98       */
99      public static String getXContentString(final ToXContent xContent, final MediaType mediaType) {
100         try {
101             return XContentHelper.toXContent(xContent, mediaType, ToXContent.EMPTY_PARAMS, false).utf8ToString();
102         } catch (final IOException e) {
103             throw new IORuntimeException(e);
104         }
105     }
106 
107     /**
108      * Functional interface for building XContent with custom logic.
109      * Allows clients to provide custom content building implementations.
110      */
111     public interface XContentBuilderCallback {
112         /**
113          * Applies custom logic to build XContent using the provided builder and parameters.
114          *
115          * @param builder the XContentBuilder to use for building content
116          * @param params the parameters to use during content building
117          * @return the modified XContentBuilder
118          * @throws IOException if an IO error occurs during building
119          */
120         XContentBuilder apply(XContentBuilder builder, ToXContent.Params params) throws IOException;
121     }
122 
123 }