1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.service;
17
18 import java.io.IOException;
19 import java.io.Reader;
20 import java.io.Writer;
21 import java.text.DateFormat;
22 import java.text.SimpleDateFormat;
23 import java.time.LocalDateTime;
24 import java.time.format.DateTimeFormatter;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.stream.Collectors;
30
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
33 import org.codelibs.core.CoreLibConstants;
34 import org.codelibs.core.beans.util.BeanUtil;
35 import org.codelibs.core.lang.StringUtil;
36 import org.codelibs.fess.Constants;
37 import org.codelibs.fess.app.pager.CrawlingInfoPager;
38 import org.codelibs.fess.exception.FessSystemException;
39 import org.codelibs.fess.mylasta.direction.FessConfig;
40 import org.codelibs.fess.opensearch.config.cbean.CrawlingInfoCB;
41 import org.codelibs.fess.opensearch.config.exbhv.CrawlingInfoBhv;
42 import org.codelibs.fess.opensearch.config.exbhv.CrawlingInfoParamBhv;
43 import org.codelibs.fess.opensearch.config.exentity.CrawlingInfo;
44 import org.codelibs.fess.opensearch.config.exentity.CrawlingInfoParam;
45 import org.codelibs.fess.util.ComponentUtil;
46 import org.dbflute.bhv.readable.EntityRowHandler;
47 import org.dbflute.cbean.result.ListResultBean;
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 import jakarta.annotation.Resource;
56
57
58
59
60
61
62 public class CrawlingInfoService {
63
64 private static final Logger logger = LogManager.getLogger(CrawlingInfoService.class);
65
66
67
68
69 public CrawlingInfoService() {
70 }
71
72
73
74
75
76 @Resource
77 protected CrawlingInfoParamBhv crawlingInfoParamBhv;
78
79
80
81
82
83 @Resource
84 protected CrawlingInfoBhv crawlingInfoBhv;
85
86
87
88
89
90 @Resource
91 protected FessConfig fessConfig;
92
93
94
95
96
97
98
99
100
101 public List<CrawlingInfo> getCrawlingInfoList(final CrawlingInfoPager crawlingInfoPager) {
102
103 final PagingResultBean<CrawlingInfo> crawlingInfoList = crawlingInfoBhv.selectPage(cb -> {
104 cb.paging(crawlingInfoPager.getPageSize(), crawlingInfoPager.getCurrentPageNumber());
105 setupListCondition(cb, crawlingInfoPager);
106 });
107
108
109 BeanUtil.copyBeanToBean(crawlingInfoList, crawlingInfoPager, option -> option.include(Constants.PAGER_CONVERSION_RULE));
110 crawlingInfoPager.setPageNumberList(
111 crawlingInfoList.pageRange(op -> op.rangeSize(fessConfig.getPagingPageRangeSizeAsInteger())).createPageNumberList());
112
113 return crawlingInfoList;
114 }
115
116
117
118
119
120
121
122 public OptionalEntity<CrawlingInfo> getCrawlingInfo(final String id) {
123 return crawlingInfoBhv.selectByPK(id);
124 }
125
126
127
128
129
130
131
132
133
134 public void store(final CrawlingInfo crawlingInfo) {
135 setupStoreCondition(crawlingInfo);
136
137 crawlingInfoBhv.insertOrUpdate(crawlingInfo, op -> op.setRefreshPolicy(Constants.TRUE));
138
139 }
140
141
142
143
144
145
146
147
148 public void delete(final CrawlingInfo crawlingInfo) {
149 setupDeleteCondition(crawlingInfo);
150
151 crawlingInfoBhv.delete(crawlingInfo, op -> op.setRefreshPolicy(Constants.TRUE));
152
153 }
154
155
156
157
158
159
160
161
162
163 protected void setupListCondition(final CrawlingInfoCB cb, final CrawlingInfoPager crawlingInfoPager) {
164 if (crawlingInfoPager.id != null) {
165 cb.query().docMeta().setId_Equal(crawlingInfoPager.id);
166 }
167
168 if (StringUtil.isNotBlank(crawlingInfoPager.sessionId)) {
169 cb.query().setSessionId_Match(crawlingInfoPager.sessionId);
170 }
171 cb.query().addOrderBy_CreatedTime_Desc();
172 }
173
174
175
176
177
178
179
180
181 protected void setupStoreCondition(final CrawlingInfo crawlingInfo) {
182 if (crawlingInfo == null) {
183 throw new FessSystemException("Crawling Session is null.");
184 }
185 final long now = ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
186 if (crawlingInfo.getCreatedTime() == null) {
187 crawlingInfo.setCreatedTime(now);
188 }
189 }
190
191
192
193
194
195
196
197 protected void setupDeleteCondition(final CrawlingInfo crawlingInfo) {
198 crawlingInfoParamBhv.queryDelete(cb -> cb.query().setCrawlingInfoId_Equal(crawlingInfo.getId()));
199 }
200
201
202
203
204
205
206
207
208
209
210 public void deleteSessionIdsBefore(final String activeSessionId, final String name, final long date) {
211 final List<CrawlingInfo> crawlingInfoList = crawlingInfoBhv.selectList(cb -> {
212 cb.query().filtered((cq, cf) -> {
213 cq.setExpiredTime_LessEqual(date);
214 if (StringUtil.isNotBlank(name)) {
215 cf.setName_Equal(name);
216 }
217 if (activeSessionId != null) {
218 cf.setSessionId_NotEqual(activeSessionId);
219 }
220
221 });
222
223 cb.fetchFirst(fessConfig.getPageCrawlingInfoMaxFetchSizeAsInteger());
224 cb.specify().columnId();
225 });
226 if (!crawlingInfoList.isEmpty()) {
227 final List<String> crawlingInfoIdList = new ArrayList<>();
228 for (final CrawlingInfo cs : crawlingInfoList) {
229 crawlingInfoIdList.add(cs.getId());
230 }
231 crawlingInfoParamBhv.queryDelete(cb2 -> cb2.query().setCrawlingInfoId_InScope(crawlingInfoIdList));
232 crawlingInfoBhv.batchDelete(crawlingInfoList, op -> op.setRefreshPolicy(Constants.TRUE));
233 }
234 }
235
236
237
238
239
240
241
242
243
244 public void storeInfo(final List<CrawlingInfoParam> crawlingInfoParamList) {
245 if (crawlingInfoParamList == null) {
246 throw new FessSystemException("Crawling Session Info is null.");
247 }
248
249 final long now = ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
250 for (final CrawlingInfoParam crawlingInfoParam : crawlingInfoParamList) {
251 if (crawlingInfoParam.getCreatedTime() == null) {
252 crawlingInfoParam.setCreatedTime(now);
253 }
254 }
255 crawlingInfoParamBhv.batchInsert(crawlingInfoParamList, op -> op.setRefreshPolicy(Constants.TRUE));
256 }
257
258
259
260
261
262
263
264
265 public List<CrawlingInfoParam> getCrawlingInfoParamList(final String id) {
266 return crawlingInfoParamBhv.selectList(cb -> {
267 cb.query().setCrawlingInfoId_Equal(id);
268 cb.query().addOrderBy_CreatedTime_Asc();
269 cb.fetchFirst(fessConfig.getPageCrawlingInfoParamMaxFetchSizeAsInteger());
270 });
271 }
272
273
274
275
276
277
278
279
280 public List<CrawlingInfoParam> getLastCrawlingInfoParamList(final String sessionId) {
281 final CrawlingInfo crawlingInfo = getLast(sessionId);
282 if (crawlingInfo == null) {
283 return Collections.emptyList();
284 }
285 final FessConfig fessConfig = ComponentUtil.getFessConfig();
286 return crawlingInfoParamBhv.selectList(cb -> {
287 cb.query().setCrawlingInfoId_Equal(crawlingInfo.getId());
288 cb.query().addOrderBy_CreatedTime_Asc();
289 cb.paging(fessConfig.getPageCrawlingInfoParamMaxFetchSizeAsInteger(), 1);
290 });
291 }
292
293
294
295
296
297
298
299 public void deleteOldSessions(final Set<String> activeSessionId) {
300 final List<CrawlingInfo> activeSessionList =
301 activeSessionId.isEmpty() ? Collections.emptyList() : crawlingInfoBhv.selectList(cb -> {
302 cb.query().setSessionId_InScope(activeSessionId);
303 cb.fetchFirst(fessConfig.getPageCrawlingInfoMaxFetchSizeAsInteger());
304 cb.specify().columnId();
305 });
306 final List<String> idList = activeSessionList.stream().map(CrawlingInfo::getId).collect(Collectors.toList());
307 crawlingInfoParamBhv.queryDelete(cb1 -> cb1.query().filtered((cq, cf) -> {
308 cq.matchAll();
309 if (!idList.isEmpty()) {
310 cf.not(subCf -> subCf.setCrawlingInfoId_InScope(idList));
311 }
312 }));
313 crawlingInfoBhv.queryDelete(cb2 -> cb2.query().filtered((cq, cf) -> {
314 cq.matchAll();
315 if (!idList.isEmpty()) {
316 cf.not(subCf -> subCf.setId_InScope(idList));
317 }
318 }));
319 }
320
321
322
323
324
325
326
327
328 public void importCsv(final Reader reader) {
329 @SuppressWarnings("resource")
330 final CsvReader csvReader = new CsvReader(reader, new CsvConfig());
331 final DateFormat formatter = new SimpleDateFormat(CoreLibConstants.DATE_FORMAT_ISO_8601_EXTEND);
332 try {
333 List<String> list;
334 csvReader.readValues();
335 while ((list = csvReader.readValues()) != null) {
336 try {
337 final String sessionId = list.get(0);
338 CrawlingInfo crawlingInfo = crawlingInfoBhv.selectEntity(cb -> {
339 cb.query().setSessionId_Equal(sessionId);
340 cb.specify().columnSessionId();
341 }).orElse(null);
342 if (crawlingInfo == null) {
343 crawlingInfo = new CrawlingInfo();
344 crawlingInfo.setSessionId(list.get(0));
345 crawlingInfo.setCreatedTime(formatter.parse(list.get(1)).getTime());
346 crawlingInfoBhv.insert(crawlingInfo, op -> op.setRefreshPolicy(Constants.TRUE));
347 }
348
349 final CrawlingInfoParam entity = new CrawlingInfoParam();
350 entity.setCrawlingInfoId(crawlingInfo.getId());
351 entity.setKey(list.get(2));
352 entity.setValue(list.get(3));
353 entity.setCreatedTime(formatter.parse(list.get(4)).getTime());
354 crawlingInfoParamBhv.insert(entity, op -> op.setRefreshPolicy(Constants.TRUE));
355 } catch (final Exception e) {
356 logger.warn("Failed to read a click log: {}", list, e);
357 }
358 }
359 } catch (final IOException e) {
360 logger.warn("Failed to read a click log.", e);
361 }
362 }
363
364
365
366
367
368
369
370
371 public void exportCsv(final Writer writer) {
372 final CsvConfig cfg = new CsvConfig(',', '"', '"');
373 cfg.setEscapeDisabled(false);
374 cfg.setQuoteDisabled(false);
375 @SuppressWarnings("resource")
376 final CsvWriter csvWriter = new CsvWriter(writer, cfg);
377 try {
378 final List<String> list = new ArrayList<>();
379 list.add("SessionId");
380 list.add("SessionCreatedTime");
381 list.add("Key");
382 list.add("Value");
383 list.add("CreatedTime");
384 csvWriter.writeValues(list);
385 final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(CoreLibConstants.DATE_FORMAT_ISO_8601_EXTEND);
386 crawlingInfoParamBhv.selectCursor(cb -> cb.query().matchAll(), new EntityRowHandler<CrawlingInfoParam>() {
387 @Override
388 public void handle(final CrawlingInfoParam entity) {
389 final List<String> list = new ArrayList<>();
390 entity.getCrawlingInfo().ifPresent(crawlingInfo -> {
391 addToList(list, crawlingInfo.getSessionId());
392 addToList(list, crawlingInfo.getCreatedTime());
393 });
394
395 if (!entity.getCrawlingInfo().isPresent()) {
396 addToList(list, "");
397 addToList(list, "");
398 }
399 addToList(list, entity.getKey());
400 addToList(list, entity.getValue());
401 addToList(list, entity.getCreatedTime());
402 try {
403 csvWriter.writeValues(list);
404 } catch (final IOException e) {
405 logger.warn("Failed to write a crawling session info: {}", entity, e);
406 }
407 }
408
409 private void addToList(final List<String> list, final Object value) {
410 if (value == null) {
411 list.add(StringUtil.EMPTY);
412 } else if (value instanceof LocalDateTime) {
413 list.add(((LocalDateTime) value).format(formatter));
414 } else {
415 list.add(value.toString());
416 }
417 }
418 });
419 csvWriter.flush();
420 } catch (final IOException e) {
421 logger.warn("Failed to write a crawling session info.", e);
422 }
423 }
424
425
426
427
428
429
430
431 public void deleteBefore(final long date) {
432 crawlingInfoBhv.selectBulk(cb -> cb.query().setExpiredTime_LessThan(date), list -> {
433 final List<String> idList = list.stream().map(CrawlingInfo::getId).collect(Collectors.toList());
434 crawlingInfoParamBhv.queryDelete(cb1 -> cb1.query().setCrawlingInfoId_InScope(idList));
435 crawlingInfoBhv.queryDelete(cb2 -> cb2.query().setExpiredTime_LessThan(date));
436 });
437 }
438
439
440
441
442
443
444
445
446 public CrawlingInfo getLast(final String sessionId) {
447 final ListResultBean<CrawlingInfo> list = crawlingInfoBhv.selectList(cb -> {
448 cb.query().setSessionId_Equal(sessionId);
449 cb.query().addOrderBy_CreatedTime_Desc();
450 cb.fetchFirst(1);
451 });
452 if (list.isEmpty()) {
453 return null;
454 }
455 return list.get(0);
456 }
457
458 }