1 package com.atlassian.plugins.rest.common.expand.parameter;
2
3 import com.atlassian.annotations.tenancy.TenantAware;
4 import com.atlassian.plugins.rest.common.expand.Expandable;
5 import com.google.common.base.Preconditions;
6 import com.google.common.collect.Maps;
7 import com.google.common.collect.Sets;
8 import org.apache.commons.lang.StringUtils;
9
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.HashSet;
13 import java.util.Map;
14 import java.util.regex.Matcher;
15 import java.util.regex.Pattern;
16
17 import static com.atlassian.annotations.tenancy.TenancyScope.SUPPRESS;
18
19
20
21
22 public final class DefaultExpandParameter implements ExpandParameter {
23 private static final String DOT = ".";
24 private static final String COMMA = ",";
25 private static final String WILDCARD = "*";
26
27 private static final ExpandParameter EMPTY_EXPAND_PARAMETER = new DefaultExpandParameter((String) null);
28
29 @TenantAware(SUPPRESS)
30 private final Map<String, ExpandInformation> parameters;
31
32 private DefaultExpandParameter(String expand) {
33 this(StringUtils.isNotBlank(expand) ? Collections.singleton(expand) : Collections.<String>emptyList());
34 }
35
36 private DefaultExpandParameter() {
37 parameters = Maps.newHashMap();
38 }
39
40 public DefaultExpandParameter(Collection<String> expands) {
41 parameters = parse(expands != null ? expands : Collections.<String>emptyList());
42 }
43
44 public boolean shouldExpand(Expandable expandable) {
45 return parameters.containsKey(WILDCARD) || parameters.containsKey(Preconditions.checkNotNull(expandable).value());
46 }
47
48 public Indexes getIndexes(Expandable expandable) {
49 final ExpandInformation expandInformation = parameters.get(Preconditions.checkNotNull(expandable).value());
50 return expandInformation != null ? expandInformation.getIndexes() : IndexParser.EMPTY;
51 }
52
53 public ExpandParameter getExpandParameter(Expandable expandable) {
54 final ExpandInformation wildcardExpandInformation = parameters.get(WILDCARD);
55 final ExpandInformation valueExpandInformation = parameters.get(Preconditions.checkNotNull(expandable).value());
56
57 return new ChainingExpandParameter(
58 wildcardExpandInformation != null ? wildcardExpandInformation.getExpandParameter() : EMPTY_EXPAND_PARAMETER,
59 valueExpandInformation != null ? valueExpandInformation.getExpandParameter() : EMPTY_EXPAND_PARAMETER);
60 }
61
62 public boolean isEmpty() {
63 return parameters.isEmpty();
64 }
65
66 private static void appendParam(Map<String, ExpandInformation> parameters, String expand) {
67 final ExpandKey key = ExpandKey.from(StringUtils.substringBefore(expand, DOT));
68 String newParameter = StringUtils.substringAfter(expand, DOT);
69 DefaultExpandParameter existingParameter = null;
70 if (parameters.containsKey(key.getName())) {
71 existingParameter = parameters.get(key.getName()).getExpandParameter();
72 } else {
73 existingParameter = new DefaultExpandParameter();
74 parameters.put(key.getName(), new ExpandInformation(key.getIndexes(), existingParameter));
75 }
76
77 if (StringUtils.isNotBlank(newParameter)) {
78 appendParam(existingParameter.parameters, newParameter);
79 }
80 }
81
82 private static Map<String, ExpandInformation> parse(Collection<String> expands) {
83 final Map<String, ExpandInformation> parameters = Maps.newHashMap();
84 for (String expand : preProcess(expands)) {
85 if (StringUtils.isNotEmpty(expand)) {
86 appendParam(parameters, expand);
87 }
88 }
89 return parameters;
90 }
91
92 private static Collection<String> preProcess(Collection<String> expands) {
93 final Collection<String> preProcessed = new HashSet<String>();
94 for (String expand : expands) {
95 preProcessed.addAll(Sets.newHashSet(expand.split(COMMA)));
96 }
97 return preProcessed;
98 }
99
100 private static class ExpandKey {
101 private static final Pattern KEY_PATTERN = Pattern.compile("(\\w+|\\*)(?:\\[([\\d:\\-\\|]+)\\])?");
102
103 private final String name;
104 private final Indexes indexes;
105
106 ExpandKey(String name, Indexes indexes) {
107 this.name = name;
108 this.indexes = indexes;
109 }
110
111 public String getName() {
112 return name;
113 }
114
115 public Indexes getIndexes() {
116 return indexes;
117 }
118
119 private static ExpandKey from(String key) {
120 final Matcher keyMatcher = KEY_PATTERN.matcher(key);
121 if (!keyMatcher.matches()) {
122 throw new RuntimeException("key <" + key + "> doesn't match pattern");
123 }
124
125 final String name = keyMatcher.group(1);
126 final String indexesString = keyMatcher.group(2);
127 return new ExpandKey(name, IndexParser.parse(indexesString));
128 }
129 }
130
131 private static class ExpandInformation {
132 private final Indexes indexes;
133 private final DefaultExpandParameter expandParameter;
134
135 public ExpandInformation(Indexes indexes, DefaultExpandParameter expandParameter) {
136 this.indexes = Preconditions.checkNotNull(indexes);
137 this.expandParameter = Preconditions.checkNotNull(expandParameter);
138 }
139
140 public Indexes getIndexes() {
141 return indexes;
142 }
143
144 public DefaultExpandParameter getExpandParameter() {
145 return expandParameter;
146 }
147 }
148 }