• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 17320701451

29 Aug 2025 09:55AM UTC coverage: 12.02% (+0.01%) from 12.007%
17320701451

push

github

ashleycaselli
refactor: minor code style update

330 of 3842 branches covered (8.59%)

Branch coverage included in aggregate %.

950 of 6807 relevant lines covered (13.96%)

0.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/main/java/com/knowledgepixels/nanodash/ApiCache.java
1
package com.knowledgepixels.nanodash;
2

3
import org.nanopub.extra.services.ApiResponse;
4
import org.nanopub.extra.services.ApiResponseEntry;
5
import org.nanopub.extra.services.FailedApiCallException;
6

7
import java.util.*;
8

9
/**
10
 * A utility class for caching API responses and maps to reduce redundant API calls.
11
 * This class is thread-safe and ensures that cached data is refreshed periodically.
12
 */
13
public class ApiCache {
14

15
    private ApiCache() {
16
    } // no instances allowed
17

18
    private transient static Map<String, ApiResponse> cachedResponses = new HashMap<>();
×
19
    private transient static Map<String, Map<String, String>> cachedMaps = new HashMap<>();
×
20
    private transient static Map<String, Long> lastRefresh = new HashMap<>();
×
21
    private transient static Map<String, Long> refreshStart = new HashMap<>();
×
22

23
    /**
24
     * Checks if a cache refresh is currently running for the given cache ID.
25
     *
26
     * @param cacheId The unique identifier for the cache.
27
     * @return True if a refresh is running, false otherwise.
28
     */
29
    private static boolean isRunning(String cacheId) {
30
        if (!refreshStart.containsKey(cacheId)) return false;
×
31
        return System.currentTimeMillis() - refreshStart.get(cacheId) < 60 * 1000;
×
32
    }
33

34
    /**
35
     * Checks if a cache refresh is running for a specific query and parameters.
36
     *
37
     * @param queryName The name of the query.
38
     * @param params    The parameters for the query.
39
     * @return True if a refresh is running, false otherwise.
40
     */
41
    public static boolean isRunning(String queryName, Map<String, String> params) {
42
        return isRunning(getCacheId(queryName, params));
×
43
    }
44

45
    /**
46
     * Checks if a cache refresh is running for a specific query and a single parameter.
47
     *
48
     * @param queryName  The name of the query.
49
     * @param paramName  The name of the parameter.
50
     * @param paramValue The value of the parameter.
51
     * @return True if a refresh is running, false otherwise.
52
     */
53
    public static boolean isRunning(String queryName, String paramName, String paramValue) {
54
        Map<String, String> params = new HashMap<>();
×
55
        params.put(paramName, paramValue);
×
56
        return isRunning(getCacheId(queryName, params));
×
57
    }
58

59
    /**
60
     * Updates the cached API response for a specific query and parameters.
61
     *
62
     * @param queryName The name of the query.
63
     * @param params    The parameters for the query.
64
     * @throws FailedApiCallException If the API call fails.
65
     */
66
    private static void updateResponse(String queryName, Map<String, String> params) throws FailedApiCallException {
67
        Map<String, String> nanopubParams = new HashMap<>();
×
68
        for (String k : params.keySet()) nanopubParams.put(k, params.get(k));
×
69
        ApiResponse response = QueryApiAccess.get(queryName, nanopubParams);
×
70
        String cacheId = getCacheId(queryName, params);
×
71
        cachedResponses.put(cacheId, response);
×
72
        lastRefresh.put(cacheId, System.currentTimeMillis());
×
73
    }
×
74

75
    /**
76
     * Retrieves a cached API response for a specific query and a single parameter.
77
     *
78
     * @param queryName  The name of the query.
79
     * @param paramName  The name of the parameter.
80
     * @param paramValue The value of the parameter.
81
     * @return The cached API response, or null if not cached.
82
     */
83
    public static ApiResponse retrieveResponse(String queryName, String paramName, String paramValue) {
84
        Map<String, String> params = new HashMap<>();
×
85
        params.put(paramName, paramValue);
×
86
        return retrieveResponse(queryName, params);
×
87
    }
88

89
    /**
90
     * Retrieves a cached API response for a specific query and parameters.
91
     * If the cache is stale, it triggers a background refresh.
92
     *
93
     * @param queryName The name of the query.
94
     * @param params    The parameters for the query.
95
     * @return The cached API response, or null if not cached.
96
     */
97
    public static synchronized ApiResponse retrieveResponse(final String queryName, final Map<String, String> params) {
98
        long timeNow = System.currentTimeMillis();
×
99
        String cacheId = getCacheId(queryName, params);
×
100
        boolean isCached = false;
×
101
        boolean needsRefresh = true;
×
102
        if (cachedResponses.containsKey(cacheId) && cachedResponses.get(cacheId) != null) {
×
103
            long cacheAge = timeNow - lastRefresh.get(cacheId);
×
104
            isCached = cacheAge < 24 * 60 * 60 * 1000;
×
105
            needsRefresh = cacheAge > 60 * 1000;
×
106
        }
107
        if (needsRefresh && !isRunning(cacheId)) {
×
108
            refreshStart.put(cacheId, timeNow);
×
109
            new Thread(() -> {
×
110
                try {
111
                    Thread.sleep(100 + new Random().nextLong(400));
×
112
                } catch (InterruptedException ex) {
×
113
                    ex.printStackTrace();
×
114
                }
×
115
                try {
116
                    ApiCache.updateResponse(queryName, params);
×
117
                } catch (Exception ex) {
×
118
                    ex.printStackTrace();
×
119
                    cachedResponses.put(cacheId, null);
×
120
                    lastRefresh.put(cacheId, System.currentTimeMillis());
×
121
                } finally {
122
                    refreshStart.remove(cacheId);
×
123
                }
124
            }).start();
×
125
        }
126
        if (isCached) {
×
127
            if (cachedResponses.get(cacheId) == null) {
×
128
                cachedResponses.remove(cacheId);
×
129
                throw new RuntimeException("Query failed: " + cacheId);
×
130
            }
131
            return cachedResponses.get(cacheId);
×
132
        } else {
133
            return null;
×
134
        }
135
    }
136

137
    /**
138
     * Updates the cached map for a specific query and parameters.
139
     *
140
     * @param queryName The name of the query.
141
     * @param params    The parameters for the query.
142
     * @throws FailedApiCallException If the API call fails.
143
     */
144
    private static void updateMap(String queryName, Map<String, String> params) throws FailedApiCallException {
145
        Map<String, String> map = new HashMap<>();
×
146
        Map<String, String> nanopubParams = new HashMap<>();
×
147
        for (String k : params.keySet()) nanopubParams.put(k, params.get(k));
×
148
        List<ApiResponseEntry> respList = QueryApiAccess.get(queryName, nanopubParams).getData();
×
149
        while (respList != null && !respList.isEmpty()) {
×
150
            ApiResponseEntry resultEntry = respList.remove(0);
×
151
            map.put(resultEntry.get("key"), resultEntry.get("value"));
×
152
        }
×
153
        String cacheId = getCacheId(queryName, params);
×
154
        cachedMaps.put(cacheId, map);
×
155
        lastRefresh.put(cacheId, System.currentTimeMillis());
×
156
    }
×
157

158
    /**
159
     * Retrieves a cached map for a specific query and parameters.
160
     * If the cache is stale, it triggers a background refresh.
161
     *
162
     * @param queryName The name of the query.
163
     * @param params    The parameters for the query.
164
     * @return The cached map, or null if not cached.
165
     */
166
    public static synchronized Map<String, String> retrieveMap(String queryName, Map<String, String> params) {
167
        long timeNow = System.currentTimeMillis();
×
168
        String cacheId = getCacheId(queryName, params);
×
169
        boolean isCached = false;
×
170
        boolean needsRefresh = true;
×
171
        if (cachedMaps.containsKey(cacheId)) {
×
172
            long cacheAge = timeNow - lastRefresh.get(cacheId);
×
173
            isCached = cacheAge < 24 * 60 * 60 * 1000;
×
174
            needsRefresh = cacheAge > 60 * 1000;
×
175
        }
176
        if (needsRefresh && !isRunning(cacheId)) {
×
177
            refreshStart.put(cacheId, timeNow);
×
178
            new Thread(() -> {
×
179
                try {
180
                    Thread.sleep(100 + new Random().nextLong(400));
×
181
                } catch (InterruptedException ex) {
×
182
                    ex.printStackTrace();
×
183
                }
×
184
                try {
185
                    ApiCache.updateMap(queryName, params);
×
186
                } catch (Exception ex) {
×
187
                    ex.printStackTrace();
×
188
                    cachedResponses.put(cacheId, null);
×
189
                    lastRefresh.put(cacheId, System.currentTimeMillis());
×
190
                } finally {
191
                    refreshStart.remove(cacheId);
×
192
                }
193
            }).start();
×
194
        }
195
        if (isCached) {
×
196
            if (cachedResponses.get(cacheId) == null) {
×
197
                cachedResponses.remove(cacheId);
×
198
                throw new RuntimeException("Query failed: " + cacheId);
×
199
            }
200
            return cachedMaps.get(cacheId);
×
201
        } else {
202
            return null;
×
203
        }
204
    }
205

206
    /**
207
     * Converts a map of parameters to a sorted string representation.
208
     *
209
     * @param params The map of parameters.
210
     * @return A string representation of the parameters.
211
     */
212
    private static String paramsToString(Map<String, String> params) {
213
        List<String> keys = new ArrayList<>(params.keySet());
×
214
        Collections.sort(keys);
×
215
        String s = "";
×
216
        for (String k : keys) s += " " + k + "=" + params.get(k);
×
217
        return s;
×
218
    }
219

220
    /**
221
     * Generates a unique cache ID for a specific query and parameters.
222
     *
223
     * @param queryName The name of the query.
224
     * @param params    The parameters for the query.
225
     * @return The unique cache ID.
226
     */
227
    public static String getCacheId(String queryName, Map<String, String> params) {
228
        return queryName + " " + paramsToString(params);
×
229
    }
230
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc