1
2
3
4
5
6
7
8
9
10
11
12
13
14 package gboat2.base.plugin.struts.convention;
15
16 import java.io.IOException;
17 import java.net.URL;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.regex.Pattern;
23
24 import org.apache.commons.lang3.StringUtils;
25 import org.apache.struts2.convention.PackageBasedActionConfigBuilder;
26
27 import com.opensymphony.xwork2.FileManager;
28 import com.opensymphony.xwork2.FileManagerFactory;
29 import com.opensymphony.xwork2.ObjectFactory;
30 import com.opensymphony.xwork2.config.Configuration;
31 import com.opensymphony.xwork2.inject.Container;
32 import com.opensymphony.xwork2.inject.Inject;
33 import com.opensymphony.xwork2.util.TextParseUtil;
34 import com.opensymphony.xwork2.util.finder.ClassFinder;
35 import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
36 import com.opensymphony.xwork2.util.finder.ClassLoaderInterfaceDelegate;
37 import com.opensymphony.xwork2.util.finder.Test;
38 import com.opensymphony.xwork2.util.finder.UrlSet;
39 import com.opensymphony.xwork2.util.logging.Logger;
40 import com.opensymphony.xwork2.util.logging.LoggerFactory;
41
42
43
44
45
46
47
48
49
50
51
52 public class GboatPackageBasedActionConfigBuilder extends PackageBasedActionConfigBuilder {
53
54 private static final Logger LOG = LoggerFactory.getLogger(PackageBasedActionConfigBuilder.class);
55
56 private String[] actionPackages;
57
58 private String[] packageLocators;
59
60 private boolean disablePackageLocatorsScanning = false;
61
62 private Set<String> fileProtocols;
63
64 private boolean excludeParentClassLoader;
65
66 private String[] includeJars;
67
68 private FileManager fileManager;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 @Inject
91 public GboatPackageBasedActionConfigBuilder(Configuration configuration,
92 Container container, ObjectFactory objectFactory,
93 @Inject("struts.convention.redirect.to.slash") String redirectToSlash,
94 @Inject("struts.convention.default.parent.package") String defaultParentPackage) {
95 super(configuration, container, objectFactory, redirectToSlash, defaultParentPackage);
96 }
97
98 @Inject
99 public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
100 this.fileManager = fileManagerFactory.getFileManager();
101 }
102
103 @SuppressWarnings("rawtypes")
104 @Override
105 protected Set<Class> findActions() {
106 Set<Class> classes = new HashSet<Class>();
107 try {
108 if (actionPackages != null
109 || (packageLocators != null && !disablePackageLocatorsScanning)) {
110
111 Test<String> classPackageTest = getClassPackageTest();
112 ClassFinder finder = new ClassFinder(getClassLoaderInterface(),
113 buildUrlSet().getUrls(), false, this.fileProtocols, classPackageTest);
114 Test<ClassFinder.ClassInfo> test = getActionClassTest();
115 classes.addAll(finder.findClasses(test));
116 }
117 } catch (Exception ex) {
118 if (LOG.isErrorEnabled())
119 LOG.error("Unable to scan named packages", ex);
120 }
121 return classes;
122 }
123
124
125
126
127
128
129
130
131 private UrlSet buildUrlSet() throws IOException {
132 ClassLoaderInterface classLoaderInterface = getClassLoaderInterface();
133
134 URL mi = classLoaderInterface.getResource("META-INF");
135 if (mi == null) {
136 LOG.error("META-INF can't be found in {}", classLoaderInterface.toString());
137 return new UrlSet(new ArrayList<URL>());
138 }
139 UrlSet urlSet = new UrlSet(classLoaderInterface, this.fileProtocols);
140
141
142
143 if (excludeParentClassLoader) {
144
145 ClassLoaderInterface parent = classLoaderInterface.getParent();
146
147
148
149
150 if (parent != null && isReloadEnabled())
151 parent = parent.getParent();
152
153 if (parent != null)
154 urlSet = urlSet.exclude(parent);
155
156 try {
157
158 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
159 urlSet = urlSet.exclude(new ClassLoaderInterfaceDelegate(systemClassLoader.getParent()));
160
161 } catch (SecurityException e) {
162 if (LOG.isWarnEnabled())
163 LOG.warn("Could not get the system classloader due to security constraints, there may be improper urls left to scan");
164 }
165 }
166
167
168 urlSet = urlSet.includeClassesUrl(classLoaderInterface, new UrlSet.FileProtocolNormalizer() {
169 public URL normalizeToFileProtocol(URL url) {
170 return fileManager.normalizeToFileProtocol(url);
171 }
172 });
173
174 urlSet = urlSet.excludeJavaExtDirs();
175 urlSet = urlSet.excludeJavaEndorsedDirs();
176 try {
177 urlSet = urlSet.excludeJavaHome();
178 } catch (NullPointerException e) {
179
180
181 if (LOG.isWarnEnabled())
182 LOG.warn("Could not exclude JAVA_HOME, is this a sandbox jvm?");
183 }
184 urlSet = urlSet.excludePaths(System.getProperty("sun.boot.class.path", ""));
185 urlSet = urlSet.exclude(".*/JavaVM.framework/.*");
186
187 if (includeJars == null) {
188 urlSet = urlSet.exclude(".*?\\.jar(!/|/)?");
189 } else {
190
191 List<URL> rawIncludedUrls = urlSet.getUrls();
192 Set<URL> includeUrls = new HashSet<URL>();
193 boolean[] patternUsed = new boolean[includeJars.length];
194
195 String convertedUrl;
196 for (URL url : rawIncludedUrls) {
197 if (fileProtocols.contains(url.getProtocol())) {
198
199
200 for (int i = 0; i < includeJars.length; i++) {
201 String includeJar = includeJars[i];
202 convertedUrl = url.toExternalForm().replaceAll("\\\\", "/");
203 if (Pattern.matches(includeJar, convertedUrl)) {
204 includeUrls.add(url);
205 patternUsed[i] = true;
206 break;
207 }
208 }
209 } else {
210
211 includeUrls.add(url);
212 }
213 }
214
215 if (LOG.isWarnEnabled()) {
216 for (int i = 0; i < patternUsed.length; i++) {
217 if (!patternUsed[i]) {
218 LOG.warn("The includeJars pattern [#0] did not match any jars in the classpath", includeJars[i]);
219 }
220 }
221 }
222 return new UrlSet(includeUrls);
223 }
224
225 return urlSet;
226 }
227
228
229
230
231
232
233 @Inject(value = "struts.convention.action.packages", required = false)
234 public void setActionPackages(String actionPackages) {
235 super.setActionPackages(actionPackages);
236 if (StringUtils.isNotBlank(actionPackages)) {
237 this.actionPackages = actionPackages.split("\\s*[,]\\s*");
238 }
239 }
240
241
242
243
244
245 @Inject(value = "struts.convention.package.locators", required = false)
246 public void setPackageLocators(String packageLocators) {
247 super.setPackageLocators(packageLocators);
248 this.packageLocators = packageLocators.split("\\s*[,]\\s*");
249 }
250
251
252
253
254
255 @Inject(value = "struts.convention.package.locators.disable", required = false)
256 public void setDisablePackageLocatorsScanning(String disablePackageLocatorsScanning) {
257 super.setDisablePackageLocatorsScanning(disablePackageLocatorsScanning);
258 this.disablePackageLocatorsScanning = "true".equals(disablePackageLocatorsScanning);
259 }
260
261
262
263
264
265
266
267
268
269 @Inject("struts.convention.action.fileProtocols")
270 public void setFileProtocols(String fileProtocols) {
271 super.setFileProtocols(fileProtocols);
272 if (StringUtils.isNotBlank(fileProtocols)) {
273 this.fileProtocols = TextParseUtil.commaDelimitedStringToSet(fileProtocols);
274 }
275 }
276
277
278
279
280
281
282
283
284
285 @Inject("struts.convention.exclude.parentClassLoader")
286 public void setExcludeParentClassLoader(String exclude) {
287 super.setExcludeParentClassLoader(exclude);
288 this.excludeParentClassLoader = "true".equals(exclude);
289 }
290
291
292
293
294
295
296 @Inject(value = "struts.convention.action.includeJars", required = false)
297 public void setIncludeJars(String includeJars) {
298 super.setIncludeJars(includeJars);
299 if (StringUtils.isNotEmpty(includeJars))
300 this.includeJars = includeJars.split("\\s*[,]\\s*");
301 }
302 }