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.ICollectionValue;
10  import gov.nist.secauto.metaschema.core.metapath.ISequence;
11  import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
12  import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
13  import gov.nist.secauto.metaschema.core.metapath.function.library.MapGet;
14  import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
15  import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem;
16  import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem;
17  import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
18  import gov.nist.secauto.metaschema.core.metapath.type.ISequenceType;
19  import gov.nist.secauto.metaschema.core.metapath.type.Occurrence;
20  import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
21  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
22  
23  import java.util.EnumSet;
24  import java.util.List;
25  import java.util.Objects;
26  import java.util.Set;
27  import java.util.stream.Collectors;
28  
29  import edu.umd.cs.findbugs.annotations.NonNull;
30  
31  /**
32   * The base class for {@link IMapItem} implementations, that provide an
33   * implementation of common utility methods.
34   *
35   * @param <VALUE>
36   *          the Java type of the value items contained within the map
37   */
38  public abstract class AbstractMapItem<VALUE extends ICollectionValue>
39      extends ImmutableCollections.AbstractImmutableDelegatedMap<IMapKey, VALUE>
40      implements IMapItem<VALUE> {
41    /**
42     * The function qualified name.
43     */
44    @NonNull
45    private static final IEnhancedQName QNAME = IEnhancedQName.of("map");
46    /**
47     * The function properties.
48     */
49    @NonNull
50    private static final Set<FunctionProperty> PROPERTIES = ObjectUtils.notNull(
51        EnumSet.of(FunctionProperty.DETERMINISTIC));
52    /**
53     * The function arguments.
54     */
55    @NonNull
56    private static final List<IArgument> ARGUMENTS = ObjectUtils.notNull(List.of(
57        IArgument.builder().name("key").type(IAnyAtomicItem.type()).one().build()));
58    @NonNull
59    private static final ISequenceType RESULT = ISequenceType.of(
60        IAnyAtomicItem.type(), Occurrence.ZERO_OR_ONE);
61  
62    @NonNull
63    private static final IMapItem<?> EMPTY = new MapItemN<>();
64  
65    /**
66     * Get an immutable map item that is empty.
67     *
68     * @param <V>
69     *          the Java type of the collection value
70     * @return the empty map item
71     */
72  
73    @SuppressWarnings("unchecked")
74    @NonNull
75    public static <V extends ICollectionValue> IMapItem<V> empty() {
76      return (IMapItem<V>) EMPTY;
77    }
78  
79    @Override
80    public boolean isDeterministic() {
81      return true;
82    }
83  
84    @Override
85    public boolean isContextDepenent() {
86      return false;
87    }
88  
89    @Override
90    public boolean isFocusDepenent() {
91      return false;
92    }
93  
94    @Override
95    public IEnhancedQName getQName() {
96      return QNAME;
97    }
98  
99    @Override
100   public Set<FunctionProperty> getProperties() {
101     return PROPERTIES;
102   }
103 
104   @Override
105   public List<IArgument> getArguments() {
106     return ARGUMENTS;
107   }
108 
109   @Override
110   public int arity() {
111     return 1;
112   }
113 
114   @Override
115   public boolean isArityUnbounded() {
116     return false;
117   }
118 
119   @Override
120   public ISequenceType getResult() {
121     return RESULT;
122   }
123 
124   @Override
125   public ISequence<?> execute(List<? extends ISequence<?>> arguments, DynamicContext dynamicContext,
126       ISequence<?> focus) {
127     ISequence<? extends IIntegerItem> arg = FunctionUtils.asType(
128         ObjectUtils.notNull(arguments.get(0)));
129 
130     IAnyAtomicItem key = arg.getFirstItem(true);
131     if (key == null) {
132       return ISequence.empty(); // NOPMD - readability
133     }
134 
135     ICollectionValue result = MapGet.get(this, key);
136     return result == null ? ISequence.empty() : result.toSequence();
137   }
138 
139   @Override
140   public int hashCode() {
141     return Objects.hash(getValue());
142   }
143 
144   @Override
145   public boolean equals(Object other) {
146     return other == this
147         || other instanceof IMapItem && getValue().equals(((IMapItem<?>) other).getValue());
148   }
149 
150   @Override
151   public String toSignature() {
152     return ObjectUtils.notNull(entrySet().stream()
153         .map(entry -> entry.getKey().getKey().toSignature() + "=" + entry.getValue().toSignature())
154         .collect(Collectors.joining(",", "[", "]")));
155   }
156 
157   @Override
158   public String toString() {
159     return toSignature();
160   }
161 }