1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.dict;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.text.SimpleDateFormat;
21 import java.util.ArrayList;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.logging.log4j.LogManager;
27 import org.apache.logging.log4j.Logger;
28 import org.codelibs.core.io.FileUtil;
29 import org.codelibs.curl.CurlResponse;
30 import org.codelibs.fess.Constants;
31 import org.codelibs.fess.util.ComponentUtil;
32 import org.codelibs.opensearch.runner.net.OpenSearchCurl;
33 import org.dbflute.optional.OptionalEntity;
34
35 import jakarta.annotation.PostConstruct;
36
37
38
39
40
41
42
43
44
45 public class DictionaryManager {
46 private static final Logger logger = LogManager.getLogger(DictionaryManager.class);
47
48
49 protected List<DictionaryCreator> creatorList = new ArrayList<>();
50
51
52
53
54
55 public DictionaryManager() {
56
57 }
58
59
60
61
62
63 @PostConstruct
64 public void init() {
65 if (logger.isDebugEnabled()) {
66 logger.debug("Initializing {}", this.getClass().getSimpleName());
67 }
68 creatorList.forEach(creator -> {
69 creator.setDictionaryManager(this);
70 });
71 }
72
73
74
75
76
77
78
79
80
81
82 public DictionaryFile<? extends DictionaryItem>[] getDictionaryFiles() {
83 try (CurlResponse response = ComponentUtil.getCurlHelper()
84 .get("/_configsync/file")
85 .param("fields", "path,@timestamp")
86 .param("size", ComponentUtil.getFessConfig().getPageDictionaryMaxFetchSize())
87 .execute()) {
88 final Map<String, Object> contentMap = response.getContent(OpenSearchCurl.jsonParser());
89 @SuppressWarnings("unchecked")
90 final List<Map<String, Object>> fileList = (List<Map<String, Object>>) contentMap.get("file");
91 return fileList.stream().map(fileMap -> {
92 try {
93 final String path = fileMap.get("path").toString();
94 final Date timestamp =
95 new SimpleDateFormat(Constants.DATE_FORMAT_ISO_8601_EXTEND_UTC).parse(fileMap.get("@timestamp").toString());
96 for (final DictionaryCreator creator : creatorList) {
97 final DictionaryFile<? extends DictionaryItem> file = creator.create(path, timestamp);
98 if (file != null) {
99 return file;
100 }
101 }
102 } catch (final Exception e) {
103 final String filePath = fileMap.get("path") != null ? fileMap.get("path").toString() : "unknown";
104 final String fileTimestamp = fileMap.get("@timestamp") != null ? fileMap.get("@timestamp").toString() : "unknown";
105 logger.warn("Failed to load dictionary file: path={}, timestamp={}, error={}", filePath, fileTimestamp, e.getMessage(),
106 e);
107 }
108 return null;
109 }).filter(file -> file != null).toArray(n -> new DictionaryFile<?>[n]);
110 } catch (final IOException e) {
111 throw new DictionaryException("Failed to access dictionaries", e);
112 }
113 }
114
115
116
117
118
119
120
121 public OptionalEntity<DictionaryFile<? extends DictionaryItem>> getDictionaryFile(final String id) {
122 for (final DictionaryFile<? extends DictionaryItem> dictFile : getDictionaryFiles()) {
123 if (dictFile.getId().equals(id)) {
124 return OptionalEntity.of(dictFile);
125 }
126 }
127 return OptionalEntity.empty();
128 }
129
130
131
132
133
134
135
136
137
138
139
140 public void store(final DictionaryFile<? extends DictionaryItem> dictFile, final File file) {
141 getDictionaryFile(dictFile.getId()).ifPresent(currentFile -> {
142 if (currentFile.getTimestamp().getTime() > dictFile.getTimestamp().getTime()) {
143 throw new DictionaryException(dictFile.getPath() + " was updated.");
144 }
145
146
147 try (CurlResponse response = ComponentUtil.getCurlHelper()
148 .post("/_configsync/file")
149 .param("path", dictFile.getPath())
150 .body(FileUtil.readUTF8(file))
151 .execute()) {
152 final Map<String, Object> contentMap = response.getContent(OpenSearchCurl.jsonParser());
153 if (!Constants.TRUE.equalsIgnoreCase(contentMap.get("acknowledged").toString())) {
154 throw new DictionaryException("Failed to update " + dictFile.getPath());
155 }
156 } catch (final IOException e) {
157 throw new DictionaryException("Failed to update " + dictFile.getPath(), e);
158 }
159
160 }).orElse(() -> {
161 throw new DictionaryException(dictFile.getPath() + " does not exist.");
162 });
163 }
164
165
166
167
168
169
170
171
172 public CurlResponse getContentResponse(final DictionaryFile<? extends DictionaryItem> dictFile) {
173 return ComponentUtil.getCurlHelper().get("/_configsync/file").param("path", dictFile.getPath()).execute();
174 }
175
176
177
178
179
180
181
182
183 public void addCreator(final DictionaryCreator creator) {
184 creatorList.add(creator);
185 }
186
187 }