1
2
3
4
5
6
7
8
9
10
11
12 package org.hyphenType.optionprocessors.lib;
13
14 import java.lang.annotation.ElementType;
15 import java.lang.annotation.Retention;
16 import java.lang.annotation.RetentionPolicy;
17 import java.lang.annotation.Target;
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Method;
20
21 import javax.script.ScriptEngine;
22 import javax.script.ScriptEngineManager;
23 import javax.script.ScriptException;
24
25 import org.hyphenType.datastructure.Options;
26 import org.hyphenType.datastructure.annotations.ArgumentsObject;
27 import org.hyphenType.datastructure.annotations.Option;
28 import org.hyphenType.datastructure.annotations.OptionArgument;
29 import org.hyphenType.datastructure.annotations.SimpleArgument;
30 import org.hyphenType.documentation.Description;
31 import org.hyphenType.optionprocessors.ArgumentsProcessorEngine;
32 import org.hyphenType.util.DefaultAnnotation;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class BooleanValidatorEngine implements ArgumentsProcessorEngine<BooleanValidatorEngine.BooleanValidator> {
56
57 @Retention(RetentionPolicy.RUNTIME)
58 @Target(ElementType.TYPE)
59 public @interface BooleanValidator {
60 @Description("The set of rules to be checked")
61 Rule[] rules();
62
63 @Description("Whether the processor will output messages detailing the execution. Good for debugging.")
64 boolean verbose() default false;
65
66 @Description("Whether the processor will output failure messages.")
67 boolean showFailureMessages() default false;
68
69 @Description("Whether the processor will threat integers as booleans. I.e. if zero will be considered FALSE and all other values will be TRUE.")
70 boolean allBooleans() default false;
71 }
72
73 @Retention(RetentionPolicy.RUNTIME)
74 @Target(ElementType.TYPE)
75 public @interface Rule {
76 String rule();
77
78 String failureCodeName() default "";
79
80 int failureCode() default 0;
81
82 String failureMessage() default "";
83 }
84
85 @SuppressWarnings("unchecked")
86 @Override
87 public <T extends Options<?>> void process(Class<T> interfaceClass, T options, BooleanValidator config) {
88
89 ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
90
91 for (Method method : interfaceClass.getMethods()) {
92 if (method.isAnnotationPresent(Option.class)) {
93 try {
94 Object val;
95 if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class))
96 val = (Boolean) method.invoke(options);
97 else {
98 if (config.allBooleans())
99 val = ((Integer) method.invoke(options)) != 0;
100 else
101 val = (Integer) method.invoke(options);
102 }
103 engine.put(method.getName(), val);
104 continue;
105 } catch (IllegalArgumentException e) {
106
107 e.printStackTrace();
108 } catch (IllegalAccessException e) {
109
110 e.printStackTrace();
111 } catch (InvocationTargetException e) {
112
113 e.printStackTrace();
114 }
115 }
116 if (method.isAnnotationPresent(OptionArgument.class) || method.isAnnotationPresent(SimpleArgument.class)) {
117 try {
118 engine.put(method.getName(), method.invoke(options));
119 continue;
120 } catch (IllegalArgumentException e) {
121
122 e.printStackTrace();
123 } catch (IllegalAccessException e) {
124
125 e.printStackTrace();
126 } catch (InvocationTargetException e) {
127
128 e.printStackTrace();
129 }
130 }
131 }
132
133 for (Rule rule : config.rules()) {
134 try {
135 int returnCode;
136 if (!rule.failureCodeName().equals("")) {
137 ArgumentsObject ao = DefaultAnnotation.getAnnotation(interfaceClass, ArgumentsObject.class);
138 returnCode = Enum.valueOf((Class<? extends Enum>) ao.statusCodeEnum(), rule.failureCodeName()).ordinal();
139 } else {
140 returnCode = rule.failureCode();
141 }
142
143 boolean val;
144 Object obj = engine.eval(rule.rule());
145 if (obj instanceof Double)
146 val = ((Double) obj).doubleValue() > 0;
147 else if (obj instanceof Boolean)
148 val = (Boolean) obj;
149 else {
150 if (config.verbose()) {
151 if (obj == null)
152 System.err.println("Rule \"" + rule + "\" did not return anything. Should return a boolean or a number.");
153 else
154 System.err.println("Rule \"" + rule + "\" returned a strange object type: " + obj.getClass().getName());
155 }
156 options.exit(returnCode);
157 return;
158 }
159 if (val) {
160 if (config.verbose())
161 System.err.println(String.format("Rule checking failure: \"%s\"", rule.rule()));
162 if (config.showFailureMessages())
163 System.err.print(rule.failureMessage());
164 options.exit(returnCode);
165 return;
166 }
167
168 if (config.verbose())
169 System.out.println(String.format("Rule checking success: \"%s\"", rule.rule()));
170 } catch (ScriptException e) {
171
172 e.printStackTrace();
173 }
174 }
175 }
176 }