View Javadoc
1   /*
2    * Copyright 2012-2021 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.app.service;
17  
18  import static org.codelibs.core.stream.StreamUtil.split;
19  import static org.codelibs.core.stream.StreamUtil.stream;
20  
21  import java.io.IOException;
22  import java.io.Reader;
23  import java.io.Writer;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.stream.Collectors;
27  
28  import javax.annotation.Resource;
29  
30  import org.apache.logging.log4j.LogManager;
31  import org.apache.logging.log4j.Logger;
32  import org.codelibs.core.beans.util.BeanUtil;
33  import org.codelibs.core.lang.StringUtil;
34  import org.codelibs.fess.Constants;
35  import org.codelibs.fess.app.pager.ElevateWordPager;
36  import org.codelibs.fess.es.client.SearchEngineClient;
37  import org.codelibs.fess.es.config.cbean.ElevateWordCB;
38  import org.codelibs.fess.es.config.exbhv.ElevateWordBhv;
39  import org.codelibs.fess.es.config.exbhv.ElevateWordToLabelBhv;
40  import org.codelibs.fess.es.config.exbhv.LabelTypeBhv;
41  import org.codelibs.fess.es.config.exentity.ElevateWord;
42  import org.codelibs.fess.es.config.exentity.ElevateWordToLabel;
43  import org.codelibs.fess.es.config.exentity.LabelType;
44  import org.codelibs.fess.helper.PermissionHelper;
45  import org.codelibs.fess.mylasta.direction.FessConfig;
46  import org.codelibs.fess.util.ComponentUtil;
47  import org.dbflute.bhv.readable.EntityRowHandler;
48  import org.dbflute.cbean.result.PagingResultBean;
49  import org.dbflute.optional.OptionalEntity;
50  
51  import com.orangesignal.csv.CsvConfig;
52  import com.orangesignal.csv.CsvReader;
53  import com.orangesignal.csv.CsvWriter;
54  
55  public class ElevateWordService {
56  
57      private static final Logger logger = LogManager.getLogger(ElevateWordService.class);
58  
59      @Resource
60      protected ElevateWordToLabelBhv elevateWordToLabelBhv;
61  
62      @Resource
63      protected ElevateWordBhv elevateWordBhv;
64  
65      @Resource
66      protected LabelTypeBhv labelTypeBhv;
67  
68      @Resource
69      protected FessConfig fessConfig;
70  
71      @Resource
72      protected SearchEngineClient searchEngineClient;
73  
74      public List<ElevateWord> getElevateWordList(final ElevateWordPager elevateWordPager) {
75  
76          final PagingResultBean<ElevateWord> elevateWordList = elevateWordBhv.selectPage(cb -> {
77              cb.paging(elevateWordPager.getPageSize(), elevateWordPager.getCurrentPageNumber());
78              setupListCondition(cb, elevateWordPager);
79          });
80  
81          // update pager
82          BeanUtil.copyBeanToBean(elevateWordList, elevateWordPager, option -> option.include(Constants.PAGER_CONVERSION_RULE));
83          elevateWordPager.setPageNumberList(elevateWordList.pageRange(op -> {
84              op.rangeSize(fessConfig.getPagingPageRangeSizeAsInteger());
85          }).createPageNumberList());
86  
87          return elevateWordList;
88      }
89  
90      public OptionalEntity<ElevateWord> getElevateWord(final String id) {
91          return elevateWordBhv.selectByPK(id).map(entity -> {
92  
93              final List<ElevateWordToLabel> wctltmList = elevateWordToLabelBhv.selectList(wctltmCb -> {
94                  wctltmCb.query().setElevateWordId_Equal(entity.getId());
95                  wctltmCb.fetchFirst(fessConfig.getPageLabeltypeMaxFetchSizeAsInteger());
96              });
97              if (!wctltmList.isEmpty()) {
98                  final List<String> labelTypeIds = new ArrayList<>(wctltmList.size());
99                  for (final ElevateWordToLabel mapping : wctltmList) {
100                     labelTypeIds.add(mapping.getLabelTypeId());
101                 }
102                 entity.setLabelTypeIds(labelTypeIds.toArray(new String[labelTypeIds.size()]));
103             }
104             return entity;
105         });
106     }
107 
108     public void store(final ElevateWord elevateWord) {
109         final boolean isNew = elevateWord.getId() == null;
110         final String[] labelTypeIds = elevateWord.getLabelTypeIds();
111 
112         elevateWordBhv.insertOrUpdate(elevateWord, op -> {
113             op.setRefreshPolicy(Constants.TRUE);
114         });
115         final String elevateWordId = elevateWord.getId();
116         if (isNew) {
117             // Insert
118             if (labelTypeIds != null) {
119                 final List<ElevateWordToLabel> wctltmList = new ArrayList<>();
120                 for (final String id : labelTypeIds) {
121                     final ElevateWordToLabel mapping = new ElevateWordToLabel();
122                     mapping.setElevateWordId(elevateWordId);
123                     mapping.setLabelTypeId(id);
124                     wctltmList.add(mapping);
125                 }
126                 elevateWordToLabelBhv.batchInsert(wctltmList, op -> {
127                     op.setRefreshPolicy(Constants.TRUE);
128                 });
129             }
130         } else // Update
131         if (labelTypeIds != null) {
132             final List<ElevateWordToLabel> list = elevateWordToLabelBhv.selectList(wctltmCb -> {
133                 wctltmCb.query().setElevateWordId_Equal(elevateWordId);
134                 wctltmCb.fetchFirst(fessConfig.getPageLabeltypeMaxFetchSizeAsInteger());
135             });
136             final List<ElevateWordToLabel> newList = new ArrayList<>();
137             final List<ElevateWordToLabel> matchedList = new ArrayList<>();
138             for (final String id : labelTypeIds) {
139                 boolean exist = false;
140                 for (final ElevateWordToLabel mapping : list) {
141                     if (mapping.getLabelTypeId().equals(id)) {
142                         exist = true;
143                         matchedList.add(mapping);
144                         break;
145                     }
146                 }
147                 if (!exist) {
148                     // new
149                     final ElevateWordToLabel mapping = new ElevateWordToLabel();
150                     mapping.setElevateWordId(elevateWordId);
151                     mapping.setLabelTypeId(id);
152                     newList.add(mapping);
153                 }
154             }
155             list.removeAll(matchedList);
156             elevateWordToLabelBhv.batchInsert(newList, op -> {
157                 op.setRefreshPolicy(Constants.TRUE);
158             });
159             elevateWordToLabelBhv.batchDelete(list, op -> {
160                 op.setRefreshPolicy(Constants.TRUE);
161             });
162         }
163     }
164 
165     public void delete(final ElevateWord elevateWord) {
166 
167         elevateWordBhv.delete(elevateWord, op -> {
168             op.setRefreshPolicy(Constants.TRUE);
169         });
170 
171     }
172 
173     protected void setupListCondition(final ElevateWordCB cb, final ElevateWordPager elevateWordPager) {
174         if (elevateWordPager.id != null) {
175             cb.query().docMeta().setId_Equal(elevateWordPager.id);
176         }
177         // TODO Long, Integer, String supported only.
178 
179         // setup condition
180         cb.query().addOrderBy_SuggestWord_Asc();
181 
182         // search
183 
184     }
185 
186     public void importCsv(final Reader reader) {
187         final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
188         final CsvConfig cfg = new CsvConfig(',', '"', '"');
189         cfg.setEscapeDisabled(false);
190         cfg.setQuoteDisabled(false);
191         @SuppressWarnings("resource")
192         final CsvReader csvReader = new CsvReader(reader, cfg);
193         try {
194             List<String> list;
195             csvReader.readValues(); // ignore header
196             while ((list = csvReader.readValues()) != null) {
197                 final String suggestWord = getValue(list, 0);
198                 if (StringUtil.isBlank(suggestWord)) {
199                     // skip
200                     continue;
201                 }
202                 try {
203                     final String[] permissions = split(getValue(list, 2), ",").get(stream -> stream.map(permissionHelper::encode)
204                             .filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n]));
205                     final String[] labels = split(getValue(list, 3), ",")
206                             .get(stream -> stream.filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n]));
207                     ElevateWord elevateWord = elevateWordBhv.selectEntity(cb -> {
208                         cb.query().setSuggestWord_Equal(suggestWord);
209                         if (permissions.length > 0) {
210                             cb.query().setPermissions_InScope(stream(permissions).get(stream -> stream.collect(Collectors.toList())));
211                         }
212                     }).orElse(null);
213                     final String reading = getValue(list, 1);
214                     final String boost = getValue(list, 4);
215                     final long now = ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
216                     if (elevateWord == null) {
217                         elevateWord = new ElevateWord();
218                         elevateWord.setSuggestWord(suggestWord);
219                         elevateWord.setReading(reading);
220                         elevateWord.setPermissions(permissions);
221                         elevateWord.setBoost(StringUtil.isBlank(boost) ? 1.0f : Float.parseFloat(boost));
222                         elevateWord.setCreatedBy(Constants.SYSTEM_USER);
223                         elevateWord.setCreatedTime(now);
224                         elevateWordBhv.insert(elevateWord);
225                         final String id = elevateWord.getId();
226                         final List<ElevateWordToLabel> mappingList = stream(labels)
227                                 .get(stream -> stream.map(l -> labelTypeBhv.selectEntity(cb -> cb.query().setValue_Equal(l)).map(e -> {
228                                     final ElevateWordToLabel m = new ElevateWordToLabel();
229                                     m.setElevateWordId(id);
230                                     m.setLabelTypeId(e.getId());
231                                     return m;
232                                 }).orElse(null)).filter(e -> e != null).collect(Collectors.toList()));
233                         if (!mappingList.isEmpty()) {
234                             elevateWordToLabelBhv.batchInsert(mappingList);
235                         }
236                     } else if (StringUtil.isBlank(reading) && StringUtil.isBlank(boost)) {
237                         elevateWordBhv.delete(elevateWord);
238                         final String id = elevateWord.getId();
239                         elevateWordToLabelBhv.queryDelete(cb -> cb.query().setElevateWordId_Equal(id));
240                     } else {
241                         elevateWord.setReading(reading);
242                         elevateWord.setPermissions(permissions);
243                         elevateWord.setBoost(StringUtil.isBlank(boost) ? 1.0f : Float.parseFloat(boost));
244                         elevateWord.setUpdatedBy(Constants.SYSTEM_USER);
245                         elevateWord.setUpdatedTime(now);
246                         elevateWordBhv.update(elevateWord);
247                         final String id = elevateWord.getId();
248                         final List<ElevateWordToLabel> mappingList = stream(labels)
249                                 .get(stream -> stream.map(l -> labelTypeBhv.selectEntity(cb -> cb.query().setValue_Equal(l)).map(e -> {
250                                     final List<ElevateWordToLabel> mList = elevateWordToLabelBhv.selectList(cb -> {
251                                         cb.query().setElevateWordId_Equal(id);
252                                         cb.query().setLabelTypeId_Equal(e.getId());
253                                     });
254                                     if (!mList.isEmpty()) {
255                                         return null;
256                                     }
257                                     final ElevateWordToLabel m = new ElevateWordToLabel();
258                                     m.setElevateWordId(id);
259                                     m.setLabelTypeId(e.getId());
260                                     return m;
261                                 }).orElse(null)).filter(e -> e != null).collect(Collectors.toList()));
262                         if (!mappingList.isEmpty()) {
263                             elevateWordToLabelBhv.batchInsert(mappingList);
264                         }
265                     }
266                 } catch (final Exception e) {
267                     logger.warn("Failed to read a sugget elevate word: {}", list, e);
268                 }
269             }
270             elevateWordBhv.refresh();
271         } catch (final IOException e) {
272             logger.warn("Failed to read a sugget elevate word.", e);
273         }
274     }
275 
276     public void exportCsv(final Writer writer) {
277         final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
278         final CsvConfig cfg = new CsvConfig(',', '"', '"');
279         cfg.setEscapeDisabled(false);
280         cfg.setQuoteDisabled(false);
281         @SuppressWarnings("resource")
282         final CsvWriter csvWriter = new CsvWriter(writer, cfg);
283         try {
284             final List<String> list = new ArrayList<>();
285             list.add("SuggestWord");
286             list.add("Reading");
287             list.add("Permissions");
288             list.add("Labels");
289             list.add("Boost");
290             csvWriter.writeValues(list);
291 
292             elevateWordBhv.selectCursor(cb -> cb.query().matchAll(), new EntityRowHandler<ElevateWord>() {
293                 @Override
294                 public void handle(final ElevateWord entity) {
295                     final List<String> list = new ArrayList<>();
296                     final String permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
297                             .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
298                     final String labels = elevateWordToLabelBhv
299                             .selectList(cb -> cb.query().setElevateWordId_Equal(entity.getId())).stream().map(e -> labelTypeBhv
300                                     .selectByPK(e.getLabelTypeId()).map(LabelType::getValue).filter(StringUtil::isNotBlank).orElse(null))
301                             .distinct().sorted().collect(Collectors.joining(","));
302                     addToList(list, entity.getSuggestWord());
303                     addToList(list, entity.getReading());
304                     addToList(list, permissions);
305                     addToList(list, labels);
306                     addToList(list, entity.getBoost());
307                     try {
308                         csvWriter.writeValues(list);
309                     } catch (final IOException e) {
310                         logger.warn("Failed to write a sugget elevate word: {}", entity, e);
311                     }
312                 }
313 
314                 private void addToList(final List<String> list, final Object value) {
315                     if (value == null) {
316                         list.add(StringUtil.EMPTY);
317                     } else {
318                         list.add(value.toString());
319                     }
320                 }
321             });
322 
323             csvWriter.flush();
324         } catch (final IOException e) {
325             logger.warn("Failed to write a sugget elevate word.", e);
326         }
327     }
328 
329     static String getValue(final List<String> list, final int index) {
330         if (index >= list.size()) {
331             return StringUtil.EMPTY;
332         }
333         String item = list.get(index).trim();
334         if (StringUtil.isBlank(item)) {
335             return StringUtil.EMPTY;
336         }
337         if (item.length() > 1 && item.charAt(0) == '"' && item.charAt(item.length() - 1) == '"') {
338             item = item.substring(1, item.length() - 1);
339         }
340         return item;
341     }
342 
343 }