1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
5  * the License. A copy of the License is located at
6  *
7  * http://aws.amazon.com/apache2.0
8  *
9  * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10  * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11  * and limitations under the License.
12  */
13 
14 package software.amazon.awssdk.services.kms.endpoints.internal;
15 
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.stream.Collectors;
21 import software.amazon.awssdk.annotations.SdkInternalApi;
22 import software.amazon.awssdk.core.exception.SdkClientException;
23 import software.amazon.awssdk.protocols.jsoncore.JsonNode;
24 
25 @SdkInternalApi
26 public class Literal extends Expr {
27     public interface Visitor<T> {
28 
visitBool(boolean b)29         T visitBool(boolean b);
30 
visitStr(Template value)31         T visitStr(Template value);
32 
visitObject(Map<Identifier, Literal> members)33         T visitObject(Map<Identifier, Literal> members);
34 
visitTuple(List<Literal> members)35         T visitTuple(List<Literal> members);
36 
visitInt(int value)37         T visitInt(int value);
38     }
39 
40     private final Lit source;
41 
Literal(Lit source)42     private Literal(Lit source) {
43         this.source = source;
44     }
45 
accept(Visitor<T> visitor)46     public <T> T accept(Visitor<T> visitor) {
47         return this.source.accept(visitor);
48     }
49 
expectLiteralString()50     public String expectLiteralString() {
51         if (source instanceof Str) {
52             Str s = (Str) source;
53 
54             return s.value.expectLiteral();
55         } else {
56             throw RuleError.builder()
57                     .cause(SourceException.builder().message("Expected a literal string, got " + source).build()).build();
58         }
59     }
60 
61     @Override
accept(ExprVisitor<R> visitor)62     public <R> R accept(ExprVisitor<R> visitor) {
63         return visitor.visitLiteral(this);
64     }
65 
66     @Override
eval(Scope<Value> scope)67     public Value eval(Scope<Value> scope) {
68         return source.accept(new Visitor<Value>() {
69             @Override
70             public Value visitInt(int value) {
71                 return Value.fromInteger(value);
72             }
73 
74             @Override
75             public Value visitBool(boolean b) {
76                 return Value.fromBool(b);
77             }
78 
79             @Override
80             public Value visitStr(Template value) {
81                 return value.eval(scope);
82             }
83 
84             @Override
85             public Value visitObject(Map<Identifier, Literal> members) {
86                 Map<Identifier, Value> tpe = new HashMap<>();
87                 members.forEach((k, v) -> {
88                     tpe.put(k, v.eval(scope));
89                 });
90                 return Value.fromRecord(tpe);
91             }
92 
93             @Override
94             public Value visitTuple(List<Literal> members) {
95                 List<Value> tuples = new ArrayList<>();
96                 for (Literal el : ((Tuple) source).members) {
97                     tuples.add(el.eval(scope));
98                 }
99                 return Value.fromArray(tuples);
100             }
101         });
102     }
103 
104     @Override
105     public boolean equals(Object o) {
106         if (this == o) {
107             return true;
108         }
109         if (o == null || getClass() != o.getClass()) {
110             return false;
111         }
112         if (!super.equals(o)) {
113             return false;
114         }
115 
116         Literal literal = (Literal) o;
117 
118         return source != null ? source.equals(literal.source) : literal.source == null;
119     }
120 
121     @Override
122     public int hashCode() {
123         return source != null ? source.hashCode() : 0;
124     }
125 
126     public String toString() {
127         return source.toString();
128     }
129 
130     public static Literal fromNode(JsonNode node) {
131         Lit lit;
132         if (node.isArray()) {
133             List<Literal> array = node.asArray().stream().map(Literal::fromNode).collect(Collectors.toList());
134             lit = new Tuple(array);
135         } else if (node.isBoolean()) {
136             lit = new Bool(node.asBoolean());
137         } else if (node.isNull()) {
138             throw SdkClientException.create("null node not supported");
139         } else if (node.isNumber()) {
140             lit = new Int(Integer.parseInt(node.asNumber()));
141         } else if (node.isObject()) {
142             Map<Identifier, Literal> obj = new HashMap<>();
143             node.asObject().forEach((k, v) -> obj.put(Identifier.of(k), fromNode(v)));
144             lit = new Obj(obj);
145         } else if (node.isString()) {
146             lit = new Str(new Template(node.asString()));
147         } else {
148             throw SdkClientException.create("Unable to create literal from " + node);
149         }
150         return new Literal(lit);
151     }
152 
153     public static Literal fromTuple(List<Literal> authSchemes) {
154         return new Literal(new Tuple(authSchemes));
155     }
156 
157     public static Literal fromRecord(Map<Identifier, Literal> record) {
158         return new Literal(new Obj(record));
159     }
160 
161     public static Literal fromStr(Template value) {
162         return new Literal(new Str(value));
163     }
164 
165     public static Literal fromStr(String s) {
166         return fromStr(new Template(s));
167     }
168 
169     public static Literal fromInteger(int value) {
170         return new Literal(new Int(value));
171     }
172 
173     public static Literal fromBool(boolean value) {
174         return new Literal(new Bool(value));
175     }
176 
177     private interface Lit {
178         <T> T accept(Visitor<T> visitor);
179     }
180 
181     static final class Int implements Lit {
182         private final Integer value;
183 
184         Int(Integer value) {
185             this.value = value;
186         }
187 
188         @Override
189         public <T> T accept(Visitor<T> visitor) {
190             return visitor.visitInt(value);
191         }
192 
193         @Override
194         public String toString() {
195             return Integer.toString(value);
196         }
197 
198         @Override
199         public boolean equals(Object o) {
200             if (this == o) {
201                 return true;
202             }
203             if (o == null || getClass() != o.getClass()) {
204                 return false;
205             }
206 
207             Int anInt = (Int) o;
208 
209             return value != null ? value.equals(anInt.value) : anInt.value == null;
210         }
211 
212         @Override
213         public int hashCode() {
214             return value != null ? value.hashCode() : 0;
215         }
216     }
217 
218     static final class Tuple implements Lit {
219         private final List<Literal> members;
220 
221         Tuple(List<Literal> members) {
222             this.members = members;
223         }
224 
225         @Override
226         public <T> T accept(Visitor<T> visitor) {
227             return visitor.visitTuple(members);
228         }
229 
230         @Override
231         public String toString() {
232             return members.stream().map(Literal::toString).collect(Collectors.joining(", ", "[", "]"));
233         }
234 
235         public List<Literal> members() {
236             return members;
237         }
238 
239         @Override
240         public boolean equals(Object o) {
241             if (this == o) {
242                 return true;
243             }
244             if (o == null || getClass() != o.getClass()) {
245                 return false;
246             }
247 
248             Tuple tuple = (Tuple) o;
249 
250             return members != null ? members.equals(tuple.members) : tuple.members == null;
251         }
252 
253         @Override
254         public int hashCode() {
255             return members != null ? members.hashCode() : 0;
256         }
257     }
258 
259     static final class Obj implements Lit {
260         private final Map<Identifier, Literal> members;
261 
262         Obj(Map<Identifier, Literal> members) {
263             this.members = members;
264         }
265 
266         @Override
267         public <T> T accept(Visitor<T> visitor) {
268             return visitor.visitObject(members);
269         }
270 
271         @Override
272         public String toString() {
273             return members.toString();
274         }
275 
276         public Map<Identifier, Literal> members() {
277             return members;
278         }
279 
280         @Override
281         public boolean equals(Object o) {
282             if (this == o) {
283                 return true;
284             }
285             if (o == null || getClass() != o.getClass()) {
286                 return false;
287             }
288 
289             Obj obj = (Obj) o;
290 
291             return members != null ? members.equals(obj.members) : obj.members == null;
292         }
293 
294         @Override
295         public int hashCode() {
296             return members != null ? members.hashCode() : 0;
297         }
298     }
299 
300     static final class Bool implements Lit {
301         private final boolean value;
302 
303         Bool(boolean value) {
304             this.value = value;
305         }
306 
307         @Override
308         public <T> T accept(Visitor<T> visitor) {
309             return visitor.visitBool(value);
310         }
311 
312         @Override
313         public String toString() {
314             return Boolean.toString(value);
315         }
316 
317         public Boolean value() {
318             return value;
319         }
320 
321         @Override
322         public boolean equals(Object o) {
323             if (this == o) {
324                 return true;
325             }
326             if (o == null || getClass() != o.getClass()) {
327                 return false;
328             }
329 
330             Bool bool = (Bool) o;
331 
332             return value == bool.value;
333         }
334 
335         @Override
336         public int hashCode() {
337             return value ? 1 : 0;
338         }
339     }
340 
341     static final class Str implements Lit {
342         private final Template value;
343 
344         Str(Template value) {
345             this.value = value;
346         }
347 
348         @Override
349         public <T> T accept(Visitor<T> visitor) {
350             return visitor.visitStr(value);
351         }
352 
353         @Override
354         public String toString() {
355             return value.toString();
356         }
357 
358         public Template value() {
359             return value;
360         }
361 
362         @Override
363         public boolean equals(Object o) {
364             if (this == o) {
365                 return true;
366             }
367             if (o == null || getClass() != o.getClass()) {
368                 return false;
369             }
370 
371             Str str = (Str) o;
372 
373             return value != null ? value.equals(str.value) : str.value == null;
374         }
375 
376         @Override
377         public int hashCode() {
378             return value != null ? value.hashCode() : 0;
379         }
380     }
381 }
382