1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.api.jackson;
18
19 import static org.forgerock.api.jackson.JacksonUtils.OBJECT_MAPPER;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import javax.validation.ValidationException;
28
29 import org.forgerock.api.enums.ReadPolicy;
30 import org.forgerock.json.JsonValue;
31
32 import com.fasterxml.jackson.databind.JavaType;
33 import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
34 import com.fasterxml.jackson.module.jsonSchema.types.ArraySchema;
35 import org.forgerock.api.enums.WritePolicy;
36
37
38
39
40 public class CrestArraySchema extends ArraySchema implements CrestReadWritePoliciesSchema, OrderedFieldSchema,
41 ValidatableSchema, WithExampleSchema<List<Object>> {
42 private static final JavaType EXAMPLE_VALUE_TYPE = OBJECT_MAPPER.getTypeFactory()
43 .constructParametrizedType(ArrayList.class, List.class, Object.class);
44
45 private WritePolicy writePolicy;
46 private ReadPolicy readPolicy;
47 private Boolean errorOnWritePolicyFailure;
48 private Boolean returnOnDemand;
49 private Integer propertyOrder;
50 private List<Object> example;
51
52 @Override
53 public WritePolicy getWritePolicy() {
54 return writePolicy;
55 }
56
57 @Override
58 public void setWritePolicy(WritePolicy policy) {
59 this.writePolicy = policy;
60 }
61
62 @Override
63 public ReadPolicy getReadPolicy() {
64 return readPolicy;
65 }
66
67 @Override
68 public void setReadPolicy(ReadPolicy readPolicy) {
69 this.readPolicy = readPolicy;
70 }
71
72 @Override
73 public Boolean getErrorOnWritePolicyFailure() {
74 return errorOnWritePolicyFailure;
75 }
76
77 @Override
78 public void setErrorOnWritePolicyFailure(Boolean errorOnWritePolicyFailure) {
79 this.errorOnWritePolicyFailure = errorOnWritePolicyFailure;
80 }
81
82 @Override
83 public Boolean getReturnOnDemand() {
84 return returnOnDemand;
85 }
86
87 @Override
88 public void setReturnOnDemand(Boolean returnOnDemand) {
89 this.returnOnDemand = returnOnDemand;
90 }
91
92 @Override
93 public Integer getPropertyOrder() {
94 return propertyOrder;
95 }
96
97 @Override
98 public void setPropertyOrder(Integer order) {
99 this.propertyOrder = order;
100 }
101
102 @Override
103 public void validate(JsonValue object) throws ValidationException {
104 if (!object.isCollection()) {
105 throw new ValidationException("Array expected, but got: " + object.getObject());
106 }
107 if (maxItems != null && object.size() > maxItems) {
108 throw new ValidationException("Array has too many items. Maximum permitted: " + maxItems);
109 }
110 if (minItems != null && object.size() < minItems) {
111 throw new ValidationException("Array has too few items. Minimum permitted: " + minItems);
112 }
113 if (items.isSingleItems()) {
114 if (items.asSingleItems().getSchema() instanceof ValidatableSchema) {
115 ValidatableSchema itemSchema = (ValidatableSchema) items.asSingleItems().getSchema();
116 for (JsonValue item : object) {
117 itemSchema.validate(item);
118 }
119 }
120 } else {
121 Iterator<JsonValue> arrayItems = object.iterator();
122 for (JsonSchema itemSchema : items.asArrayItems().getJsonSchemas()) {
123 if (!arrayItems.hasNext()) {
124 throw new ValidationException("Not enough items. Expecting " + itemSchema);
125 }
126 if (itemSchema instanceof ValidatableSchema) {
127 ((ValidatableSchema) itemSchema).validate(arrayItems.next());
128 }
129 }
130 }
131 }
132
133 @Override
134 public List<Object> getExample() {
135 List<Object> example = this.example;
136 if (example == null) {
137 example = new ArrayList<>();
138 boolean foundExample = items.isSingleItems()
139 ? applySingleSchemaExample(example)
140 : applyMultipleSchemasExamples(example);
141 if (!foundExample) {
142 example = null;
143 }
144 }
145 return example;
146 }
147
148 private boolean applySingleSchemaExample(List<Object> example) {
149 boolean foundExample = false;
150 if (items.asSingleItems().getSchema() instanceof WithExampleSchema) {
151 Object itemsExample = ((WithExampleSchema) items.asSingleItems().getSchema()).getExample();
152 if (itemsExample != null) {
153 int count = minItems != null && minItems > 1 ? minItems : 1;
154 foundExample = true;
155 for (int i = 0; i < count; i++) {
156 example.add(itemsExample);
157 }
158 }
159 }
160 return foundExample;
161 }
162
163 private boolean applyMultipleSchemasExamples(List<Object> example) {
164 boolean foundExample = false;
165 for (JsonSchema schema : items.asArrayItems().getJsonSchemas()) {
166 if (schema instanceof WithExampleSchema) {
167 Object propertyExample = ((WithExampleSchema) schema).getExample();
168 if (propertyExample != null) {
169 foundExample = true;
170 example.add(propertyExample);
171 } else {
172 example.add(new HashMap<>());
173 }
174 }
175 }
176 return foundExample;
177 }
178
179 @Override
180 public void setExample(String example) throws IOException {
181 this.example = OBJECT_MAPPER.readValue(example, EXAMPLE_VALUE_TYPE);
182 }
183 }