PageRenderTime 34ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/web/dispatcher/JiraWebworkViewDispatcher.java

https://bitbucket.org/ahmed_bilal_360factors/jira7-core
Java | 207 lines | 152 code | 33 blank | 22 comment | 24 complexity | e193fade629e2b854ec2c22108f89194 MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jira.web.dispatcher;
  2. import com.atlassian.fugue.Option;
  3. import com.atlassian.jira.component.ComponentAccessor;
  4. import com.atlassian.jira.config.webwork.actions.ActionConfiguration;
  5. import com.atlassian.jira.security.JiraAuthenticationContext;
  6. import com.atlassian.jira.template.TemplateType;
  7. import com.atlassian.seraph.util.RedirectUtils;
  8. import com.google.common.annotations.VisibleForTesting;
  9. import com.google.common.base.Function;
  10. import com.google.common.base.Supplier;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import webwork.action.Action;
  14. import webwork.config.util.ActionInfo;
  15. import webwork.dispatcher.ActionResult;
  16. import webwork.util.ServletValueStack;
  17. import javax.servlet.RequestDispatcher;
  18. import javax.servlet.ServletException;
  19. import javax.servlet.http.HttpServletRequest;
  20. import javax.servlet.http.HttpServletResponse;
  21. import java.io.IOException;
  22. import static java.lang.String.format;
  23. /**
  24. * The logic for dispatching a particular view for an action is encapsulated in this class
  25. *
  26. * @since v6.0
  27. */
  28. class JiraWebworkViewDispatcher {
  29. private static final Logger log = LoggerFactory.getLogger(JiraWebworkViewDispatcher.class);
  30. private static final Supplier<String> ASSERTION_CANT_BE_NONE = () -> "This cannot not be Option.none() at this stage";
  31. private final JiraSoyViewDispatcher soyViewDispatcher = new JiraSoyViewDispatcher();
  32. private final JiraVelocityViewDispatcher velocityViewDispatcher = new JiraVelocityViewDispatcher();
  33. void dispatchView(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final boolean doCleanup, final ActionResult ar, final String actionAlias)
  34. throws ServletException, IOException {
  35. if (permissionViolationCheckHandled(ar, httpServletRequest, httpServletResponse, doCleanup)) {
  36. return;
  37. }
  38. String actionView = ar.getView().toString();
  39. String actionResult = ar.getResult();
  40. log.debug("Action Result {} --> View Name: {}", actionResult, actionView);
  41. Option<ActionInfo.ViewInfo> viewInfo = determineViewInfo(ar, actionAlias);
  42. try {
  43. if (isSoyView(viewInfo)) {
  44. dispatchViaSoyView(httpServletResponse, ar, viewInfo);
  45. } else if (isVelocityView(viewInfo)) {
  46. dispatchViaVelocityView(httpServletRequest, httpServletResponse, ar, viewInfo);
  47. } else {
  48. dispatchViaHttpView(httpServletRequest, httpServletResponse, ar, viewInfo);
  49. }
  50. } finally {
  51. cleanUpStack(httpServletRequest, doCleanup);
  52. }
  53. }
  54. private Option<ActionInfo.ViewInfo> determineViewInfo(final ActionResult ar, final String actionAlias) {
  55. Option<ActionInfo.ViewInfo> viewInfo = getViewInfo(actionAlias, ar.getResult());
  56. if (viewInfo.isEmpty() && Action.INPUT.equals(ar.getResult())) {
  57. //
  58. // Webwork ConfigurationViewMappping class has an annoying edge case where it equates Action.INPUT ==> Action.ERROR
  59. // when the Action.INPUT view is undefined. So we need to do something similar so that we find the right ActionInfo for that case
  60. // otherwise we will will not resolve to the appropriate view
  61. //
  62. viewInfo = getViewInfo(actionAlias, Action.ERROR);
  63. }
  64. return viewInfo;
  65. }
  66. private void dispatchViaHttpView(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, ActionResult actionResult, final Option<ActionInfo.ViewInfo> viewInfo)
  67. throws ServletException, IOException {
  68. String view = actionResult.getView().toString();
  69. forwardToHttpView(httpServletRequest, httpServletResponse, view, getRequestDispatcher(httpServletRequest, view));
  70. }
  71. private void dispatchViaVelocityView(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final ActionResult actionResult, final Option<ActionInfo.ViewInfo> viewInfoOption)
  72. throws ServletException, IOException {
  73. velocityViewDispatcher.dispatch(httpServletRequest, httpServletResponse, actionResult, viewInfoOption.get());
  74. }
  75. private void forwardToHttpView(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final String view, final RequestDispatcher dispatcher)
  76. throws ServletException, IOException {
  77. // If we're included or if content has already been sent down the pipe, then include the view
  78. // Otherwise do forward
  79. // This allow the page to, for example, set content type
  80. if (!httpServletResponse.isCommitted() && httpServletRequest.getAttribute("javax.servlet.include.servlet_path") == null) {
  81. httpServletRequest.setAttribute("webwork.view_uri", view);
  82. httpServletRequest.setAttribute("webwork.request_uri", httpServletRequest.getRequestURI());
  83. dispatcher.forward(httpServletRequest, httpServletResponse);
  84. } else {
  85. dispatcher.include(httpServletRequest, httpServletResponse);
  86. }
  87. }
  88. private RequestDispatcher getRequestDispatcher(final HttpServletRequest httpServletRequest, final String view)
  89. throws ServletException {
  90. final RequestDispatcher dispatcher;
  91. dispatcher = httpServletRequest.getRequestDispatcher(view);
  92. if (dispatcher == null) {
  93. throw new ServletException(format("No presentation file with name: '%s' found!", view));
  94. }
  95. return dispatcher;
  96. }
  97. private void dispatchViaSoyView(final HttpServletResponse httpServletResponse, final ActionResult ar, Option<ActionInfo.ViewInfo> viewInfo)
  98. throws ServletException, IOException {
  99. soyViewDispatcher.dispatch(httpServletResponse, ar, viewInfo.getOrError(ASSERTION_CANT_BE_NONE));
  100. }
  101. private boolean isSoyView(Option<ActionInfo.ViewInfo> viewInfo) {
  102. return TemplateType.SOY.getKey().equals(getAttrValue(viewInfo, "type").getOrNull());
  103. }
  104. private boolean isVelocityView(final Option<ActionInfo.ViewInfo> viewInfo) {
  105. boolean isVelocity = false;
  106. if (viewInfo.isDefined()) {
  107. isVelocity = "velocity".equals(getAttrValue(viewInfo, "type").getOrNull());
  108. isVelocity |= viewInfo.get().getViewValue().endsWith(".vm");
  109. }
  110. return isVelocity;
  111. }
  112. private void cleanUpStack(HttpServletRequest httpServletRequest, boolean doCleanup) {
  113. if (doCleanup) {
  114. // Get last action from stack and and store it in request attribute STACK_HEAD
  115. // It is then popped from the stack.
  116. httpServletRequest.setAttribute(JiraWebworkActionDispatcher.STACK_HEAD, ServletValueStack.getStack(httpServletRequest).popValue());
  117. }
  118. }
  119. private boolean permissionViolationCheckHandled(final ActionResult ar, final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final boolean doCleanup) {
  120. // special hard coded support for actions returning permission violation that require a login
  121. if (!isUserLoggedIn()) {
  122. final String result = ar.getResult();
  123. if ("permissionviolation".equals(result) || "securitybreach".equals(result)) {
  124. final String loginUrl = RedirectUtils.getLoginUrl(httpServletRequest);
  125. try {
  126. httpServletResponse.sendRedirect(loginUrl);
  127. } catch (IOException e) {
  128. log.error("Unable to redirect permission violation to " + loginUrl);
  129. } finally {
  130. cleanUpStack(httpServletRequest, doCleanup);
  131. }
  132. return true;
  133. }
  134. }
  135. return false;
  136. }
  137. private Option<ActionInfo.ViewInfo> getViewInfo(final String actionAlias, final String actionResult) {
  138. ActionConfiguration.Entry actionConfiguration = getActionConfiguration(actionAlias);
  139. ActionInfo actionInfo = actionConfiguration.getActionInfo();
  140. for (ActionInfo.ViewInfo viewInfo : actionInfo.getViews()) {
  141. if (viewInfo.getViewName().equals(actionResult)) {
  142. return Option.some(viewInfo);
  143. }
  144. }
  145. return Option.none();
  146. }
  147. private Option<String> getAttrValue(Option<ActionInfo.ViewInfo> viewInfo, final String attrName) {
  148. return viewInfo.map(new Function<ActionInfo.ViewInfo, String>() {
  149. @Override
  150. public String apply(final ActionInfo.ViewInfo input) {
  151. return input.getAttributeValue(attrName);
  152. }
  153. });
  154. }
  155. /**
  156. * Returns true if the plugin source is from JIRA core
  157. *
  158. * @param pluginSource the source to check
  159. * @return true if the plugin source is from JIRA core
  160. */
  161. public static boolean isFromCore(final String pluginSource) {
  162. return pluginSource == null
  163. || pluginSource.endsWith("WEB-INF/classes/actions.xml") // standard run
  164. || pluginSource.endsWith("jira-core/target/classes/actions.xml"); // when using JRebel
  165. }
  166. @VisibleForTesting
  167. boolean isUserLoggedIn() {
  168. return ComponentAccessor.getComponent(JiraAuthenticationContext.class).getUser() != null;
  169. }
  170. @VisibleForTesting
  171. ActionConfiguration.Entry getActionConfiguration(String actionAlias) {
  172. return ComponentAccessor.getComponent(ActionConfiguration.class).getActionCommand(actionAlias);
  173. }
  174. }