1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.internal;
18
19 import java.util.HashMap;
20 import java.util.LinkedHashSet;
21 import java.util.Map;
22 import java.util.Objects;
23 import java.util.Set;
24 import java.util.concurrent.locks.ReadWriteLock;
25 import java.util.concurrent.locks.ReentrantReadWriteLock;
26
27 import org.apache.commons.jexl3.JexlContext;
28 import org.apache.commons.jexl3.introspection.JexlUberspect;
29
30
31
32
33
34
35 final class FqcnResolver implements JexlContext.ClassNameResolver {
36
37
38
39 private final JexlUberspect uberspect;
40
41
42
43 private final ReadWriteLock lock = new ReentrantReadWriteLock();
44
45
46
47 private final Set<String> imports = new LinkedHashSet<>();
48
49
50
51
52 private final Map<String, String> fqcns = new HashMap<>();
53
54
55
56 private final FqcnResolver parent;
57
58
59
60
61
62
63
64 FqcnResolver(final FqcnResolver solver) {
65 Objects.requireNonNull(solver, "solver");
66 this.parent = solver;
67 this.uberspect = solver.uberspect;
68 }
69
70
71
72
73
74
75
76 FqcnResolver(final JexlUberspect uber, final Iterable<String> packages) {
77 this.uberspect = uber;
78 this.parent = null;
79 importCheck(packages);
80 }
81
82
83
84
85
86
87
88 String getQualifiedName(final String name) {
89 String fqcn;
90 if (parent != null && (fqcn = parent.getQualifiedName(name)) != null) {
91 return fqcn;
92 }
93 lock.readLock().lock();
94 try {
95 fqcn = fqcns.get(name);
96 } finally {
97 lock.readLock().unlock();
98 }
99 if (fqcn == null) {
100 final ClassLoader loader = uberspect.getClassLoader();
101 for (final String pkg : imports) {
102 Class<?> clazz;
103 try {
104 clazz = loader.loadClass(pkg + "." + name);
105 } catch (final ClassNotFoundException e) {
106
107 continue;
108 }
109
110 if (clazz != null) {
111 fqcn = clazz.getName();
112 lock.writeLock().lock();
113 try {
114 fqcns.put(name, fqcn);
115 } finally {
116 lock.writeLock().unlock();
117 }
118 break;
119 }
120 }
121 }
122 return fqcn;
123 }
124
125
126
127
128
129 private void importCheck(final Iterable<String> names) {
130 if (names != null) {
131 names.forEach(this::importCheck);
132 }
133 }
134
135
136
137
138
139 private void importCheck(final String name) {
140
141 if (name != null && Package.getPackage(name) != null) {
142 imports.add(name);
143 }
144 }
145
146
147
148
149
150
151
152 FqcnResolver importPackages(final Iterable<String> packages) {
153 if (packages != null) {
154 lock.writeLock().lock();
155 try {
156 if (parent == null) {
157 importCheck(packages);
158 } else {
159 packages.forEach(pkg ->{ if (!parent.isImporting(pkg)) { importCheck(pkg); }});
160 }
161 } finally {
162 lock.writeLock().unlock();
163 }
164 }
165 return this;
166 }
167
168
169
170
171
172
173
174 boolean isImporting(final String pkg) {
175 if (parent != null && parent.isImporting(pkg)) {
176 return true;
177 }
178 lock.readLock().lock();
179 try {
180 return imports.contains(pkg);
181 } finally {
182 lock.readLock().unlock();
183 }
184 }
185
186 @Override
187 public String resolveClassName(final String name) {
188 return getQualifiedName(name);
189 }
190 }