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