1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.dict.protwords;
17
18 import java.io.BufferedInputStream;
19 import java.io.BufferedReader;
20 import java.io.BufferedWriter;
21 import java.io.Closeable;
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.OutputStreamWriter;
28 import java.io.Writer;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Date;
32 import java.util.List;
33
34 import org.apache.commons.io.IOUtils;
35 import org.codelibs.core.lang.StringUtil;
36 import org.codelibs.fess.Constants;
37 import org.codelibs.fess.dict.DictionaryException;
38 import org.codelibs.fess.dict.DictionaryFile;
39 import org.dbflute.optional.OptionalEntity;
40
41 public class ProtwordsFile extends DictionaryFile<ProtwordsItem> {
42 private static final String PROTWORDS = "protwords";
43
44 List<ProtwordsItem> protwordsItemList;
45
46 public ProtwordsFile(final String id, final String path, final Date timestamp) {
47 super(id, path, timestamp);
48 }
49
50 @Override
51 public String getType() {
52 return PROTWORDS;
53 }
54
55 @Override
56 public String getPath() {
57 return path;
58 }
59
60 @Override
61 public synchronized OptionalEntity<ProtwordsItem> get(final long id) {
62 if (protwordsItemList == null) {
63 reload(null, null);
64 }
65
66 for (final ProtwordsItem ProtwordsItem : protwordsItemList) {
67 if (id == ProtwordsItem.getId()) {
68 return OptionalEntity.of(ProtwordsItem);
69 }
70 }
71 return OptionalEntity.empty();
72 }
73
74 @Override
75 public synchronized PagingList<ProtwordsItem> selectList(final int offset, final int size) {
76 if (protwordsItemList == null) {
77 reload(null, null);
78 }
79
80 if (offset >= protwordsItemList.size() || offset < 0) {
81 return new PagingList<>(Collections.<ProtwordsItem> emptyList(), offset, size, protwordsItemList.size());
82 }
83
84 int toIndex = offset + size;
85 if (toIndex > protwordsItemList.size()) {
86 toIndex = protwordsItemList.size();
87 }
88
89 return new PagingList<>(protwordsItemList.subList(offset, toIndex), offset, size, protwordsItemList.size());
90 }
91
92 @Override
93 public synchronized void insert(final ProtwordsItem item) {
94 try (SynonymUpdater updater = new SynonymUpdater(item)) {
95 reload(updater, null);
96 }
97 }
98
99 @Override
100 public synchronized void update(final ProtwordsItem item) {
101 try (SynonymUpdater updater = new SynonymUpdater(item)) {
102 reload(updater, null);
103 }
104 }
105
106 @Override
107 public synchronized void delete(final ProtwordsItem item) {
108 final ProtwordsItem ProtwordsItem = item;
109 ProtwordsItem.setNewInput(StringUtil.EMPTY);
110 try (SynonymUpdater updater = new SynonymUpdater(item)) {
111 reload(updater, null);
112 }
113 }
114
115 protected void reload(final SynonymUpdater updater, final InputStream in) {
116 final List<ProtwordsItem> itemList = new ArrayList<>();
117 try (BufferedReader reader =
118 new BufferedReader(new InputStreamReader(in != null ? in : dictionaryManager.getContentInputStream(this), Constants.UTF_8))) {
119 long id = 0;
120 String line = null;
121 while ((line = reader.readLine()) != null) {
122 if (line.length() == 0 || line.charAt(0) == '#') {
123 if (updater != null) {
124 updater.write(line);
125 }
126 continue;
127 }
128
129 final String inputStrings = line;
130 String input = null;
131 if (inputStrings != null) {
132 input = unescape(inputStrings);
133 }
134
135 if (input.length() > 0) {
136 id++;
137 final ProtwordsItem item = new ProtwordsItem(id, input);
138 if (updater != null) {
139 final ProtwordsItem newItem = updater.write(item);
140 if (newItem != null) {
141 itemList.add(newItem);
142 } else {
143 id--;
144 }
145 } else {
146 itemList.add(item);
147 }
148 }
149 }
150 if (updater != null) {
151 final ProtwordsItem item = updater.commit();
152 if (item != null) {
153 itemList.add(item);
154 }
155 }
156 protwordsItemList = itemList;
157 } catch (final IOException e) {
158 throw new DictionaryException("Failed to parse " + path, e);
159 }
160 }
161
162 private String unescape(final String s) {
163 if (s.indexOf('\\') >= 0) {
164 final StringBuilder sb = new StringBuilder();
165 for (int i = 0; i < s.length(); i++) {
166 final char ch = s.charAt(i);
167 if (ch == '\\' && i < s.length() - 1) {
168 sb.append(s.charAt(++i));
169 } else {
170 sb.append(ch);
171 }
172 }
173 return sb.toString();
174 }
175 return s;
176 }
177
178 public String getSimpleName() {
179 return new File(path).getName();
180 }
181
182 public InputStream getInputStream() throws IOException {
183 return new BufferedInputStream(dictionaryManager.getContentInputStream(this));
184 }
185
186 public synchronized void update(final InputStream in) throws IOException {
187 try (SynonymUpdater updater = new SynonymUpdater(null)) {
188 reload(updater, in);
189 }
190 }
191
192 @Override
193 public String toString() {
194 return "SynonymFile [path=" + path + ", srotwordsItemList=" + protwordsItemList + ", id=" + id + "]";
195 }
196
197 protected class SynonymUpdater implements Closeable {
198
199 protected boolean isCommit = false;
200
201 protected File newFile;
202
203 protected Writer writer;
204
205 protected ProtwordsItem item;
206
207 protected SynonymUpdater(final ProtwordsItem newItem) {
208 try {
209 newFile = File.createTempFile(PROTWORDS, ".txt");
210 writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), Constants.UTF_8));
211 } catch (final IOException e) {
212 if (newFile != null) {
213 newFile.delete();
214 }
215 throw new DictionaryException("Failed to write a userDict file.", e);
216 }
217 item = newItem;
218 }
219
220 public ProtwordsItem write(final ProtwordsItem oldItem) {
221 try {
222 if (item != null && item.getId() == oldItem.getId() && item.isUpdated()) {
223 if (item.equals(oldItem)) {
224 try {
225 if (!item.isDeleted()) {
226
227 writer.write(item.toLineString());
228 writer.write(Constants.LINE_SEPARATOR);
229 return new ProtwordsItem(item.getId(), item.getNewInput());
230 } else {
231 return null;
232 }
233 } finally {
234 item.setNewInput(null);
235 }
236 } else {
237 throw new DictionaryException("Protwords file was updated: old=" + oldItem + " : new=" + item);
238 }
239 } else {
240 writer.write(oldItem.toLineString());
241 writer.write(Constants.LINE_SEPARATOR);
242 return oldItem;
243 }
244 } catch (final IOException e) {
245 throw new DictionaryException("Failed to write: " + oldItem + " -> " + item, e);
246 }
247 }
248
249 public void write(final String line) {
250 try {
251 writer.write(line);
252 writer.write(Constants.LINE_SEPARATOR);
253 } catch (final IOException e) {
254 throw new DictionaryException("Failed to write: " + line, e);
255 }
256 }
257
258 public ProtwordsItem commit() {
259 isCommit = true;
260 if (item != null && item.isUpdated()) {
261 try {
262 writer.write(item.toLineString());
263 writer.write(Constants.LINE_SEPARATOR);
264 return item;
265 } catch (final IOException e) {
266 throw new DictionaryException("Failed to write: " + item, e);
267 }
268 }
269 return null;
270 }
271
272 @Override
273 public void close() {
274 try {
275 writer.flush();
276 } catch (final IOException e) {
277
278 }
279 IOUtils.closeQuietly(writer);
280
281 if (isCommit) {
282 try {
283 dictionaryManager.store(ProtwordsFile.this, newFile);
284 } finally {
285 newFile.delete();
286 }
287 } else {
288 newFile.delete();
289 }
290 }
291 }
292 }