1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.gui.preferences.imagery;
|
---|
3 |
|
---|
4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
5 |
|
---|
6 | import java.awt.GridBagLayout;
|
---|
7 | import java.awt.event.ActionEvent;
|
---|
8 | import java.util.ArrayList;
|
---|
9 | import java.util.Comparator;
|
---|
10 | import java.util.List;
|
---|
11 | import java.util.Map;
|
---|
12 | import java.util.Map.Entry;
|
---|
13 | import java.util.Set;
|
---|
14 | import java.util.concurrent.ConcurrentHashMap;
|
---|
15 |
|
---|
16 | import javax.swing.AbstractAction;
|
---|
17 | import javax.swing.JLabel;
|
---|
18 | import javax.swing.JPanel;
|
---|
19 | import javax.swing.JScrollPane;
|
---|
20 | import javax.swing.JTable;
|
---|
21 | import javax.swing.table.DefaultTableModel;
|
---|
22 | import javax.swing.table.TableColumn;
|
---|
23 | import javax.swing.table.TableModel;
|
---|
24 |
|
---|
25 | import org.apache.commons.jcs.access.CacheAccess;
|
---|
26 | import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
|
---|
27 | import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
|
---|
28 | import org.apache.commons.jcs.engine.stats.behavior.IStats;
|
---|
29 | import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
|
---|
30 | import org.openstreetmap.josm.gui.MainApplication;
|
---|
31 | import org.openstreetmap.josm.gui.layer.TMSLayer;
|
---|
32 | import org.openstreetmap.josm.gui.layer.WMSLayer;
|
---|
33 | import org.openstreetmap.josm.gui.layer.WMTSLayer;
|
---|
34 | import org.openstreetmap.josm.gui.util.GuiHelper;
|
---|
35 | import org.openstreetmap.josm.gui.widgets.ButtonColumn;
|
---|
36 | import org.openstreetmap.josm.tools.GBC;
|
---|
37 | import org.openstreetmap.josm.tools.Logging;
|
---|
38 | import org.openstreetmap.josm.tools.Pair;
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * Panel for cache content management.
|
---|
42 | *
|
---|
43 | * @author Wiktor Niesiobędzki
|
---|
44 | *
|
---|
45 | */
|
---|
46 | public class CacheContentsPanel extends JPanel {
|
---|
47 |
|
---|
48 | /**
|
---|
49 | * Creates cache content panel
|
---|
50 | */
|
---|
51 | public CacheContentsPanel() {
|
---|
52 | super(new GridBagLayout());
|
---|
53 | MainApplication.worker.submit(() -> {
|
---|
54 | addToPanel(TMSLayer.getCache(), "TMS");
|
---|
55 | addToPanel(WMSLayer.getCache(), "WMS");
|
---|
56 | addToPanel(WMTSLayer.getCache(), "WMTS");
|
---|
57 | });
|
---|
58 | }
|
---|
59 |
|
---|
60 | private void addToPanel(final CacheAccess<String, BufferedImageCacheEntry> cache, final String name) {
|
---|
61 | final Long cacheSize = getCacheSize(cache);
|
---|
62 | final TableModel tableModel = getTableModel(cache);
|
---|
63 |
|
---|
64 | GuiHelper.runInEDT(() -> {
|
---|
65 | add(new JLabel(tr("{0} cache, total cache size: {1} bytes", name, cacheSize)),
|
---|
66 | GBC.eol().insets(5, 5, 0, 0));
|
---|
67 | add(new JScrollPane(getTableForCache(cache, tableModel)),
|
---|
68 | GBC.eol().fill(GBC.BOTH));
|
---|
69 | });
|
---|
70 | }
|
---|
71 |
|
---|
72 | private static Long getCacheSize(CacheAccess<String, BufferedImageCacheEntry> cache) {
|
---|
73 | ICacheStats stats = cache.getStatistics();
|
---|
74 | for (IStats cacheStats: stats.getAuxiliaryCacheStats()) {
|
---|
75 | for (IStatElement<?> statElement: cacheStats.getStatElements()) {
|
---|
76 | if ("Data File Length".equals(statElement.getName())) {
|
---|
77 | Object val = statElement.getData();
|
---|
78 | if (val instanceof Long) {
|
---|
79 | return (Long) val;
|
---|
80 | }
|
---|
81 | }
|
---|
82 | }
|
---|
83 | }
|
---|
84 | return Long.valueOf(-1);
|
---|
85 | }
|
---|
86 |
|
---|
87 | /**
|
---|
88 | * Returns the cache stats.
|
---|
89 | * @param cache imagery cache
|
---|
90 | * @return the cache stats
|
---|
91 | */
|
---|
92 | public static String[][] getCacheStats(CacheAccess<String, BufferedImageCacheEntry> cache) {
|
---|
93 | Set<String> keySet = cache.getCacheControl().getKeySet();
|
---|
94 | Map<String, int[]> temp = new ConcurrentHashMap<>(); // use int[] as a Object reference to int, gives better performance
|
---|
95 | for (String key: keySet) {
|
---|
96 | String[] keyParts = key.split(":", 2);
|
---|
97 | if (keyParts.length == 2) {
|
---|
98 | int[] counter = temp.get(keyParts[0]);
|
---|
99 | if (counter == null) {
|
---|
100 | temp.put(keyParts[0], new int[]{1});
|
---|
101 | } else {
|
---|
102 | counter[0]++;
|
---|
103 | }
|
---|
104 | } else {
|
---|
105 | Logging.warn("Could not parse the key: {0}. No colon found", key);
|
---|
106 | }
|
---|
107 | }
|
---|
108 |
|
---|
109 | List<Pair<String, Integer>> sortedStats = new ArrayList<>();
|
---|
110 | for (Entry<String, int[]> e: temp.entrySet()) {
|
---|
111 | sortedStats.add(new Pair<>(e.getKey(), e.getValue()[0]));
|
---|
112 | }
|
---|
113 | sortedStats.sort(Comparator.comparing(o -> o.b, Comparator.reverseOrder()));
|
---|
114 | String[][] ret = new String[sortedStats.size()][3];
|
---|
115 | int index = 0;
|
---|
116 | for (Pair<String, Integer> e: sortedStats) {
|
---|
117 | ret[index] = new String[]{e.a, e.b.toString(), tr("Clear")};
|
---|
118 | index++;
|
---|
119 | }
|
---|
120 | return ret;
|
---|
121 | }
|
---|
122 |
|
---|
123 | private static JTable getTableForCache(final CacheAccess<String, BufferedImageCacheEntry> cache, final TableModel tableModel) {
|
---|
124 | final JTable ret = new JTable(tableModel);
|
---|
125 |
|
---|
126 | ButtonColumn buttonColumn = new ButtonColumn(
|
---|
127 | new AbstractAction() {
|
---|
128 | @Override
|
---|
129 | public void actionPerformed(ActionEvent e) {
|
---|
130 | int row = ret.convertRowIndexToModel(ret.getEditingRow());
|
---|
131 | tableModel.setValueAt("0", row, 1);
|
---|
132 | cache.remove(ret.getValueAt(row, 0).toString() + ':');
|
---|
133 | }
|
---|
134 | });
|
---|
135 | TableColumn tableColumn = ret.getColumnModel().getColumn(2);
|
---|
136 | tableColumn.setCellRenderer(buttonColumn);
|
---|
137 | tableColumn.setCellEditor(buttonColumn);
|
---|
138 | return ret;
|
---|
139 | }
|
---|
140 |
|
---|
141 | private static DefaultTableModel getTableModel(final CacheAccess<String, BufferedImageCacheEntry> cache) {
|
---|
142 | return new DefaultTableModel(
|
---|
143 | getCacheStats(cache),
|
---|
144 | new String[]{tr("Cache name"), tr("Object Count"), tr("Clear")}) {
|
---|
145 | @Override
|
---|
146 | public boolean isCellEditable(int row, int column) {
|
---|
147 | return column == 2;
|
---|
148 | }
|
---|
149 | };
|
---|
150 | }
|
---|
151 | }
|
---|