1 package io.jawk.ext;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.lang.reflect.Method;
26 import java.util.Collections;
27 import java.util.LinkedHashMap;
28 import java.util.Map;
29 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
30 import io.jawk.ext.annotations.JawkFunction;
31 import io.jawk.jrt.IllegalAwkArgumentException;
32 import io.jawk.jrt.JRT;
33 import io.jawk.jrt.VariableManager;
34 import io.jawk.util.AwkSettings;
35
36
37
38
39
40
41
42
43
44
45 public abstract class AbstractExtension implements JawkExtension {
46
47 private JRT jrt;
48 private VariableManager vm;
49 private AwkSettings settings;
50 private Map<String, ExtensionFunction> annotatedFunctions;
51
52
53 @Override
54 public String getExtensionName() {
55 return getClass().getSimpleName();
56 }
57
58
59 @Override
60 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "Extension needs direct access to runtime, VM and settings")
61 public void init(VariableManager vmParam, JRT runtime, final AwkSettings conf) {
62 this.vm = vmParam;
63 this.jrt = runtime;
64 this.settings = conf;
65 }
66
67
68
69
70
71
72
73
74
75 protected final String toAwkString(Object obj) {
76 return jrt.toAwkString(obj);
77 }
78
79
80
81
82
83
84
85
86
87 protected static void checkNumArgs(Object[] arr, int expectedNum) {
88
89
90
91
92
93 if (arr.length != expectedNum) {
94 throw new IllegalAwkArgumentException("Expecting " + expectedNum + " arg(s), got " + arr.length);
95 }
96 }
97
98
99
100
101
102
103
104
105 protected JRT getJrt() {
106 return jrt;
107 }
108
109
110
111
112
113
114
115
116 protected VariableManager getVm() {
117 return vm;
118 }
119
120
121
122
123
124
125
126
127 protected AwkSettings getSettings() {
128 return settings;
129 }
130
131 private Map<String, ExtensionFunction> getAnnotatedFunctions() {
132 if (annotatedFunctions == null) {
133 annotatedFunctions = Collections.unmodifiableMap(scanAnnotatedFunctions());
134 }
135 return annotatedFunctions;
136 }
137
138 private Map<String, ExtensionFunction> scanAnnotatedFunctions() {
139 Map<String, ExtensionFunction> discovered = new LinkedHashMap<String, ExtensionFunction>();
140 Class<? extends AbstractExtension> type = getClass();
141 for (Method method : type.getMethods()) {
142 JawkFunction function = method.getAnnotation(JawkFunction.class);
143 if (function == null) {
144 continue;
145 }
146 String keyword = function.value();
147 ExtensionFunction existing = discovered.put(keyword, new ExtensionFunction(keyword, method));
148 if (existing != null) {
149 throw new IllegalStateException(
150 "Duplicate @JawkFunction mapping for keyword '" + keyword + "' in " + type.getName());
151 }
152 }
153 return discovered;
154 }
155
156
157 @Override
158 public Map<String, ExtensionFunction> getExtensionFunctions() {
159 return getAnnotatedFunctions();
160 }
161 }