1 package com.atlassian.plugin.util.validation;
2
3 import org.dom4j.Node;
4 import org.apache.commons.lang.Validate;
5
6 import java.util.ArrayList;
7 import java.util.List;
8
9
10
11
12
13
14
15 public class ValidationPattern
16 {
17 private final List<Rule> rules = new ArrayList<Rule>();
18
19 private ValidationPattern() {
20 }
21
22
23
24
25 public static ValidationPattern createPattern()
26 {
27 return new ValidationPattern();
28 }
29
30
31
32
33
34
35
36 public ValidationPattern rule(String context, RuleTest... tests)
37 {
38 rules.add(new Rule(context, tests));
39 return this;
40 }
41
42
43
44
45
46
47 public ValidationPattern rule(RuleTest... tests)
48 {
49 rules.add(new Rule(".", tests));
50 return this;
51 }
52
53
54
55
56
57
58
59 public void evaluate(Node node) throws ValidationException
60 {
61 List<String> errors = new ArrayList<String>();
62 for (Rule rule : rules)
63 {
64 rule.evaluate(node, errors);
65 }
66 if (!errors.isEmpty())
67 {
68 if (errors.size() == 1)
69 {
70 throw new ValidationException(errors.get(0), errors);
71 }
72 else
73 {
74 StringBuilder sb = new StringBuilder();
75 sb.append("There were validation errors:\n");
76 for (String msg : errors)
77 {
78 sb.append("\t- ").append(msg).append("\n");
79 }
80 throw new ValidationException(sb.toString(), errors);
81 }
82 }
83 }
84
85
86
87
88
89
90 public static RuleTest test(String xpath)
91 {
92 return new RuleTest(xpath);
93 }
94
95
96
97
98 public static class RuleTest
99 {
100 private final String xpath;
101 private String errorMessage;
102
103 private RuleTest(String xpath)
104 {
105 Validate.notNull(xpath);
106 this.xpath = xpath;
107 }
108
109
110
111
112
113
114 public RuleTest withError(String msg)
115 {
116 this.errorMessage = msg;
117 return this;
118 }
119
120 private void evaluate(Node ctxNode, List<String> errors)
121 {
122 Object obj = ctxNode.selectObject(xpath);
123 if (obj == null)
124 {
125 errors.add(errorMessage + ": " + ctxNode.asXML());
126 }
127 else if (obj instanceof Boolean && !((Boolean)obj))
128 {
129 errors.add(errorMessage + ": " + ctxNode.asXML());
130 }
131 else if (obj instanceof List && ((List<?>)obj).isEmpty())
132 {
133 errors.add(errorMessage + ": " + ctxNode.asXML());
134 }
135 }
136 }
137
138
139
140
141 public static class Rule
142 {
143 private final String contextPattern;
144 private final RuleTest[] tests;
145
146 private Rule(String contextPattern, RuleTest[] tests)
147 {
148 Validate.notNull(contextPattern);
149 Validate.notNull(tests);
150 this.contextPattern = contextPattern;
151 this.tests = tests;
152 }
153
154 private void evaluate(Node e, List<String> errors)
155 {
156 @SuppressWarnings("unchecked")
157 List<Node> contexts = e.selectNodes(contextPattern);
158
159 if (contexts != null && contexts.size() > 0)
160 {
161 for (Node ctxNode : contexts)
162 {
163 for (RuleTest test : tests)
164 {
165 test.evaluate(ctxNode, errors);
166 }
167 }
168 }
169 }
170 }
171
172 }