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.dict;
17  
18  import java.io.BufferedInputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Date;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.ListIterator;
27  
28  import org.codelibs.curl.CurlResponse;
29  import org.dbflute.optional.OptionalEntity;
30  import org.lastaflute.web.servlet.request.stream.WrittenStreamOut;
31  
32  /**
33   * Abstract base class for dictionary files that manage dictionary items.
34   * A dictionary file represents a collection of dictionary items with
35   * CRUD operations and pagination support.
36   *
37   * @param <T> the type of dictionary items managed by this file
38   */
39  public abstract class DictionaryFile<T extends DictionaryItem> {
40      /** The dictionary manager responsible for this file. */
41      protected DictionaryManager dictionaryManager;
42  
43      /** The unique identifier for this dictionary file. */
44      protected String id;
45  
46      /** The file path of this dictionary. */
47      protected String path;
48  
49      /** The timestamp when this dictionary file was created or last modified. */
50      protected Date timestamp;
51  
52      /**
53       * Creates a new DictionaryFile with the specified parameters.
54       *
55       * @param id the unique identifier for this dictionary file
56       * @param path the file path of this dictionary
57       * @param timestamp the timestamp of the dictionary file
58       */
59      protected DictionaryFile(final String id, final String path, final Date timestamp) {
60          this.id = id;
61          this.path = path;
62          this.timestamp = timestamp;
63      }
64  
65      /**
66       * Returns the unique identifier of this dictionary file.
67       *
68       * @return the dictionary file ID
69       */
70      public String getId() {
71          return id;
72      }
73  
74      /**
75       * Gets the file path of this dictionary.
76       *
77       * @return the file path
78       */
79      public String getPath() {
80          return path;
81      }
82  
83      /**
84       * Returns the timestamp of this dictionary file.
85       *
86       * @return the timestamp when this dictionary was created or last modified
87       */
88      public Date getTimestamp() {
89          return timestamp;
90      }
91  
92      /**
93       * Sets the dictionary manager for this file and returns this instance.
94       *
95       * @param dictionaryManager the dictionary manager to set
96       * @return this dictionary file instance for method chaining
97       */
98      public DictionaryFile<T> manager(final DictionaryManager dictionaryManager) {
99          this.dictionaryManager = dictionaryManager;
100         return this;
101     }
102 
103     /**
104      * Writes the content of this dictionary file to the provided output stream.
105      *
106      * @param out the output stream to write to
107      * @throws IOException if an I/O error occurs during writing
108      */
109     public void writeOut(final WrittenStreamOut out) throws IOException {
110         try (final CurlResponse curlResponse = dictionaryManager.getContentResponse(this);
111                 final InputStream inputStream = new BufferedInputStream(curlResponse.getContentAsStream())) {
112             out.write(inputStream);
113         }
114     }
115 
116     /**
117      * Gets the type identifier for this dictionary file.
118      *
119      * @return the dictionary type
120      */
121     public abstract String getType();
122 
123     /**
124      * Retrieves a paginated list of dictionary items.
125      *
126      * @param offset the starting offset for pagination
127      * @param size the number of items to retrieve
128      * @return a paginated list of dictionary items
129      */
130     public abstract PagingList<T> selectList(int offset, int size);
131 
132     /**
133      * Retrieves a dictionary item by its ID.
134      *
135      * @param id the item ID
136      * @return an optional containing the item if found
137      */
138     public abstract OptionalEntity<T> get(long id);
139 
140     /**
141      * Inserts a new dictionary item.
142      *
143      * @param item the item to insert
144      */
145     public abstract void insert(T item);
146 
147     /**
148      * Updates an existing dictionary item.
149      *
150      * @param item the item to update
151      */
152     public abstract void update(T item);
153 
154     /**
155      * Deletes a dictionary item.
156      *
157      * @param item the item to delete
158      */
159     public abstract void delete(T item);
160 
161     /**
162      * A paginated list implementation that wraps another list and provides
163      * pagination metadata and functionality.
164      *
165      * @param <E> the type of elements in this list
166      */
167     public static class PagingList<E> implements List<E> {
168         /** The underlying list containing the actual data. */
169         private final List<E> parent;
170 
171         /** The total number of pages available. */
172         protected int allPageCount;
173 
174         /** The total number of records across all pages. */
175         protected int allRecordCount;
176 
177         /** The number of records per page. */
178         protected int pageSize;
179 
180         /** The current page number (1-based). */
181         protected int currentPageNumber;
182 
183         /** The size of the page range for navigation. */
184         protected int pageRangeSize;
185 
186         /**
187          * Creates a new PagingList with the specified parameters.
188          *
189          * @param list the underlying list of items for this page
190          * @param offset the starting offset for this page
191          * @param size the page size
192          * @param allRecordCount the total number of records across all pages
193          */
194         public PagingList(final List<E> list, final int offset, final int size, final int allRecordCount) {
195             parent = list;
196             this.allRecordCount = allRecordCount;
197             pageSize = size;
198             currentPageNumber = offset / size + 1;
199             allPageCount = allRecordCount == 0 ? 0 : (allRecordCount - 1) / size + 1;
200         }
201 
202         @Override
203         public int size() {
204             return parent.size();
205         }
206 
207         @Override
208         public boolean isEmpty() {
209             return parent.isEmpty();
210         }
211 
212         @Override
213         public boolean contains(final Object o) {
214             return parent.contains(o);
215         }
216 
217         @Override
218         public Iterator<E> iterator() {
219             return parent.iterator();
220         }
221 
222         @Override
223         public Object[] toArray() {
224             return parent.toArray();
225         }
226 
227         @Override
228         public <T> T[] toArray(final T[] a) {
229             return parent.toArray(a);
230         }
231 
232         @Override
233         public boolean add(final E e) {
234             return parent.add(e);
235         }
236 
237         @Override
238         public boolean remove(final Object o) {
239             return parent.remove(o);
240         }
241 
242         @Override
243         public boolean containsAll(final Collection<?> c) {
244             return parent.containsAll(c);
245         }
246 
247         @Override
248         public boolean addAll(final Collection<? extends E> c) {
249             return parent.addAll(c);
250         }
251 
252         @Override
253         public boolean addAll(final int index, final Collection<? extends E> c) {
254             return parent.addAll(index, c);
255         }
256 
257         @Override
258         public boolean removeAll(final Collection<?> c) {
259             return parent.removeAll(c);
260         }
261 
262         @Override
263         public boolean retainAll(final Collection<?> c) {
264             return parent.retainAll(c);
265         }
266 
267         @Override
268         public void clear() {
269             parent.clear();
270         }
271 
272         @Override
273         public E get(final int index) {
274             return parent.get(index);
275         }
276 
277         @Override
278         public E set(final int index, final E element) {
279             return parent.set(index, element);
280         }
281 
282         @Override
283         public void add(final int index, final E element) {
284             parent.add(index, element);
285         }
286 
287         @Override
288         public E remove(final int index) {
289             return parent.remove(index);
290         }
291 
292         @Override
293         public int indexOf(final Object o) {
294             return parent.indexOf(o);
295         }
296 
297         @Override
298         public int lastIndexOf(final Object o) {
299             return parent.lastIndexOf(o);
300         }
301 
302         @Override
303         public ListIterator<E> listIterator() {
304             return parent.listIterator();
305         }
306 
307         @Override
308         public ListIterator<E> listIterator(final int index) {
309             return parent.listIterator(index);
310         }
311 
312         @Override
313         public List<E> subList(final int fromIndex, final int toIndex) {
314             return parent.subList(fromIndex, toIndex);
315         }
316 
317         /**
318          * Returns the total number of records across all pages.
319          *
320          * @return the total record count
321          */
322         public int getAllRecordCount() {
323             return allRecordCount;
324         }
325 
326         /**
327          * Returns the page size (number of records per page).
328          *
329          * @return the page size
330          */
331         public int getPageSize() {
332             return pageSize;
333         }
334 
335         /**
336          * Returns the current page number (1-based).
337          *
338          * @return the current page number
339          */
340         public int getCurrentPageNumber() {
341             return currentPageNumber;
342         }
343 
344         /**
345          * Returns the total number of pages.
346          *
347          * @return the total page count
348          */
349         public int getAllPageCount() {
350             return allPageCount;
351         }
352 
353         /**
354          * Checks if a previous page exists.
355          *
356          * @return true if there is a previous page, false otherwise
357          */
358         public boolean isExistPrePage() {
359             return currentPageNumber != 1;
360         }
361 
362         /**
363          * Checks if a next page exists.
364          *
365          * @return true if there is a next page, false otherwise
366          */
367         public boolean isExistNextPage() {
368             return currentPageNumber != allPageCount;
369         }
370 
371         /**
372          * Sets the page range size for navigation.
373          *
374          * @param pageRangeSize the page range size to set
375          */
376         public void setPageRangeSize(final int pageRangeSize) {
377             this.pageRangeSize = pageRangeSize;
378         }
379 
380         /**
381          * Creates a list of page numbers for navigation.
382          *
383          * @return a list of page numbers within the page range
384          */
385         public List<Integer> createPageNumberList() {
386             int startPage = currentPageNumber - pageRangeSize;
387             if (startPage < 1) {
388                 startPage = 1;
389             }
390             int endPage = currentPageNumber + pageRangeSize;
391             if (endPage > allPageCount) {
392                 endPage = allPageCount;
393             }
394             final List<Integer> pageNumberList = new ArrayList<>();
395             for (int i = startPage; i <= endPage; i++) {
396                 pageNumberList.add(i);
397             }
398             return pageNumberList;
399         }
400 
401     }
402 
403 }