1
2
3
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.function.FunctionUtils;
10 import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
11 import gov.nist.secauto.metaschema.core.metapath.function.library.MapGet;
12 import gov.nist.secauto.metaschema.core.metapath.item.ICollectionValue;
13 import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
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.qname.IEnhancedQName;
19 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
20
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.stream.Collectors;
26
27 import edu.umd.cs.findbugs.annotations.NonNull;
28
29
30
31
32
33
34
35
36 public abstract class AbstractMapItem<VALUE extends ICollectionValue>
37 extends ImmutableCollections.AbstractImmutableDelegatedMap<IMapKey, VALUE>
38 implements IMapItem<VALUE>, IFeatureCollectionFunctionItem {
39
40
41
42 @NonNull
43 private static final IEnhancedQName QNAME = IEnhancedQName.of("map");
44
45
46
47 @NonNull
48 private static final List<IArgument> ARGUMENTS = ObjectUtils.notNull(List.of(
49 IArgument.builder().name("key").type(IAnyAtomicItem.type()).one().build()));
50 @NonNull
51 private static final IMapItem<?> EMPTY = new MapItemN<>();
52
53
54
55
56
57
58
59
60
61 @SuppressWarnings("unchecked")
62 @NonNull
63 public static <V extends ICollectionValue> IMapItem<V> empty() {
64 return (IMapItem<V>) EMPTY;
65 }
66
67 @Override
68 public IEnhancedQName getQName() {
69 return QNAME;
70 }
71
72 @Override
73 public List<IArgument> getArguments() {
74 return ARGUMENTS;
75 }
76
77 @Override
78 public ISequence<?> execute(List<? extends ISequence<?>> arguments, DynamicContext dynamicContext,
79 ISequence<?> focus) {
80 ISequence<? extends IIntegerItem> arg = FunctionUtils.asType(
81 ObjectUtils.notNull(arguments.get(0)));
82
83 IAnyAtomicItem key = arg.getFirstItem(true);
84 if (key == null) {
85 return ISequence.empty();
86 }
87
88 ICollectionValue result = MapGet.get(this, key);
89 return result == null ? ISequence.empty() : result.toSequence();
90 }
91
92 @Override
93 public int hashCode() {
94 return Objects.hash(getValue());
95 }
96
97 @Override
98 public boolean equals(Object other) {
99 return other == this
100 || other instanceof IMapItem && getValue().equals(((IMapItem<?>) other).getValue());
101 }
102
103 @SuppressWarnings("PMD.OnlyOneReturn")
104 @Override
105 public boolean deepEquals(ICollectionValue other, DynamicContext dynamicContext) {
106 if (!(other instanceof IMapItem)) {
107 return false;
108 }
109
110 IMapItem<?> otherItem = (IMapItem<?>) other;
111 if (size() != otherItem.size()) {
112 return false;
113 }
114
115 Iterator<Map.Entry<IMapKey, VALUE>> thisIterator = entrySet().iterator();
116 Iterator<? extends Map.Entry<IMapKey, ? extends ICollectionValue>> otherIterator = otherItem.entrySet().iterator();
117 boolean retval = true;
118 while (thisIterator.hasNext() && otherIterator.hasNext()) {
119 Map.Entry<IMapKey, ? extends ICollectionValue> i1 = thisIterator.next();
120 Map.Entry<IMapKey, ? extends ICollectionValue> i2 = otherIterator.next();
121
122 retval = i1.getKey().isSameKey(ObjectUtils.notNull(i2.getKey()))
123 && i1.getValue().deepEquals(i2.getValue(), dynamicContext);
124 if (!retval) {
125 break;
126 }
127 }
128 return retval;
129 }
130
131 @Override
132 public String toSignature() {
133 return ObjectUtils.notNull(entrySet().stream()
134 .map(entry -> entry.getKey().getKey().toSignature() + "=" + entry.getValue().toSignature())
135 .collect(Collectors.joining(",", "[", "]")));
136 }
137
138 @Override
139 public String toString() {
140 return toSignature();
141 }
142 }