1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.metapath;
28
29 import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
30 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
31 import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
32 import gov.nist.secauto.metaschema.core.metapath.function.DefaultFunction.CallingContext;
33 import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
34 import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
35 import gov.nist.secauto.metaschema.core.model.IUriResolver;
36 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
37
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.net.URI;
41 import java.net.URISyntaxException;
42 import java.net.URL;
43 import java.nio.file.Path;
44 import java.time.Clock;
45 import java.time.ZoneId;
46 import java.time.ZonedDateTime;
47 import java.util.Collections;
48 import java.util.HashMap;
49 import java.util.Map;
50 import java.util.concurrent.ConcurrentHashMap;
51
52 import edu.umd.cs.findbugs.annotations.NonNull;
53
54 public class DynamicContext {
55 @NonNull
56 private final StaticContext staticContext;
57 @NonNull
58 private final ZoneId implicitTimeZone;
59 @NonNull
60 private final ZonedDateTime currentDateTime;
61 @NonNull
62 private final Map<URI, IDocumentNodeItem> availableDocuments;
63 private final Map<CallingContext, ISequence<?>> functionResultCache;
64 private CachingLoader documentLoader;
65 @NonNull
66 private final IMutableConfiguration<MetapathEvaluationFeature<?>> configuration;
67 @NonNull
68 private final Map<String, ISequence<?>> letVariableMap;
69
70 @SuppressWarnings("null")
71 public DynamicContext(@NonNull StaticContext staticContext) {
72 this.staticContext = staticContext;
73
74 Clock clock = Clock.systemDefaultZone();
75
76 this.implicitTimeZone = clock.getZone();
77 this.currentDateTime = ZonedDateTime.now(clock);
78 this.availableDocuments = new HashMap<>();
79 this.functionResultCache = new HashMap<>();
80 this.configuration = new DefaultConfiguration<>();
81 this.configuration.enableFeature(MetapathEvaluationFeature.METAPATH_EVALUATE_PREDICATES);
82 this.letVariableMap = new ConcurrentHashMap<>();
83 }
84
85 @NonNull
86 public StaticContext getStaticContext() {
87 return staticContext;
88 }
89
90 @NonNull
91 public ZoneId getImplicitTimeZone() {
92 return implicitTimeZone;
93 }
94
95 @NonNull
96 public ZonedDateTime getCurrentDateTime() {
97 return currentDateTime;
98 }
99
100 @SuppressWarnings("null")
101 @NonNull
102 public Map<URI, INodeItem> getAvailableDocuments() {
103 return Collections.unmodifiableMap(availableDocuments);
104 }
105
106 public IDocumentLoader getDocumentLoader() {
107 return documentLoader;
108 }
109
110 public void setDocumentLoader(@NonNull IDocumentLoader documentLoader) {
111 this.documentLoader = new CachingLoader(documentLoader);
112 }
113
114 public ISequence<?> getCachedResult(@NonNull CallingContext callingContext) {
115 return functionResultCache.get(callingContext);
116 }
117
118 @NonNull
119 public DynamicContext disablePredicateEvaluation() {
120 this.configuration.disableFeature(MetapathEvaluationFeature.METAPATH_EVALUATE_PREDICATES);
121 return this;
122 }
123
124 @NonNull
125 public IConfiguration<MetapathEvaluationFeature<?>> getConfiguration() {
126 return configuration;
127 }
128
129 public void cacheResult(@NonNull CallingContext callingContext, @NonNull ISequence<?> result) {
130 ISequence<?> old = functionResultCache.put(callingContext, result);
131 assert old == null;
132 }
133
134 @NonNull
135 public ISequence<?> getVariableValue(String name) {
136 return ObjectUtils.requireNonNull(letVariableMap.get(name));
137 }
138
139 public void setVariableValue(String name, ISequence<?> boundValue) {
140 letVariableMap.put(name, boundValue);
141 }
142
143 public void clearVariableValue(String name) {
144 letVariableMap.remove(name);
145 }
146
147 private class CachingLoader implements IDocumentLoader {
148 @NonNull
149 private final IDocumentLoader proxy;
150
151 public CachingLoader(@NonNull IDocumentLoader proxy) {
152 this.proxy = proxy;
153 }
154
155 @Override
156 public IUriResolver getUriResolver() {
157 return new ContextUriResolver();
158 }
159
160 @Override
161 public void setUriResolver(@NonNull IUriResolver resolver) {
162
163 throw new UnsupportedOperationException("Set the resolver on the proxy");
164 }
165
166 @NonNull
167 protected IDocumentLoader getProxiedDocumentLoader() {
168 return proxy;
169 }
170
171 @Override
172 public IDocumentNodeItem loadAsNodeItem(Path path) throws IOException {
173 URI uri = path.toUri();
174 IDocumentNodeItem retval = availableDocuments.get(uri);
175 if (retval == null) {
176 retval = getProxiedDocumentLoader().loadAsNodeItem(path);
177 availableDocuments.put(uri, retval);
178 }
179 return retval;
180 }
181
182 @Override
183 public IDocumentNodeItem loadAsNodeItem(URL url) throws IOException, URISyntaxException {
184 URI uri = ObjectUtils.notNull(url.toURI());
185 IDocumentNodeItem retval = availableDocuments.get(uri);
186 if (retval == null) {
187 retval = getProxiedDocumentLoader().loadAsNodeItem(uri);
188 availableDocuments.put(uri, retval);
189 }
190 return retval;
191 }
192
193 @Override
194 public IDocumentNodeItem loadAsNodeItem(URI uri) throws IOException {
195 IDocumentNodeItem retval = availableDocuments.get(uri);
196 if (retval == null) {
197 retval = getProxiedDocumentLoader().loadAsNodeItem(uri);
198 availableDocuments.put(uri, retval);
199 }
200 return retval;
201 }
202
203 @Override
204 public @NonNull IDocumentNodeItem loadAsNodeItem(
205 @NonNull InputStream is,
206 @NonNull URI documentUri) throws IOException {
207 throw new UnsupportedOperationException();
208
209 }
210
211 public class ContextUriResolver implements IUriResolver {
212
213
214
215
216
217
218
219 @Override
220 public URI resolve(URI uri) {
221 URI baseUri = getStaticContext().getBaseUri();
222
223 URI resolvedUri;
224 if (baseUri == null) {
225 resolvedUri = uri;
226 } else {
227 resolvedUri = ObjectUtils.notNull(baseUri.resolve(uri));
228 }
229
230 IUriResolver resolver = getProxiedDocumentLoader().getUriResolver();
231 return resolver == null ? resolvedUri : resolver.resolve(resolvedUri);
232 }
233 }
234 }
235 }