1 | // Jomic - a viewer for comic book archives. |
2 | // Copyright (C) 2004-2011 Thomas Aglassinger |
3 | // |
4 | // This program is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by |
6 | // the Free Software Foundation, either version 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
9 | // This program is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // GNU General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | package net.sf.jomic.common; |
17 | |
18 | import java.awt.Component; |
19 | import java.awt.Dimension; |
20 | import java.awt.Toolkit; |
21 | import java.beans.PropertyChangeEvent; |
22 | import java.beans.PropertyChangeListener; |
23 | import java.io.File; |
24 | import java.io.FileInputStream; |
25 | import java.io.FileNotFoundException; |
26 | import java.io.FileOutputStream; |
27 | import java.io.IOException; |
28 | import java.io.InputStream; |
29 | import java.io.OutputStream; |
30 | import java.util.ArrayList; |
31 | import java.util.HashMap; |
32 | import java.util.Iterator; |
33 | import java.util.List; |
34 | import java.util.Locale; |
35 | import java.util.Map; |
36 | import java.util.Properties; |
37 | import java.util.Set; |
38 | |
39 | import net.roydesign.mac.MRJAdapter; |
40 | import net.roydesign.mac.MRJFolderConstants; |
41 | import net.sf.jomic.tools.FileTools; |
42 | import net.sf.jomic.tools.ImageTools; |
43 | import net.sf.jomic.tools.LocaleTools; |
44 | import net.sf.jomic.tools.StringTools; |
45 | import net.sf.jomic.tools.SystemTools; |
46 | import net.sf.jomic.tools.TunneledIOException; |
47 | |
48 | import org.apache.commons.logging.Log; |
49 | import org.apache.commons.logging.LogFactory; |
50 | |
51 | /** |
52 | * Settings for Jomic. These are collected as Properties, and can be read from or written to a |
53 | * settings file. |
54 | * |
55 | * @author Thomas Aglassinger |
56 | * @see #read(File) |
57 | * @see #write(File) |
58 | */ |
59 | public final class Settings extends ComicSheetRenderSettings implements PropertyChangeListener |
60 | { |
61 | public static final int MAX_BLUR_RADIUS = 15; |
62 | public static final int MAX_BLUR_THRESHOLD = 255; |
63 | public static final int MIN_BLUR_RADIUS = 3; |
64 | public static final int MIN_BLUR_THRESHOLD = 0; |
65 | |
66 | private static final double DEFAULT_HEIGHT_FACTOR = 0.5; |
67 | private static final double DEFAULT_WIDTH_FACTOR = 0.5; |
68 | |
69 | private static Settings instance; |
70 | |
71 | private File baseCacheDir; |
72 | |
73 | /** |
74 | * Map to map cache name (for example "imageio") to directory (for example |
75 | * "~/Users/me/Library/Cache/jomic/imageio"). |
76 | * |
77 | * @see #getCacheDir(String) |
78 | */ |
79 | private Map cacheDirMap; |
80 | private FileTools fileTools; |
81 | private ImageTools imageTools; |
82 | private LocaleTools localeTools; |
83 | private Log logger; |
84 | private List recentFiles; |
85 | private StartupTools startupTools; |
86 | private StringTools stringTools; |
87 | private SystemTools systemTools; |
88 | |
89 | public Settings(Properties defaults) { |
90 | this(); |
91 | |
92 | Iterator defaultsRider = defaults.entrySet().iterator(); |
93 | |
94 | while (defaultsRider.hasNext()) { |
95 | Map.Entry entry = (Map.Entry) defaultsRider.next(); |
96 | String key = (String) entry.getKey(); |
97 | String value = (String) entry.getValue(); |
98 | |
99 | setProperty(key, value); |
100 | } |
101 | } |
102 | |
103 | private Settings() { |
104 | logger = LogFactory.getLog(Settings.class); |
105 | fileTools = FileTools.instance(); |
106 | imageTools = ImageTools.instance(); |
107 | localeTools = LocaleTools.instance(); |
108 | startupTools = StartupTools.instance(); |
109 | stringTools = StringTools.instance(); |
110 | systemTools = SystemTools.instance(); |
111 | |
112 | setSystemPropertyPrefix(PropertyConstants.SYSTEM_PROPERTY_PREFIX); |
113 | |
114 | // Setup default properties |
115 | Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); |
116 | int[] defaultComicWindow = new int[]{ |
117 | 0, 0, |
118 | (int) (DEFAULT_WIDTH_FACTOR * screenSize.width), |
119 | (int) (DEFAULT_HEIGHT_FACTOR * screenSize.height) |
120 | }; |
121 | String homeDir = System.getProperty("user.home"); |
122 | |
123 | assert homeDir != null; |
124 | |
125 | setDefault(PropertyConstants.ARCHIVE_CACHE_SIZE_IN_MB, |
126 | PropertyConstants.DEFAULT_ARCHIVE_CACHE_SIZE_IN_MB); |
127 | setDefault(PropertyConstants.BLUR_RADIUS, PropertyConstants.DEFAULT_BLUR_RADIUS); |
128 | setDefault(PropertyConstants.BLUR_THRESHOLD, PropertyConstants.DEFAULT_BLUR_THRESHOLD); |
129 | setDefault(PropertyConstants.BLUR_MODE, ImageTools.GAUSSIAN_BLUR); |
130 | setDefault(PropertyConstants.COMIC_WINDOW, stringTools.arrayToString(defaultComicWindow)); |
131 | setDefault(PropertyConstants.FEW, PropertyConstants.DEFAULT_FEW); |
132 | setDefault(PropertyConstants.LAST_CREATE_COMIC_SOURCE_DIR, ""); |
133 | setDefault(PropertyConstants.LAST_CREATE_COMIC_TARGET_DIR, homeDir); |
134 | setDefault(PropertyConstants.LAST_EXPORTED_IMAGE_DIR, homeDir); |
135 | setDefault(PropertyConstants.LAST_EXPORT_ALL_IMAGES_DIR, homeDir); |
136 | setDefault(PropertyConstants.LOCALE, Locale.getDefault().toString()); |
137 | setDefault(PropertyConstants.MOST_RECENT_PAGE, PropertyConstants.DEFAULT_MOST_RECENT_PAGE); |
138 | setDefault(PropertyConstants.OPEN_IN_FULL_SCREEN, false); |
139 | setDefault(PropertyConstants.RECENT_COUNT, PropertyConstants.DEFAULT_RECENT_COUNT); |
140 | setDefault(PropertyConstants.SCROLL_COUNT, PropertyConstants.DEFAULT_SCROLL_COUNT); |
141 | setDefault(PropertyConstants.SHOW_INFO, false); |
142 | setDefault(PropertyConstants.SHOW_TOOLBAR, true); |
143 | setDefault(PropertyConstants.SHOW_THUMBS, false); |
144 | setDefault(PropertyConstants.SORT_MODE, PropertyConstants.DEFAULT_SORT_MODE); |
145 | setDefault(ComicSheetRenderSettings.SWAP_LEFT_AND_RIGHT_IMAGE, false); |
146 | setDefault(PropertyConstants.TEST_DELAY, PropertyConstants.DEFAULT_DELAY); |
147 | setDefault(PropertyConstants.TILE_CACHE_SIZE_IN_MB, PropertyConstants.DEFAULT_TILE_CACHE_SIZE_IN_MB); |
148 | setDefault(ComicSheetRenderSettings.SHOW_TWO_PAGES, false); |
149 | |
150 | recentFiles = new ArrayList(); |
151 | cacheDirMap = new HashMap(); |
152 | addPropertyChangeListener(localeTools); |
153 | addPropertyChangeListener(PropertyConstants.CACHE_DIR, this); |
154 | localeTools.setLocale(getLocale()); |
155 | } |
156 | |
157 | public void setAdjustArchiveSuffix(boolean newAdjustArchiveSuffix) { |
158 | setBooleanProperty(PropertyConstants.ADJUST_ARCHIVE_SUFFIX, newAdjustArchiveSuffix); |
159 | } |
160 | |
161 | public void setBlurMode(String newBlurMode) { |
162 | setChoiceProperty(PropertyConstants.BLUR_MODE, newBlurMode, imageTools.getPossibleBlurModes()); |
163 | } |
164 | |
165 | public void setBlurRadius(int newBlurRadius) { |
166 | setLimitedIntProperty(PropertyConstants.BLUR_RADIUS, newBlurRadius, MIN_BLUR_RADIUS, MAX_BLUR_RADIUS); |
167 | } |
168 | |
169 | public void setBlurThreshold(int newBlurThreshold) { |
170 | setLimitedIntProperty(PropertyConstants.BLUR_THRESHOLD, newBlurThreshold, |
171 | MIN_BLUR_THRESHOLD, MAX_BLUR_THRESHOLD); |
172 | } |
173 | |
174 | public void setComicWindow(Component component) { |
175 | setComponentAreaProperty(PropertyConstants.COMIC_WINDOW, component); |
176 | } |
177 | |
178 | public void setLastCreateComicSourceDir(File newSourceDir) { |
179 | assert newSourceDir != null; |
180 | setFileProperty(PropertyConstants.LAST_CREATE_COMIC_SOURCE_DIR, newSourceDir); |
181 | } |
182 | |
183 | public void setLastCreateComicTargetDir(File newTargetDir) { |
184 | assert newTargetDir != null; |
185 | setFileProperty(PropertyConstants.LAST_CREATE_COMIC_TARGET_DIR, newTargetDir); |
186 | } |
187 | |
188 | public void setLastExportAllImagesDir(File newDir) { |
189 | assert newDir != null; |
190 | setFileProperty(PropertyConstants.LAST_EXPORT_ALL_IMAGES_DIR, newDir); |
191 | } |
192 | |
193 | public void setLastExportedImageDir(File newImageDir) { |
194 | assert newImageDir != null; |
195 | setFileProperty(PropertyConstants.LAST_EXPORTED_IMAGE_DIR, newImageDir); |
196 | } |
197 | |
198 | public void setLocale(String newLocale) { |
199 | assert newLocale != null; |
200 | setProperty(PropertyConstants.LOCALE, newLocale); |
201 | } |
202 | |
203 | /** |
204 | * Get the most recently opened file, or <code>null</code> no recent file has ever been opened |
205 | * (typically when using Jomic the first time after installation). |
206 | */ |
207 | public void setMostRecentPage(int newMostRecentPage) { |
208 | assert newMostRecentPage >= 0; |
209 | setIntProperty(PropertyConstants.MOST_RECENT_PAGE, newMostRecentPage); |
210 | } |
211 | |
212 | public void setOpenInFullScreen(boolean newOpenInFullScreen) { |
213 | setBooleanProperty(PropertyConstants.OPEN_IN_FULL_SCREEN, newOpenInFullScreen); |
214 | } |
215 | |
216 | public void setOpenNewComic(boolean newOpenNewComic) { |
217 | setBooleanProperty(PropertyConstants.OPEN_NEW_COMIC, newOpenNewComic); |
218 | } |
219 | |
220 | public void setShowInfo(boolean newShowInfo) { |
221 | setBooleanProperty(PropertyConstants.SHOW_INFO, newShowInfo); |
222 | } |
223 | |
224 | public void setShowThumbs(boolean newShowThumbs) { |
225 | setBooleanProperty(PropertyConstants.SHOW_THUMBS, newShowThumbs); |
226 | } |
227 | |
228 | public void setShowToolbar(boolean newShowToolbar) { |
229 | setBooleanProperty(PropertyConstants.SHOW_TOOLBAR, newShowToolbar); |
230 | } |
231 | |
232 | public void setUseBlur(boolean newUseBlur) { |
233 | setBooleanProperty(PropertyConstants.USE_BLUR, newUseBlur); |
234 | } |
235 | |
236 | private synchronized void setupBaseCacheDir() |
237 | throws FileNotFoundException { |
238 | setupBaseCacheDir(getProperty(PropertyConstants.CACHE_DIR)); |
239 | } |
240 | |
241 | private synchronized void setupBaseCacheDir(String cacheDirName) |
242 | throws FileNotFoundException { |
243 | if (cacheDirName != null) { |
244 | baseCacheDir = new File(cacheDirName); |
245 | } else { |
246 | if (systemTools.isMacOSX()) { |
247 | try { |
248 | baseCacheDir = MRJAdapter.findFolder(MRJFolderConstants.kUserDomain, |
249 | MRJFolderConstants.kCachedDataFolderType, true); |
250 | } catch (FileNotFoundException error) { |
251 | String message = localeTools.getMessage("errors.cannotCreateCacheFolder"); |
252 | |
253 | throw new TunneledIOException(message, error); |
254 | } |
255 | baseCacheDir = new File(baseCacheDir.getAbsolutePath(), "jomic"); |
256 | } else { |
257 | File jomicDir = new File(System.getProperty("user.home"), ".jomic"); |
258 | |
259 | baseCacheDir = new File(jomicDir, "caches"); |
260 | } |
261 | } |
262 | if (logger.isInfoEnabled()) { |
263 | logger.info("base cache path = " |
264 | + stringTools.sourced(baseCacheDir.getAbsolutePath())); |
265 | } |
266 | assert baseCacheDir != null; |
267 | fileTools.mkdirs(baseCacheDir); |
268 | } |
269 | |
270 | public boolean getAdjustArchiveSuffix() { |
271 | return getBooleanProperty(PropertyConstants.ADJUST_ARCHIVE_SUFFIX); |
272 | } |
273 | |
274 | public File getArchiveCache() |
275 | throws IOException { |
276 | return getCacheDir("archives"); |
277 | } |
278 | |
279 | /** |
280 | * Get tile cache size (in mega byte). |
281 | */ |
282 | public int getArchiveCacheSizeInMb() { |
283 | return getIntProperty(PropertyConstants.ARCHIVE_CACHE_SIZE_IN_MB); |
284 | } |
285 | |
286 | public String getBlurMode() { |
287 | return getChoiceProperty(PropertyConstants.BLUR_MODE, imageTools.getPossibleBlurModes()); |
288 | } |
289 | |
290 | public int getBlurRadius() { |
291 | return getLimitedIntProperty(PropertyConstants.BLUR_RADIUS, MIN_BLUR_RADIUS, MAX_BLUR_RADIUS); |
292 | } |
293 | |
294 | public int getBlurThreshold() { |
295 | return getLimitedIntProperty(PropertyConstants.BLUR_THRESHOLD, MIN_BLUR_THRESHOLD, MAX_BLUR_THRESHOLD); |
296 | } |
297 | |
298 | /** |
299 | * Get the cache directory <code>name</code> in the base cache directory. If the directory does |
300 | * not exist yet, create it. |
301 | */ |
302 | public File getCacheDir(String name) |
303 | throws FileNotFoundException { |
304 | assert name != null; |
305 | assert name.length() > 0; |
306 | File result; |
307 | |
308 | synchronized (cacheDirMap) { |
309 | result = (File) cacheDirMap.get(name); |
310 | if (result == null) { |
311 | setupBaseCacheDir(); |
312 | result = new File(baseCacheDir, name); |
313 | fileTools.mkdirs(result); |
314 | cacheDirMap.put(name, result); |
315 | } |
316 | } |
317 | assert result != null; |
318 | return result; |
319 | } |
320 | |
321 | /** |
322 | * Get the base cache directory, where all the caches are stored. |
323 | */ |
324 | public File getCacheDir() |
325 | throws FileNotFoundException { |
326 | setupBaseCacheDir(); |
327 | return baseCacheDir; |
328 | } |
329 | |
330 | public int getFew() { |
331 | return getIntProperty(PropertyConstants.FEW); |
332 | } |
333 | |
334 | public File getImageIOCache() |
335 | throws IOException { |
336 | return getCacheDir("imageio"); |
337 | } |
338 | |
339 | public File getLastCreateComicSourceDir() { |
340 | return getFileProperty(PropertyConstants.LAST_CREATE_COMIC_SOURCE_DIR); |
341 | } |
342 | |
343 | public File getLastCreateComicTargetDir() { |
344 | return getFileProperty(PropertyConstants.LAST_CREATE_COMIC_TARGET_DIR); |
345 | } |
346 | |
347 | public File getLastExportAllImagesDir() { |
348 | return getFileProperty(PropertyConstants.LAST_EXPORT_ALL_IMAGES_DIR); |
349 | } |
350 | |
351 | public File getLastExportedImageDir() { |
352 | return getFileProperty(PropertyConstants.LAST_EXPORTED_IMAGE_DIR); |
353 | } |
354 | |
355 | public String getLocale() { |
356 | String result = getProperty(PropertyConstants.LOCALE); |
357 | |
358 | return result; |
359 | } |
360 | |
361 | /** |
362 | * Get the most recently opened file, or <code>null</code> no recent file has ever been opened |
363 | * (typically when using Jomic the first time after installation). |
364 | */ |
365 | public File getMostRecentFile() { |
366 | File result; |
367 | |
368 | synchronized (recentFiles) { |
369 | int fileCount = getRecentFiles().size(); |
370 | |
371 | if (fileCount == 0) { |
372 | result = null; |
373 | } else { |
374 | result = (File) getRecentFiles().get(0); |
375 | } |
376 | } |
377 | return result; |
378 | } |
379 | |
380 | /** |
381 | * Get the most recently opened file, or <code>null</code> no recent file has ever been opened |
382 | * (typically when using Jomic the first time after installation). |
383 | */ |
384 | public int getMostRecentPage() { |
385 | return getIntProperty(PropertyConstants.MOST_RECENT_PAGE); |
386 | } |
387 | |
388 | public boolean getOpenInFullScreen() { |
389 | return getBooleanProperty(PropertyConstants.OPEN_IN_FULL_SCREEN); |
390 | } |
391 | |
392 | public boolean getOpenNewComic() { |
393 | return getBooleanProperty(PropertyConstants.OPEN_NEW_COMIC); |
394 | } |
395 | |
396 | public int getRecentCount() { |
397 | return getIntProperty(PropertyConstants.RECENT_COUNT); |
398 | } |
399 | |
400 | public List getRecentFiles() { |
401 | assert recentFiles != null; |
402 | return recentFiles; |
403 | } |
404 | |
405 | public int getScrollCount() { |
406 | return getIntProperty(PropertyConstants.SCROLL_COUNT); |
407 | } |
408 | |
409 | /** |
410 | * Gets the file where the settings are stored. |
411 | */ |
412 | public File getSettingsFile() { |
413 | return startupTools.getSettingsFile("jomic"); |
414 | } |
415 | |
416 | public boolean getShowInfo() { |
417 | return getBooleanProperty(PropertyConstants.SHOW_INFO); |
418 | } |
419 | |
420 | public boolean getShowThumbs() { |
421 | return getBooleanProperty(PropertyConstants.SHOW_THUMBS); |
422 | } |
423 | |
424 | public boolean getShowToolbar() { |
425 | return getBooleanProperty(PropertyConstants.SHOW_TOOLBAR); |
426 | } |
427 | |
428 | public String getSortMode() { |
429 | return getProperty(PropertyConstants.SORT_MODE); |
430 | } |
431 | |
432 | /** |
433 | * Get tile cache size (in mega byte). |
434 | */ |
435 | public int getTileCacheSizeInMb() { |
436 | return getIntProperty(PropertyConstants.TILE_CACHE_SIZE_IN_MB); |
437 | } |
438 | |
439 | public static synchronized Settings instance() { |
440 | if (instance == null) { |
441 | instance = new Settings(); |
442 | } |
443 | return instance; |
444 | } |
445 | |
446 | public void addRecentFile(final File file, int page) { |
447 | assert file != null; |
448 | assert page >= 0; |
449 | if (logger.isDebugEnabled()) { |
450 | logger.debug("add recent file: \"" + file + "\" at page " + page); |
451 | } |
452 | synchronized (recentFiles) { |
453 | recentFiles.remove(file); |
454 | recentFiles.add(0, file); |
455 | setMostRecentPage(page); |
456 | if (recentFiles.size() > getRecentCount()) { |
457 | if (logger.isDebugEnabled()) { |
458 | logger.debug("discarding oldest recent file"); |
459 | } |
460 | recentFiles.remove(getRecentCount()); |
461 | } |
462 | } |
463 | } |
464 | |
465 | public void applyComicWindow(Component component) { |
466 | assert component != null; |
467 | applyComponentAreaProperty(PropertyConstants.COMIC_WINDOW, component); |
468 | } |
469 | |
470 | public void clearRecentFiles() { |
471 | synchronized (recentFiles) { |
472 | recentFiles.clear(); |
473 | } |
474 | } |
475 | |
476 | public void propertyChange(PropertyChangeEvent event) { |
477 | assert event != null; |
478 | String propertyName = event.getPropertyName(); |
479 | |
480 | if (propertyName.equals(PropertyConstants.CACHE_DIR)) { |
481 | try { |
482 | setupBaseCacheDir((String) event.getNewValue()); |
483 | } catch (FileNotFoundException error) { |
484 | throw new TunneledIOException(error); |
485 | } |
486 | } |
487 | } |
488 | |
489 | public void read(File file) |
490 | throws IOException { |
491 | assert file != null; |
492 | Properties loaded = new Properties(); |
493 | |
494 | try { |
495 | InputStream in = new FileInputStream(file); |
496 | |
497 | try { |
498 | loaded.load(in); |
499 | } finally { |
500 | in.close(); |
501 | } |
502 | |
503 | Set entries = loaded.entrySet(); |
504 | Iterator rider = entries.iterator(); |
505 | |
506 | while (rider.hasNext()) { |
507 | Map.Entry entry = (Map.Entry) rider.next(); |
508 | |
509 | setProperty((String) entry.getKey(), (String) entry.getValue()); |
510 | } |
511 | updateRecentFilesFromProperties(); |
512 | |
513 | // Remove obsolete properties |
514 | remove("comic.height"); |
515 | remove("comic.left"); |
516 | remove("comic.top"); |
517 | remove("comic.width"); |
518 | } catch (FileNotFoundException error) { |
519 | logger.warn("cannot read settings from \"" + file + "\"; using defaults"); |
520 | } |
521 | } |
522 | |
523 | public void resetComicFrame() { |
524 | remove(PropertyConstants.COMIC_WINDOW); |
525 | } |
526 | |
527 | public boolean useBlur() { |
528 | return getBooleanProperty(PropertyConstants.USE_BLUR); |
529 | } |
530 | |
531 | public void write(File settingsFile) |
532 | throws IOException { |
533 | assert settingsFile != null; |
534 | |
535 | // Make sure directories for settings file exist. |
536 | File settingsDir = settingsFile.getParentFile(); |
537 | |
538 | fileTools.mkdirs(settingsDir); |
539 | |
540 | // Write actual settings file. |
541 | OutputStream out = new FileOutputStream(settingsFile); |
542 | |
543 | updatePropertiesFromRecentFiles(); |
544 | try { |
545 | store(out, "Settings for Jomic"); |
546 | } finally { |
547 | out.close(); |
548 | } |
549 | } |
550 | |
551 | private void removeDuplicatesFromRecentFiles() { |
552 | recentFiles = new ArrayList(); |
553 | for (int i = 0; i < getRecentCount(); i += 1) { |
554 | String key = PropertyConstants.RECENT_PREFIX + i; |
555 | String recentPath = getProperty(key); |
556 | |
557 | if (recentPath != null) { |
558 | File recentFile = new File(recentPath); |
559 | |
560 | if (!recentFiles.contains(recentFile)) { |
561 | recentFiles.add(recentFile); |
562 | } |
563 | } |
564 | } |
565 | } |
566 | |
567 | private void updatePropertiesFromRecentFiles() { |
568 | setIntProperty(PropertyConstants.RECENT_COUNT, getRecentCount()); |
569 | |
570 | int i = 1; |
571 | Iterator rider = recentFiles.iterator(); |
572 | |
573 | while (rider.hasNext()) { |
574 | File recentFile = (File) rider.next(); |
575 | |
576 | setProperty(PropertyConstants.RECENT_PREFIX + i, recentFile.getAbsolutePath()); |
577 | i += 1; |
578 | } |
579 | } |
580 | |
581 | private void updateRecentFilesFromProperties() { |
582 | removeDuplicatesFromRecentFiles(); |
583 | |
584 | // Remove "recent" properties. |
585 | Map.Entry recentEntryToRemove; |
586 | |
587 | do { |
588 | Set entries = entrySet(); |
589 | Iterator rider = entries.iterator(); |
590 | |
591 | // This property should never exist, and would cause trouble for substring-index operations later on. |
592 | if (getProperty(PropertyConstants.RECENT_PREFIX) != null) { |
593 | String message = localeTools.getMessage( |
594 | "errors.propertyMustBeRemoved", PropertyConstants.RECENT_PREFIX); |
595 | |
596 | throw new IllegalStateException(message); |
597 | } |
598 | |
599 | recentEntryToRemove = null; |
600 | while ((recentEntryToRemove == null) && (rider.hasNext())) { |
601 | Map.Entry next = (Map.Entry) rider.next(); |
602 | String propertyName = (String) next.getKey(); |
603 | |
604 | if (propertyName.startsWith(PropertyConstants.RECENT_PREFIX)) { |
605 | String suffix = propertyName.substring(PropertyConstants.RECENT_PREFIX.length()); |
606 | |
607 | try { |
608 | Integer.parseInt(suffix); |
609 | recentEntryToRemove = next; |
610 | } catch (NumberFormatException error) { |
611 | if (logger.isDebugEnabled()) { |
612 | logger.debug("keeping non-numeric recent-property:" + propertyName); |
613 | } |
614 | } |
615 | } |
616 | } |
617 | if (recentEntryToRemove != null) { |
618 | String recentKeyToRemove = (String) recentEntryToRemove.getKey(); |
619 | |
620 | remove(recentKeyToRemove); |
621 | } |
622 | } while (recentEntryToRemove != null); |
623 | } |
624 | } |