1
2
3
4
5 package gboat2.base.plugin.struts.convention;
6
7 import gboat2.base.bridge.GboatAppConstants;
8 import gboat2.base.bridge.debug.DefaultDebugHook;
9 import gboat2.base.bridge.util.BundleUtil;
10
11 import java.io.File;
12 import java.lang.reflect.Method;
13 import java.lang.reflect.Modifier;
14 import java.net.MalformedURLException;
15 import java.util.Map;
16
17 import javax.servlet.ServletContext;
18
19 import org.apache.commons.lang3.StringUtils;
20 import org.apache.struts2.ServletActionContext;
21 import org.apache.struts2.convention.ConventionUnknownHandler;
22 import org.apache.struts2.osgi.DefaultBundleAccessor;
23 import org.osgi.framework.Bundle;
24 import org.springframework.util.ReflectionUtils;
25
26 import com.opensymphony.xwork2.ActionContext;
27 import com.opensymphony.xwork2.ActionInvocation;
28 import com.opensymphony.xwork2.ObjectFactory;
29 import com.opensymphony.xwork2.Result;
30 import com.opensymphony.xwork2.config.Configuration;
31 import com.opensymphony.xwork2.config.entities.ActionConfig;
32 import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
33 import com.opensymphony.xwork2.inject.Container;
34 import com.opensymphony.xwork2.inject.Inject;
35 import com.opensymphony.xwork2.util.logging.Logger;
36 import com.opensymphony.xwork2.util.logging.LoggerFactory;
37
38
39
40
41
42
43
44 public class GboatConventionUnknownHandler extends ConventionUnknownHandler {
45
46 private static final Logger LOG = LoggerFactory.getLogger(GboatConventionUnknownHandler.class);
47 private ActionContext actionContext;
48 private String nameSeparator;
49
50 @Inject
51 public GboatConventionUnknownHandler(Configuration configuration, ObjectFactory objectFactory,
52 ServletContext servletContext, Container container,
53 @Inject("struts.convention.default.parent.package") String defaultParentPackageName,
54 @Inject("struts.convention.redirect.to.slash") String redirectToSlash,
55 @Inject("struts.convention.action.name.separator") String nameSeparator) {
56 super(configuration, objectFactory, servletContext, container, defaultParentPackageName, redirectToSlash, nameSeparator);
57 this.nameSeparator = nameSeparator;
58 }
59
60 @Override
61 public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig, String resultCode) {
62 Result result = super.handleUnknownResult(actionContext, actionName, actionConfig, resultCode);
63 if (result == null) {
64 DefaultBundleAccessor.getInstance().loadResource(actionName);
65 }
66 this.actionContext = actionContext;
67 return result;
68 }
69
70 @Override
71 protected Resource findResource(Map<String, ResultTypeConfig> resultsByExtension, String... parts) {
72 String pathPrefix = string(parts);
73 DefaultDebugHook debugHook = DefaultDebugHook.getInstance();
74
75 ActionInvocation invocation = actionContext.getActionInvocation();
76 Bundle bundle = BundleUtil.getBundleForRequestJsp(pathPrefix, invocation, servletContext);
77
78 String extendForView = getExtendForView(invocation);
79 String[] canonicalPaths = null;
80 boolean traceEnabled = LOG.isTraceEnabled();
81 for (String ext : resultsByExtension.keySet()) {
82
83 canonicalPaths = (StringUtils.isBlank(extendForView) ? new String[] { canonicalize(pathPrefix + "." + ext) }
84 : new String[] { canonicalize(pathPrefix + nameSeparator + extendForView + "." + ext),
85 canonicalize(pathPrefix + "." + ext) });
86 for (String canonicalPath : canonicalPaths) {
87 if (bundle != null) {
88
89 boolean isDevMode = debugHook.isBundleDebugEnabled(bundle.getSymbolicName());
90 if (isDevMode) {
91 File sourceFile = new File(debugHook.getSourceFilePath(bundle.getSymbolicName(), canonicalPath));
92 if (traceEnabled) {
93 LOG.trace("Checking for [#0]", sourceFile.getAbsolutePath());
94 }
95 if (sourceFile.isFile())
96 return new Resource(canonicalPath, ext);
97 }
98
99 if (traceEnabled) {
100 LOG.trace("Checking for [#0] from bundle [#1]", canonicalPath, bundle.getSymbolicName());
101 }
102
103 if (bundle.getResource(canonicalPath) != null)
104 return new Resource(canonicalPath, ext);
105 }
106
107 if (traceEnabled) {
108 LOG.trace("Checking for [#0]", canonicalPath);
109 }
110 try {
111
112 if (servletContext.getResource(canonicalPath) != null)
113 return new Resource(canonicalPath, ext);
114 } catch (MalformedURLException e) {
115 if (LOG.isErrorEnabled()) {
116 LOG.error("Unable to parse path to the web application resource [#0] skipping...", canonicalPath);
117 }
118 }
119 }
120 }
121 return null;
122 }
123
124 @Override
125 protected Result findResult(String path, String resultCode, String ext, ActionContext actionContext, Map<String, ResultTypeConfig> resultsByExtension) {
126 DefaultDebugHook debugHook = DefaultDebugHook.getInstance();
127 ActionInvocation invocation = actionContext.getActionInvocation();
128 Bundle bundle = BundleUtil.getBundleForRequestJsp(path, invocation, servletContext);
129
130 String extendForView = getExtendForView(invocation);
131 String suffix = "." + ext;
132 String[] paths = (StringUtils.isBlank(extendForView) ? new String[] { path } : new String[] {
133 (StringUtils.removeEnd(path, suffix) + nameSeparator + extendForView + suffix), path });
134 for (String p : paths) {
135 if(bundle != null) {
136 boolean traceEnabled = LOG.isTraceEnabled();
137
138 boolean isDevMode = debugHook.isBundleDebugEnabled(bundle.getSymbolicName());
139 if(isDevMode) {
140 File sourceFile = new File(debugHook.getSourceFilePath(bundle.getSymbolicName(), p));
141 if (traceEnabled) {
142 LOG.trace("Checking for [#0]", sourceFile.getAbsolutePath());
143 }
144 if(sourceFile.isFile())
145 return buildResult(p, resultCode, resultsByExtension.get(ext), actionContext);
146 }
147
148 if (traceEnabled)
149 LOG.trace("Checking bundle resource for [#0]", p);
150
151 if (bundle.getEntry(p) != null)
152 return buildResult(p, resultCode, resultsByExtension.get(ext), actionContext);
153 }
154 Result result = super.findResult(p, resultCode, ext, actionContext, resultsByExtension);
155 if (result != null) {
156 return result;
157 }
158 }
159 return null;
160 }
161
162 @Override
163 protected Result buildResult(String path, String resultCode, ResultTypeConfig config, ActionContext invocationContext) {
164
165 Result result = super.buildResult(path, resultCode, config, invocationContext);
166
167
168
169
170
171 ServletActionContext.getRequest().setAttribute(GboatAppConstants.INCLUDE_SERVLET_PATH_KEY, path);
172 return result;
173 }
174
175 private String getExtendForView(ActionInvocation invocation) {
176 Object action = invocation.getAction();
177 Method method = ReflectionUtils.findMethod(action.getClass(), "getExtendForView");
178
179 if (method != null && !Modifier.isPrivate(method.getModifiers())) {
180 if (!method.isAccessible()) {
181 method.setAccessible(true);
182 }
183 return (String) ReflectionUtils.invokeMethod(method, action);
184 }
185 return null;
186 }
187 }