1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.impl;
7   
8   import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
9   import gov.nist.secauto.metaschema.core.metapath.IExpression;
10  import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression;
11  import gov.nist.secauto.metaschema.core.metapath.InvalidMetapathGrammarException;
12  import gov.nist.secauto.metaschema.core.metapath.MetapathException;
13  import gov.nist.secauto.metaschema.core.metapath.StaticContext;
14  import gov.nist.secauto.metaschema.core.metapath.cst.IExpressionVisitor;
15  import gov.nist.secauto.metaschema.core.metapath.item.IItem;
16  import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
17  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
18  
19  import java.util.List;
20  
21  import edu.umd.cs.findbugs.annotations.NonNull;
22  import nl.talsmasoftware.lazy4j.Lazy;
23  
24  /**
25   * An implementation of a Metapath expression that is compiled when evaluated.
26   * <p>
27   * Lazy compilation may cause additional {@link MetapathException} errors at
28   * evaluation time, since compilation errors are not raised until evaluation.
29   */
30  public class LazyCompilationMetapathExpression implements IMetapathExpression {
31    @NonNull
32    private final String path;
33    @NonNull
34    private final StaticContext staticContext;
35    @NonNull
36    private final Lazy<IMetapathExpression> compiledMetapath;
37  
38    /**
39     * Construct a new lazy-compiled Metapath expression.
40     *
41     * @param path
42     *          the metapath expression
43     * @param staticContext
44     *          the static evaluation context
45     */
46    public LazyCompilationMetapathExpression(
47        @NonNull String path,
48        @NonNull StaticContext staticContext) {
49      this.path = path;
50      this.staticContext = staticContext;
51      this.compiledMetapath = ObjectUtils.notNull(Lazy.of(() -> {
52        IMetapathExpression result;
53        try {
54          result = IMetapathExpression.compile(path, staticContext);
55        } catch (InvalidMetapathGrammarException ex) {
56          throw new InvalidMetapathGrammarException(ex);
57        }
58        return result;
59      }));
60    }
61  
62    @Override
63    public String getPath() {
64      return path;
65    }
66  
67    @Override
68    public StaticContext getStaticContext() {
69      return staticContext;
70    }
71  
72    @NonNull
73    private IMetapathExpression getCompiledMetapath() {
74      return ObjectUtils.notNull(compiledMetapath.get());
75    }
76  
77    @Override
78    public List<? extends IExpression> getChildren() {
79      return getCompiledMetapath().getChildren();
80    }
81  
82    @Override
83    public Class<? extends IItem> getBaseResultType() {
84      return getCompiledMetapath().getBaseResultType();
85    }
86  
87    @Override
88    public ISequence<? extends IItem> accept(DynamicContext dynamicContext, ISequence<?> focus) {
89      return getCompiledMetapath().accept(dynamicContext, focus);
90    }
91  
92    @Override
93    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
94      return getCompiledMetapath().accept(visitor, context);
95    }
96  
97    @Override
98    public <T extends IItem> ISequence<T> evaluate(IItem focus, DynamicContext dynamicContext) {
99      return getCompiledMetapath().evaluate(focus, dynamicContext);
100   }
101 
102   @Override
103   public String toString() {
104     return getPath();
105   }
106 }