|
39 | 39 | @RequiredArgsConstructor
|
40 | 40 | public class LdContextCache {
|
41 | 41 |
|
42 |
| - private final ContextProperties contextProperties; |
43 |
| - |
44 |
| - private URL coreContextUrl; |
45 |
| - private Object coreContext; |
46 |
| - |
47 |
| - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); |
48 |
| - |
49 |
| - @PostConstruct |
50 |
| - public void initDefaultContext() { |
51 |
| - try { |
52 |
| - coreContextUrl = new URL(contextProperties.getDefaultUrl()); |
53 |
| - coreContext = JsonUtils.fromURLJavaNet(coreContextUrl); |
54 |
| - } catch (IOException e) { |
55 |
| - throw new ContextRetrievalException("Invalid core context configured.", e, contextProperties.getDefaultUrl()); |
56 |
| - } |
57 |
| - } |
58 |
| - |
59 |
| - /** |
60 |
| - * Get context from the given url. Will be cached. |
61 |
| - * |
62 |
| - * @param url - url to get the context from |
63 |
| - * @return the context |
64 |
| - */ |
65 |
| - @Cacheable |
66 |
| - public Object getContextFromURL(URL url) { |
67 |
| - try { |
68 |
| - if (url.toURI().equals(coreContextUrl.toURI())) { |
69 |
| - return coreContext; |
70 |
| - } |
71 |
| - return JsonUtils.fromURLJavaNet(url); |
72 |
| - } catch (IOException e) { |
73 |
| - throw new ContextRetrievalException(String.format("Was not able to retrieve context from %s.", url), e, url.toString()); |
74 |
| - } catch (URISyntaxException uriSyntaxException) { |
75 |
| - throw new IllegalArgumentException(String.format("Received an invalid url: %s", url), uriSyntaxException); |
76 |
| - } |
77 |
| - } |
78 |
| - |
79 |
| - /** |
80 |
| - * Expand all given attributes with the given contexts. |
81 |
| - * |
82 |
| - * @param stringsToExpand - strings to be expanded |
83 |
| - * @param contextUrls - urls of contexts to be used for expansion |
84 |
| - * @return list of expanded attribute-ids |
85 |
| - */ |
86 |
| - public List<String> expandStrings(List<String> stringsToExpand, List<URL> contextUrls) { |
87 |
| - Map contextMap = (Map) getContext(contextUrls); |
88 |
| - |
89 |
| - return stringsToExpand.stream() |
90 |
| - .map(stringToExpand -> expandString(stringToExpand, contextMap)) |
91 |
| - .collect(Collectors.toList()); |
92 |
| - } |
93 |
| - |
94 |
| - /** |
95 |
| - * Expand the given string with the provided contexts. |
96 |
| - * |
97 |
| - * @param stringToExpand - string to be expanded |
98 |
| - * @param contextUrls - urls of contexts to be used for expansion |
99 |
| - * @return the expanded attribute-id |
100 |
| - */ |
101 |
| - public String expandString(String stringToExpand, List<URL> contextUrls) { |
102 |
| - return expandString(stringToExpand, (Map) getContext(contextUrls)); |
103 |
| - } |
104 |
| - |
105 |
| - private String expandString(String stringToExpand, Map contextMap) { |
106 |
| - String jsonLdString = getJsonLdString(stringToExpand); |
107 |
| - try { |
108 |
| - Map jsonLdObject = (Map) JsonUtils.fromString(jsonLdString); |
109 |
| - jsonLdObject.put(JsonLdConsts.CONTEXT, contextMap.get(JsonLdConsts.CONTEXT)); |
110 |
| - return getIdFromJsonLDObject(jsonLdObject); |
111 |
| - } catch (IOException e) { |
112 |
| - throw new StringExpansionException(String.format("Was not able expand %s.", jsonLdString), e); |
113 |
| - } |
114 |
| - } |
115 |
| - |
116 |
| - /** |
117 |
| - * Retrieve the context as a JsonDocument |
118 |
| - * |
119 |
| - * @param contextURLs - either be a (URL)String, a URL or a list of urls/urlstrings. |
120 |
| - * @return the context |
121 |
| - */ |
122 |
| - public Document getContextDocument(Object contextURLs) { |
123 |
| - try { |
124 |
| - Object context = getContext(contextURLs); |
125 |
| - return JsonDocument.of(new ByteArrayInputStream(OBJECT_MAPPER.writeValueAsString(context).getBytes(StandardCharsets.UTF_8))); |
126 |
| - } catch (JsonLdError | JsonProcessingException e) { |
127 |
| - throw new IllegalArgumentException(String.format("No valid context available via %s", contextURLs), e); |
128 |
| - } |
129 |
| - } |
130 |
| - |
131 |
| - /** |
132 |
| - * Get the context from the given object. Should either be a (URL)String, a URL or a list of urls/urlstrings. |
133 |
| - * We use the Json-ld-java lib for retrieval, since the titanium lib is not able to combine context objects. |
134 |
| - * |
135 |
| - * @param contextURLs - either be a (URL)String, a URL or a list of urls/urlstrings. |
136 |
| - * @return the context |
137 |
| - */ |
138 |
| - private Object getContext(Object contextURLs) { |
139 |
| - if (contextURLs instanceof List) { |
140 |
| - return Map.of(JsonLdConsts.CONTEXT, ((List) contextURLs).stream() |
141 |
| - .map(this::getContext) |
142 |
| - .map(contextMap -> ((Map<String, Object>) contextMap).get(JsonLdConsts.CONTEXT)) |
143 |
| - .map(contextObject -> { |
144 |
| - // follow potential list-contexts |
145 |
| - if (contextObject instanceof List) { |
146 |
| - return getContext((List) contextObject); |
147 |
| - } else { |
148 |
| - return contextObject; |
149 |
| - } |
150 |
| - }) |
151 |
| - .flatMap(map -> ((Map<String, Object>) map).entrySet().stream()) |
152 |
| - .collect(Collectors.toMap(e -> ((Map.Entry<String, Object>) e).getKey(), e -> ((Map.Entry<String, Object>) e).getValue(), (e1, e2) -> e2))); |
153 |
| - } else if (contextURLs instanceof URL) { |
154 |
| - return getContextFromURL((URL) contextURLs); |
155 |
| - } else if (contextURLs instanceof String) { |
156 |
| - return getContextFromURL((String) contextURLs); |
157 |
| - } else if (contextURLs instanceof URI) { |
158 |
| - return getContextFromURL(contextURLs.toString()); |
159 |
| - } |
160 |
| - throw new ContextRetrievalException(String.format("Did not receive a valid context: %s.", contextURLs), contextURLs.toString()); |
161 |
| - } |
162 |
| - |
163 |
| - |
164 |
| - /** |
165 |
| - * Get the context from the given url |
166 |
| - * |
167 |
| - * @param urlString - string containing the url |
168 |
| - * @return the context |
169 |
| - */ |
170 |
| - private Object getContextFromURL(String urlString) { |
171 |
| - try { |
172 |
| - return getContextFromURL(new URL(urlString)); |
173 |
| - } catch (MalformedURLException e) { |
174 |
| - throw new ContextRetrievalException(String.format("Was not able to convert %s to URL.", urlString), e, urlString); |
175 |
| - } |
176 |
| - } |
177 |
| - |
178 |
| - |
179 |
| - /** |
180 |
| - * Extract the context urls from the link header. CORE_CONTEXT will be automatically added. |
181 |
| - * |
182 |
| - * @param headerString - content of the link header |
183 |
| - * @return list of context urls, will either be only the core context or the core-context + the header context |
184 |
| - */ |
185 |
| - public List<URL> getContextURLsFromLinkHeader(String headerString) { |
186 |
| - |
187 |
| - Optional<String> linkedContextString = Optional.empty(); |
188 |
| - |
189 |
| - if (headerString != null && !headerString.isEmpty() && !headerString.isBlank()) { |
190 |
| - linkedContextString = Optional.of(headerString.split(";")[0].replace("<", "").replace(">", "")); |
191 |
| - } |
192 |
| - |
193 |
| - return linkedContextString |
194 |
| - .map(lCS -> { |
195 |
| - try { |
196 |
| - return new URL(lCS); |
197 |
| - } catch (MalformedURLException e) { |
198 |
| - throw new IllegalArgumentException("Context url is invalid.", e); |
199 |
| - } |
200 |
| - }) |
201 |
| - .map(url -> List.of(url, coreContextUrl)).orElse(List.of(coreContextUrl)); |
202 |
| - } |
203 |
| - |
204 |
| - // extract the Id from the expanded object |
205 |
| - private String getIdFromJsonLDObject(Map<String, Object> jsonLdObject) { |
206 |
| - Map<String, Object> expandedObject = (Map<String, Object>) JsonLdProcessor.expand(jsonLdObject) |
207 |
| - .stream() |
208 |
| - .findFirst() |
209 |
| - .orElseThrow(() -> new StringExpansionException(String.format("Was not able to get an expanded object for %s.", jsonLdObject))); |
210 |
| - Set<String> expandedKeys = expandedObject.keySet(); |
211 |
| - if (expandedKeys.size() != 1) { |
212 |
| - throw new StringExpansionException(String.format("Was not able to correctly expand key. Got multiple keys: %s", expandedKeys)); |
213 |
| - } |
214 |
| - return expandedKeys.iterator().next(); |
215 |
| - } |
216 |
| - |
217 |
| - // create a json object for json-ld api to be used for extending the key. |
218 |
| - private String getJsonLdString(String string) { |
219 |
| - return String.format("{\"%s\":\"\"}", string); |
220 |
| - } |
| 42 | + private final ContextProperties contextProperties; |
| 43 | + |
| 44 | + private URL coreContextUrl; |
| 45 | + private Object coreContext; |
| 46 | + |
| 47 | + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); |
| 48 | + |
| 49 | + @PostConstruct |
| 50 | + public void initDefaultContext() { |
| 51 | + try { |
| 52 | + coreContextUrl = new URL(contextProperties.getDefaultUrl()); |
| 53 | + coreContext = JsonUtils.fromURLJavaNet(coreContextUrl); |
| 54 | + } catch (IOException e) { |
| 55 | + throw new ContextRetrievalException("Invalid core context configured.", e, contextProperties.getDefaultUrl()); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * Get context from the given url. Will be cached. |
| 61 | + * |
| 62 | + * @param url - url to get the context from |
| 63 | + * @return the context |
| 64 | + */ |
| 65 | + @Cacheable |
| 66 | + public Object getContextFromURL(URL url) { |
| 67 | + try { |
| 68 | + if (url.toURI().equals(coreContextUrl.toURI())) { |
| 69 | + return coreContext; |
| 70 | + } |
| 71 | + return JsonUtils.fromURLJavaNet(url); |
| 72 | + } catch (IOException e) { |
| 73 | + throw new ContextRetrievalException(String.format("Was not able to retrieve context from %s.", url), e, url.toString()); |
| 74 | + } catch (URISyntaxException uriSyntaxException) { |
| 75 | + throw new IllegalArgumentException(String.format("Received an invalid url: %s", url), uriSyntaxException); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * Expand all given attributes with the given contexts. |
| 81 | + * |
| 82 | + * @param stringsToExpand - strings to be expanded |
| 83 | + * @param contextUrls - urls of contexts to be used for expansion |
| 84 | + * @return list of expanded attribute-ids |
| 85 | + */ |
| 86 | + public List<String> expandStrings(List<String> stringsToExpand, List<URL> contextUrls) { |
| 87 | + Map contextMap = (Map) getContext(contextUrls); |
| 88 | + |
| 89 | + return stringsToExpand.stream() |
| 90 | + .map(stringToExpand -> expandString(stringToExpand, contextMap)) |
| 91 | + .collect(Collectors.toList()); |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Expand the given string with the provided contexts. |
| 96 | + * |
| 97 | + * @param stringToExpand - string to be expanded |
| 98 | + * @param contextUrls - urls of contexts to be used for expansion |
| 99 | + * @return the expanded attribute-id |
| 100 | + */ |
| 101 | + public String expandString(String stringToExpand, List<URL> contextUrls) { |
| 102 | + return expandString(stringToExpand, (Map) getContext(contextUrls)); |
| 103 | + } |
| 104 | + |
| 105 | + private String expandString(String stringToExpand, Map contextMap) { |
| 106 | + String jsonLdString = getJsonLdString(stringToExpand); |
| 107 | + try { |
| 108 | + Map jsonLdObject = (Map) JsonUtils.fromString(jsonLdString); |
| 109 | + jsonLdObject.put(JsonLdConsts.CONTEXT, contextMap.get(JsonLdConsts.CONTEXT)); |
| 110 | + return getIdFromJsonLDObject(jsonLdObject); |
| 111 | + } catch (IOException e) { |
| 112 | + throw new StringExpansionException(String.format("Was not able expand %s.", jsonLdString), e); |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + /** |
| 117 | + * Retrieve the context as a JsonDocument |
| 118 | + * |
| 119 | + * @param contextURLs - either be a (URL)String, a URL or a list of urls/urlstrings. |
| 120 | + * @return the context |
| 121 | + */ |
| 122 | + public Document getContextDocument(Object contextURLs) { |
| 123 | + try { |
| 124 | + Object context = getContext(contextURLs); |
| 125 | + return JsonDocument.of(new ByteArrayInputStream(OBJECT_MAPPER.writeValueAsString(context).getBytes(StandardCharsets.UTF_8))); |
| 126 | + } catch (JsonLdError | JsonProcessingException e) { |
| 127 | + throw new IllegalArgumentException(String.format("No valid context available via %s", contextURLs), e); |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + /** |
| 132 | + * Get the context from the given object. Should either be a (URL)String, a URL or a list of urls/urlstrings. |
| 133 | + * We use the Json-ld-java lib for retrieval, since the titanium lib is not able to combine context objects. |
| 134 | + * |
| 135 | + * @param contextURLs - either be a (URL)String, a URL or a list of urls/urlstrings. |
| 136 | + * @return the context |
| 137 | + */ |
| 138 | + private Object getContext(Object contextURLs) { |
| 139 | + if (contextURLs instanceof List) { |
| 140 | + var m = Map.of(JsonLdConsts.CONTEXT, ((List) contextURLs).stream() |
| 141 | + .map(url -> getContext(url)) |
| 142 | + .map(contextMap -> ((Map<String, Object>) contextMap).get(JsonLdConsts.CONTEXT)) |
| 143 | + .map(contextObject -> { |
| 144 | + // follow potential list-contexts |
| 145 | + if (contextObject instanceof List) { |
| 146 | + return getContext((List) contextObject); |
| 147 | + } |
| 148 | + return contextObject; |
| 149 | + }) |
| 150 | + .map(co -> { |
| 151 | + if (co instanceof Map<?, ?> coMap) { |
| 152 | + if (coMap.containsKey(JsonLdConsts.CONTEXT)) { |
| 153 | + return coMap.get(JsonLdConsts.CONTEXT); |
| 154 | + } |
| 155 | + } |
| 156 | + return co; |
| 157 | + }) |
| 158 | + .flatMap(map -> ((Map<String, Object>) map).entrySet().stream()) |
| 159 | + .collect(Collectors.toMap(e -> ((Map.Entry<String, Object>) e).getKey(), e -> ((Map.Entry<String, Object>) e).getValue(), (e1, e2) -> e2))); |
| 160 | + return m; |
| 161 | + } else if (contextURLs instanceof URL) { |
| 162 | + return getContextFromURL((URL) contextURLs); |
| 163 | + } else if (contextURLs instanceof String) { |
| 164 | + return getContextFromURL((String) contextURLs); |
| 165 | + } else if (contextURLs instanceof URI) { |
| 166 | + return getContextFromURL(contextURLs.toString()); |
| 167 | + } |
| 168 | + throw new ContextRetrievalException(String.format("Did not receive a valid context: %s.", contextURLs), contextURLs.toString()); |
| 169 | + } |
| 170 | + |
| 171 | + |
| 172 | + /** |
| 173 | + * Get the context from the given url |
| 174 | + * |
| 175 | + * @param urlString - string containing the url |
| 176 | + * @return the context |
| 177 | + */ |
| 178 | + private Object getContextFromURL(String urlString) { |
| 179 | + try { |
| 180 | + return getContextFromURL(new URL(urlString)); |
| 181 | + } catch (MalformedURLException e) { |
| 182 | + throw new ContextRetrievalException(String.format("Was not able to convert %s to URL.", urlString), e, urlString); |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + |
| 187 | + /** |
| 188 | + * Extract the context urls from the link header. CORE_CONTEXT will be automatically added. |
| 189 | + * |
| 190 | + * @param headerString - content of the link header |
| 191 | + * @return list of context urls, will either be only the core context or the core-context + the header context |
| 192 | + */ |
| 193 | + public List<URL> getContextURLsFromLinkHeader(String headerString) { |
| 194 | + |
| 195 | + Optional<String> linkedContextString = Optional.empty(); |
| 196 | + |
| 197 | + if (headerString != null && !headerString.isEmpty() && !headerString.isBlank()) { |
| 198 | + linkedContextString = Optional.of(headerString.split(";")[0].replace("<", "").replace(">", "")); |
| 199 | + } |
| 200 | + |
| 201 | + return linkedContextString |
| 202 | + .map(lCS -> { |
| 203 | + try { |
| 204 | + return new URL(lCS); |
| 205 | + } catch (MalformedURLException e) { |
| 206 | + throw new IllegalArgumentException("Context url is invalid.", e); |
| 207 | + } |
| 208 | + }) |
| 209 | + .map(url -> List.of(url, coreContextUrl)).orElse(List.of(coreContextUrl)); |
| 210 | + } |
| 211 | + |
| 212 | + // extract the Id from the expanded object |
| 213 | + private String getIdFromJsonLDObject(Map<String, Object> jsonLdObject) { |
| 214 | + Map<String, Object> expandedObject = (Map<String, Object>) JsonLdProcessor.expand(jsonLdObject) |
| 215 | + .stream() |
| 216 | + .findFirst() |
| 217 | + .orElseThrow(() -> new StringExpansionException(String.format("Was not able to get an expanded object for %s.", jsonLdObject))); |
| 218 | + Set<String> expandedKeys = expandedObject.keySet(); |
| 219 | + if (expandedKeys.size() != 1) { |
| 220 | + throw new StringExpansionException(String.format("Was not able to correctly expand key. Got multiple keys: %s", expandedKeys)); |
| 221 | + } |
| 222 | + return expandedKeys.iterator().next(); |
| 223 | + } |
| 224 | + |
| 225 | + // create a json object for json-ld api to be used for extending the key. |
| 226 | + private String getJsonLdString(String string) { |
| 227 | + return String.format("{\"%s\":\"\"}", string); |
| 228 | + } |
221 | 229 |
|
222 | 230 | }
|
0 commit comments