1 package com.atlassian.plugins.rest.doclet.generators.schema;
2
3 import com.atlassian.annotations.tenancy.TenantAware;
4 import com.google.common.base.Function;
5 import com.google.common.base.Joiner;
6 import com.google.common.base.Objects;
7 import com.google.common.base.Splitter;
8 import com.google.common.collect.ImmutableList;
9 import com.google.common.collect.ImmutableMap;
10 import com.google.common.collect.Iterables;
11 import com.google.common.collect.Lists;
12 import com.google.common.collect.Maps;
13 import org.codehaus.jackson.annotate.JsonAutoDetect;
14 import org.codehaus.jackson.annotate.JsonProperty;
15
16 import java.util.Arrays;
17 import java.util.List;
18 import java.util.Map;
19
20 import static com.atlassian.annotations.tenancy.TenancyScope.SUPPRESS;
21 import static com.atlassian.annotations.tenancy.TenancyScope.TENANTLESS;
22
23 @JsonAutoDetect
24 public class Schema
25 {
26 public enum Type
27 {
28 Any, Object, Array, Number, Integer, Boolean, String, Uri("string", "uri");
29
30 private final String name;
31 private final String format;
32
33 Type(final java.lang.String name, final java.lang.String format)
34 {
35 this.name = name;
36 this.format = format;
37 }
38
39 Type()
40 {
41 this(null, null);
42 }
43
44 @Override
45 public String toString()
46 {
47 return Objects.firstNonNull(name, this.name().toLowerCase());
48 }
49
50 public java.lang.String format()
51 {
52 return format;
53 }
54 }
55
56 private final String $ref;
57 private final String id;
58 private final String title;
59 private final String description;
60 private final String type;
61 private final String format;
62 @TenantAware(TENANTLESS)
63 private final Map<String, Schema> properties;
64 private final Schema items;
65 @JsonProperty ("enum")
66 private final List<String> _enum;
67
68 @TenantAware(TENANTLESS)
69 private final Map<String, Schema> patternProperties;
70 private final List<Schema> anyOf;
71
72 @TenantAware(TENANTLESS)
73 private final Map<String, Schema> definitions;
74 private Boolean additionalProperties;
75 private final List<String> required;
76
77 private Schema(final String $ref, final String id, String title, String description, Type type, Map<String, Schema> properties, Schema items, Iterable<String> _enum, Iterable<String> required, Map<String, Schema> patternProperties, final Map<String, Schema> definitions, final List<Schema> anyOf)
78 {
79 this.$ref = $ref;
80 this.id = id;
81 this.title = title;
82 this.description = description;
83 this.type = type != null && type != Type.Any ? type.toString() : null;
84 this.format = this.type != null ? type.format() : null;
85 this.anyOf = anyOf != null && anyOf.size() > 0 ? ImmutableList.copyOf(anyOf) : null;
86 this.properties = properties != null && properties.size() > 0
87 ? ImmutableMap.copyOf(properties)
88 : null;
89 this.items = items;
90 this._enum = _enum != null && Iterables.size(_enum) > 0 ? ImmutableList.copyOf(_enum) : null;
91 this.required = required != null && Iterables.size(required) > 0 ? ImmutableList.copyOf(required) : null;
92 this.patternProperties = patternProperties != null && patternProperties.size() > 0
93 ? ImmutableMap.copyOf(patternProperties)
94 : null;
95 this.definitions = definitions != null && definitions.size() > 0
96 ? ImmutableMap.copyOf(definitions)
97 : null;
98 this.additionalProperties = type != null && type == Type.Object &&
99 (this.properties != null || this.patternProperties != null) ? false : null;
100 }
101
102 public static Schema ref(String title)
103 {
104 return new Schema("#/definitions/" + titleToId(title), null, null, null, null, null, null, null, null, null, null, null);
105 }
106
107 public static String titleToId(final String title)
108 {
109 return title != null ? Joiner.on("-").join(Splitter.on(" ").split(title)).toLowerCase() : null;
110 }
111
112 public String get$ref()
113 {
114 return $ref;
115 }
116
117 public String getId()
118 {
119 return id;
120 }
121
122 public String getTitle()
123 {
124 return title;
125 }
126
127 public String getDescription()
128 {
129 return description;
130 }
131
132 public String getType()
133 {
134 return type;
135 }
136
137 public String getFormat()
138 {
139 return format;
140 }
141
142 public Map<String, Schema> getProperties()
143 {
144 return properties;
145 }
146
147 public Schema getItems()
148 {
149 return items;
150 }
151
152 public List<String> get_enum()
153 {
154 return _enum;
155 }
156
157 public Map<String, Schema> getPatternProperties()
158 {
159 return patternProperties;
160 }
161
162 public List<Schema> getAnyOf()
163 {
164 return anyOf;
165 }
166
167 public Map<String, Schema> getDefinitions()
168 {
169 return definitions;
170 }
171
172 public Boolean getAdditionalProperties()
173 {
174 return additionalProperties;
175 }
176
177 public List<String> getRequired()
178 {
179 return required;
180 }
181
182 public static Builder builder()
183 {
184 return new Builder();
185 }
186
187 @Override
188 public boolean equals(Object o)
189 {
190 if (this == o) { return true; }
191 if (o == null || getClass() != o.getClass()) { return false; }
192
193 Schema that = (Schema) o;
194
195 return Objects.equal(this.title, that.title) &&
196 Objects.equal(this.description, that.description) &&
197 Objects.equal(this.type, that.type) &&
198 Objects.equal(this.properties, that.properties) &&
199 Objects.equal(this.items, that.items) &&
200 Objects.equal(this._enum, that._enum) &&
201 Objects.equal(this.required, that.required);
202 }
203
204 @Override
205 public int hashCode()
206 {
207 return Objects.hashCode(title, description, type, properties, items, _enum, required);
208 }
209
210 @Override
211 public String toString()
212 {
213 return Objects.toStringHelper(this)
214 .add("title", title)
215 .add("description", description)
216 .add("type", type)
217 .add("properties", properties)
218 .add("items", items)
219 .add("enum", _enum)
220 .add("required", required)
221 .toString();
222 }
223
224 public static final class Builder
225 {
226 private String id;
227 private String title;
228 private String description;
229 private Type type;
230
231 @TenantAware(SUPPRESS)
232 private Map<String, Schema> properties = Maps.newLinkedHashMap();
233
234 @TenantAware(SUPPRESS)
235 private Map<String, Schema> patternProperties = Maps.newLinkedHashMap();
236 private Schema items;
237 private List<String> _enum = Lists.newArrayList();
238 private List<String> required = Lists.newArrayList();
239
240 @TenantAware(SUPPRESS)
241 private Map<String, Schema> definitions = Maps.newTreeMap();
242 private List<Schema> anyOf = Lists.newArrayList();
243
244 private Builder() {}
245
246 public Builder setId(String id)
247 {
248 this.id = id;
249 return this;
250 }
251
252 public Builder setTitle(String title)
253 {
254 this.title = title;
255 return this;
256 }
257
258 public Builder setDescription(String description)
259 {
260 this.description = description;
261 return this;
262 }
263
264 public Builder setType(Type type)
265 {
266 this.type = type;
267 return this;
268 }
269
270 public Builder setProperties(Map<String, Schema> properties)
271 {
272 this.properties = properties;
273 return this;
274 }
275
276 public Builder addProperty(String propertyName, Schema propertySchema)
277 {
278 this.properties.put(propertyName, propertySchema);
279 return this;
280 }
281
282 public Builder addPatternProperty(String pattern, Schema schema)
283 {
284 this.patternProperties.put(pattern, schema);
285 return this;
286 }
287
288 public Builder setItems(Schema items)
289 {
290 this.items = items;
291 return this;
292 }
293
294 public <T extends Enum<T>> Builder setEnum(Class<T> enumType)
295 {
296 this._enum = ImmutableList.copyOf(Iterables.transform(Arrays.asList(enumType.getEnumConstants()), new Function<T, String>()
297 {
298 @Override
299 public String apply(final T input)
300 {
301 return input.toString();
302 }
303 }));
304 return this;
305 }
306
307 public Builder setRequired(List<String> required)
308 {
309 this.required = required;
310 return this;
311 }
312
313 public Builder addRequired(String required)
314 {
315 this.required.add(required);
316 return this;
317 }
318
319 public Builder addDefinition(Schema schema)
320 {
321 this.definitions.put(titleToId(schema.getTitle()), schema);
322 return this;
323 }
324
325 public Builder addAnyOf(Schema schema)
326 {
327 this.anyOf.add(schema);
328 return this;
329 }
330
331 public Schema build()
332 {
333 return new Schema(null, id, title, description, type, properties, items, _enum, required, patternProperties, definitions, anyOf);
334 }
335 }
336 }