DefaultActionInvocation 源码


/**
* Copyright 2002-2006,2009 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2;

import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.PreResultListener;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/***
* The Default ActionInvocation implementation
*
* @author Rainer Hermanns
* @author tmjee
* @version $Date: 2009-12-27 19:18:29 +0100 (Sun, 27 Dec 2009) $ $Id: DefaultActionInvocation.java 894090 2009-12-27 18:18:29Z martinc $
* @see com.opensymphony.xwork2.DefaultActionProxy
*/
public class DefaultActionInvocation implements ActionInvocation {

private static final long serialVersionUID = -585293628862447329L;

//static {
// if (ObjectFactory.getContinuationPackage() != null) {
// continuationHandler = new ContinuationHandler();
// }
//}
private static final Logger LOG = LoggerFactory.getLogger(DefaultActionInvocation.class);

private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];

protected Object action;
protected ActionProxy proxy;
protected List<PreResultListener> preResultListeners;
protected Map<String, Object> extraContext;
protected ActionContext invocationContext;
protected Iterator<InterceptorMapping> interceptors;
protected ValueStack stack;
protected Result result;
protected Result explicitResult;
protected String resultCode;
protected boolean executed = false;
protected boolean pushAction = true;
protected ObjectFactory objectFactory;
protected ActionEventListener actionEventListener;
protected ValueStackFactory valueStackFactory;
protected Container container;
private Configuration configuration;
protected UnknownHandlerManager unknownHandlerManager;

public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
DefaultActionInvocation.this.extraContext = extraContext;
DefaultActionInvocation.this.pushAction = pushAction;
}

@Inject
public void setUnknownHandlerManager(UnknownHandlerManager unknownHandlerManager) {
this.unknownHandlerManager = unknownHandlerManager;
}

@Inject
public void setValueStackFactory(ValueStackFactory fac) {
this.valueStackFactory = fac;
}

@Inject
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}

@Inject
public void setObjectFactory(ObjectFactory fac) {
this.objectFactory = fac;
}

@Inject
public void setContainer(Container cont) {
this.container = cont;
}

@Inject(required=false)
public void setActionEventListener(ActionEventListener listener) {

this.actionEventListener = listener;
}

public Object getAction() {
return action;
}

public boolean isExecuted() {
return executed;
}

public ActionContext getInvocationContext() {
return invocationContext;
}

public ActionProxy getProxy() {
return proxy;
}

/***
* If the DefaultActionInvocation has been executed before and the Result is an instance of ActionChainResult, this method
* will walk down the chain of ActionChainResults until it finds a non-chain result, which will be returned. If the
* DefaultActionInvocation‘s result has not been executed before, the Result instance will be created and populated with
* the result params.
*
* @return a Result instance
* @throws Exception
*/
public Result getResult() throws Exception {
Result returnResult = result;

// If we‘ve chained to other Actions, we need to find the last result
while (returnResult instanceof ActionChainResult) {
ActionProxy aProxy = ((ActionChainResult) returnResult).getProxy();

if (aProxy != null) {
Result proxyResult = aProxy.getInvocation().getResult();

if ((proxyResult != null) && (aProxy.getExecuteResult())) {
returnResult = proxyResult;
} else {
break;
}
} else {
break;
}
}

return returnResult;
}

public String getResultCode() {
return resultCode;
}

public void setResultCode(String resultCode) {
if (isExecuted())
throw new IllegalStateException("Result has already been executed.");

this.resultCode = resultCode;
}

public ValueStack getStack() {
return stack;
}

/***
* Register a com.opensymphony.xwork2.interceptor.PreResultListener to be notified after the Action is executed and before the
* Result is executed. The ActionInvocation implementation must guarantee that listeners will be called in the order
* in which they are registered. Listener registration and execution does not need to be thread-safe.
*
* @param listener
*/
public void addPreResultListener(PreResultListener listener) {
if (preResultListeners == null) {
preResultListeners = new ArrayList<PreResultListener>(1);
}

preResultListeners.add(listener);
}

public Result createResult() throws Exception {

if (explicitResult != null) {
Result ret = explicitResult;
explicitResult = null;

return ret;
}
ActionConfig config = proxy.getConfig();
Map<String, ResultConfig> results = config.getResults();

ResultConfig resultConfig = null;

try {
resultConfig = results.get(resultCode);
} catch (NullPointerException e) {
// swallow
}

if (resultConfig == null) {
// If no result is found for the given resultCode, try to get a wildcard ‘*‘ match.
resultConfig = results.get("*");
}

if (resultConfig != null) {
try {
return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
} catch (Exception e) {
LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);
throw new XWorkException(e, resultConfig);
}
} else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {
return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
}
return null;
}

/***
* @throws ConfigurationException If no result can be found with the returned code
*/
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey);

if (executed) {
throw new IllegalStateException("Action has already executed");
}

if (interceptors.hasNext()) {
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
}
finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
resultCode = invokeActionOnly();
}

// this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if (!executed) {
if (preResultListeners != null) {
for (Object preResultListener : preResultListeners) {
PreResultListener listener = (PreResultListener) preResultListener;

String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}

// now execute the result, if we‘re supposed to
if (proxy.getExecuteResult()) {
executeResult();
}

executed = true;
}

return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}

public String invokeActionOnly() throws Exception {
return invokeAction(getAction(), proxy.getConfig());
}

protected void createAction(Map<String, Object> contextMap) {
// load action
String timerKey = "actionCreate: " + proxy.getActionName();
try {
UtilTimerStack.push(timerKey);
action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
} catch (InstantiationException e) {
throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());
} catch (IllegalAccessException e) {
throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());
} catch (Exception e) {
String gripe = "";

if (proxy == null) {
gripe = "Whoa! No ActionProxy instance found in current ActionInvocation. This is bad ... very bad";
} else if (proxy.getConfig() == null) {
gripe = "Sheesh. Where‘d that ActionProxy get to? I can‘t find it in the current ActionInvocation!?";
} else if (proxy.getConfig().getClassName() == null) {
gripe = "No Action defined for ‘" + proxy.getActionName() + "‘ in namespace ‘" + proxy.getNamespace() + "‘";
} else {
gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ", defined for ‘" + proxy.getActionName() + "‘ in namespace ‘" + proxy.getNamespace() + "‘";
}

gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");
throw new XWorkException(gripe, e, proxy.getConfig());
} finally {
UtilTimerStack.pop(timerKey);
}

if (actionEventListener != null) {
action = actionEventListener.prepare(action, stack);
}
}

protected Map<String, Object> createContextMap() {
Map<String, Object> contextMap;

if ((extraContext != null) && (extraContext.containsKey(ActionContext.VALUE_STACK))) {
// In case the ValueStack was passed in
stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);

if (stack == null) {
throw new IllegalStateException("There was a null Stack set into the extra params.");
}

contextMap = stack.getContext();
} else {
// create the value stack
// this also adds the ValueStack to its context
stack = valueStackFactory.createValueStack();

// create the action context
contextMap = stack.getContext();
}

// put extraContext in
if (extraContext != null) {
contextMap.putAll(extraContext);
}

//put this DefaultActionInvocation into the context map
contextMap.put(ActionContext.ACTION_INVOCATION, this);
contextMap.put(ActionContext.CONTAINER, container);

return contextMap;
}

/***
* Uses getResult to get the final Result and executes it
*
* @throws ConfigurationException If not result can be found with the returned code
*/
private void executeResult() throws Exception {
result = createResult();

String timerKey = "executeResult: " + getResultCode();
try {
UtilTimerStack.push(timerKey);
if (result != null) {
result.execute(this);
} else if (resultCode != null && !Action.NONE.equals(resultCode)) {
throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
+ " and result " + getResultCode(), proxy.getConfig());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
}
}
} finally {
UtilTimerStack.pop(timerKey);
}
}

public void init(ActionProxy proxy) {
this.proxy = proxy;
Map<String, Object> contextMap = createContextMap();

// Setting this so that other classes, like object factories, can use the ActionProxy and other
// contextual information to operate
ActionContext actionContext = ActionContext.getContext();

if (actionContext != null) {
actionContext.setActionInvocation(this);
}

createAction(contextMap);

if (pushAction) {
stack.push(action);
contextMap.put("action", action);
}

invocationContext = new ActionContext(contextMap);
invocationContext.setName(proxy.getActionName());

// get a new List so we don‘t get problems with the iterator if someone changes the list
List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
interceptors = interceptorList.iterator();
}

protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
String methodName = proxy.getMethod();

if (LOG.isDebugEnabled()) {
LOG.debug("Executing action method = " + actionConfig.getMethodName());
}

String timerKey = "invokeAction: " + proxy.getActionName();
try {
UtilTimerStack.push(timerKey);

boolean methodCalled = false;
Object methodResult = null;
Method method = null;
try {
method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
} catch (NoSuchMethodException e) {
// hmm -- OK, try doXxx instead
try {
String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
} catch (NoSuchMethodException e1) {
// well, give the unknown handler a shot
if (unknownHandlerManager.hasUnknownHandlers()) {
try {
methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
methodCalled = true;
} catch (NoSuchMethodException e2) {
// throw the original one
throw e;
}
} else {
throw e;
}
}
}

if (!methodCalled) {
methodResult = method.invoke(action, new Object[0]);
}

if (methodResult instanceof Result) {
this.explicitResult = (Result) methodResult;

// Wire the result automatically
container.inject(explicitResult);
return null;
} else {
return (String) methodResult;
}
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
} catch (InvocationTargetException e) {
// We try to return the source exception.
Throwable t = e.getTargetException();

if (actionEventListener != null) {
String result = actionEventListener.handleException(t, getStack());
if (result != null) {
return result;
}
}
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw e;
}
} finally {
UtilTimerStack.pop(timerKey);
}
}

}

DefaultActionInvocation 源码,布布扣,bubuko.com

时间: 2024-10-22 02:34:35

DefaultActionInvocation 源码的相关文章

Struts2 源码分析——Result类实例

本章简言 上一章笔者讲到关于DefaultActionInvocation类执行action的相关知识.我们清楚的知道在执行action类实例之后会相关处理返回的结果.而这章笔者将对处理结果相关的内容进行讲解.笔者叫他们为Result类实例.如果还记得在上一章最后笔者说可以把处理action执行的结果简单的理解处理网页.而且还用红色标识.实际是处理跟表现层有关的内容.而不是页面上的内容.如HTML.即是MVC里面的C到V的内容.当然这还关系到配置文件里面的result元素节点信息.如strtus

Struts2 源码分析——拦截器的机制

本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样子讲吧.拦截器的应用是sturts2核心的亮点之一.如果不明白拦截器是什么的话,那么你相当于没有学习过struts2.笔者本来想直接讲这一章的知识点.可是又怕读者可能对拦截器没有一个概念化的理解.为什么这么讲呢?struts2在设计拦截器这一个部分的内容.在笔者看来事实是以AOP为核心思想来设计的.

关于阅读Struts2部分拦截器源码的记录

Struts2中的拦截器在ActionInvocation对象的invoke()方法中执行. ActionInvocation对象从配置文件中读取Interceptor对象,加入到自己的存取拦截器的容器中. 在invoke()方法中,当容器中还有Interceptor对象时,就执行对应Interceptor的intercept方法;在intercept方法中,除了加入拦截器自己的部分语句,还会调用同一个ActionInvocation对象的invoke方法,然后invoke方法再执行下一个Int

struct2源码解读(11)之执行action请求中篇

struct2源码解读之执行action请求(2) 上篇博文介绍了执行action请求前的一些准备工作,包括封装http参数到一个map中,获得一个值栈对象和配置信息configuration,并创建一个执行action请求的actionProxy对象,并对这个对象进行了初始化,包括指定默认执行方法和对actionName对应的类进行依赖注入以及调出拦截器. 然后就到了我们执行action请求的工作.  if (mapping.getResult() != null) {            

Struts2请求处理流程及源码分析

1.1 Struts2请求处理 1. 一个请求在Struts2框架中的处理步骤: a) 客户端初始化一个指向Servlet容器的请求: b) 根据Web.xml配置,请求首先经过ActionContextCleanUp过滤器,其为可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助(SiteMesh Plugin),主要清理当前线程的ActionContext和Dispatcher: c) 请求经过插件过滤器,如:SiteMesh.etc等过滤器: d) 请求经过核心过滤器Filte

结合源码浅析Struts2与Spring整合的原理

本文假设读者已经自己动手整合过Struts2和Spring这两个框架.我想说明的重点不是如何整合这两个框架,而是为什么经过配置之后Struts的Action等对象可以由Spring来管理,即找到两个框架的衔接点. 笔者用的是框架版本分别为Struts-2.3和Spring-4.1. ------------------------------------------------------- 文章的结构如下: 一.回顾Struts2与Spring整合的配置方法 二.(重点)对关键配置的分析 --

Struts2源码解析2

看了前面一节对Struts2各个模块运行有了大概了解,也对调用的函数有了一定的了解,本节希望打断点跑一个Struts2例子! 还是放在struts2结构图: 一:项目启动后解析web.xml文件,会解析到配置的StrutsPrepareAndExecuteFilter的过滤器. 1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app id="WebApp_9" version=&q

小说分销系统,微信小说分销,类掌中云小说系统,类818tu系统源码

[演示站参数][][][][][][][][][][][] [后 台 地 址]     http://xiaoshuo.qqsiot.cn/manager          [] [管理员账号]     admin                                                     [] [渠道商账号]     channel                                                  [] [代理商账号]     age

cocos Creator js 房卡麻将/血战/H5四川麻将源码下载搭建

房卡麻将/血战/H5四川麻将 源码 支持iOS/Android/H5 完整源码 1.基于NODEJS+MYSQL的服务器,成熟的技术方案,高效稳定,且方便Windows开发,Linux平台布署,节约服务器运转成本. 2.采用最新版本的cocos引擎,cocos creator开发,可快速的进行界面调整.且能够快速地发布iOS,Android版本. 3.如需H5版本,只需针对H5平台进行资源优化即可. 4.成熟可靠的房卡式设计,能满足大部分用户使用体验. 5.产品经过大量测试,可以运转稳定. 测试