| 
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