using struts 2 action for a simple ajax request - java

I am trying to make a simple request using AJAX . But the whole thing is not working. Below is the code I wrote
jsp/javascript :
$("#my_"+rowNum).load("getdata.action?id="+123,function(data) {
alert("i am inside "+data);
});
Struts Action :
public class MyAction extends BaseAction {
public String execute() {
try {
inputStream = new ByteArrayInputStream("ABC 123 556".getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e) {
//handle exception
}
return SUCCESS;
}
}​
struts.xml :
<action name="getdata" class="com.amtd.advisoradmin.action.MyAction">
<result type="stream">
<param name="contentType">text/html</param>
<param name="inputName">inputStream</param>
</result>
I feel the configuration is correct, but I don't get the alert I printed in my jsp after the control returns from the Action class. Am I missing something ?
PS : ABC 123 556 is the data I need to get in the alerts.

I would suggest you to have a private variable for inputStream type InputStream and public getter and setter for it in your Action class, which is missing.
Thanks

Related

Can I use multiple methods in the same action?

I am using Struts 2 (2.5.10.1) with struts2-json-plugin-2.5.10.1. On my page I have a grid using ExtJs 4.2.2 that will be populated with projects, each row will have two actions: edit and delete.
The problem is that I have encountered: if I try to use multiple methods from the same action to do all the above, when I try to populate the grid I get no JSON response. Is what i am trying to do even possible ? (The edit and delete functionalities are not yet implemented)
Here is my struts.xml:
<package name="admin" extends="json-default">
<action name="requestProjectData"
class="administrator.ACTION_ProjectsGrid"
method="requestProjectData">
<result type="json" >
<param name="root">projectData</param>
</result>
</action>
<action name="requestDeleteProject"
class="administrator.ACTION_ProjectsGrid"
method="deleteProject">
<result type="json" >
<param name="root">success</param>
</result>
</action>
<action name="requestEditProject"
class="administrator.ACTION_ProjectsGrid"
method="editProject">
<result type="json" >
<param name="root">success</param>
</result>
</action>
Here is my Action class:
public class ACTION_ProjectsGrid extends ActionSupport {
private static final long serialVersionUID = 1L;
private List<Project> projectData;
private boolean success;
public void requestProjectData()
{
ProjectManager pm = new ProjectManager();
List<Project> listOfProjects = pm.getAllProjects();
projectData = listOfProjects;
}
public void deleteProject()
{
success = true;
}
public void editProject()
{
success = true;
}
public List<Project> getProjectData() {
return projectData;
}
public void setProjectData(List<Project> projectData) {
this.projectData = projectData;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
And my JSP page:
<body>
<script type="text/javascript">
Ext.define('Project', {
extend: 'Ext.data.Model',
fields: [ 'projectId', 'projectName' ]
});
var projStore = Ext.create('Ext.data.Store', {
model: 'Project',
proxy: {
type: 'ajax',
pageParam: false,
startParam: false,
limitParam: false,
noCache: false,
url: 'requestProjectData',
reader: {
type: 'json'
}
},
autoLoad: true
});
Ext.create('Ext.grid.Panel', {
renderTo: Ext.getBody(),
store: projStore,
width: 641,
height: 300,
title: 'Projects',
columns: [
{
text: 'ID',
width: 80,
dataIndex: 'projectId'
},
{
text: 'Project Name',
width: 80,
dataIndex: 'projectName'
},
{
xtype: 'actioncolumn',
width: 80,
items: [{
icon: '${pageContext.request.contextPath}/JavaScript/extjs/resources/user_edit.png',
tooltip: 'Edit',
handler: function(grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
Ext.Ajax.request({
url: 'requestDeleteProject',
disableCaching: false,
params: {
projectId: rec.get("projectId").toString(),
},
success: function(response)
{
grid.getStore().load();
}
});
}
}]
}
]
});
</script>
</body>
Ext.Ajax.request({
url: 'requestDeleteProject',
disableCaching: false,
params: {
projectId: rec.get("projectId").toString(),
},
success: function(response){
grid.getStore().load();
}
});}
Inside that part you making your request... You should decode the "response" inside the sucess and after it load the data to your store; making grid.getStore().load()
You are making another Request you want is something like
var json = Ext.decode(response.wtv..);
and then you want to load the grid's store like
grid.getStore().loadData(json);
soo like
success: function(response){
var json = Ext.decode(response.wtv..);
grid.getStore().loadData(json);
}
I found the problem. For this solution to work, all methods have to be created like the execute method. After I changed the return type to String and returned ActionSupport.SUCCESS, the json response appeared. But I still do not know if this solution is correct or I am breaking some rules, can anyone explain this to me ?
If you define an action that is mapped to the action class' method, the method should return either String or Result. The ActionSupport class provides you the default implementation for the action class.
Beside that, it implements a lot of interfaces that involve additional functionality via interceptors. One of this interfaces is Action. It is a functional interface that has only one method execute() which is invoked by default if no method is mapped to the action.
The value that is returned from the action method is a result code. This code or Result is necessary for Struts to proceed with the response after the action was executed. Thus the result code is returned to the invoker (ActionInvocation) which finds and executes a result with the same name defined in the action configuration. The default result name is Action.SUCCESS or ActionSupport.SUCCESS that you can return from the action. There should be result in the action configuration that implicitly or explicitly define a result with the name "success".
The "success" result is defined by default in your configuration, because it's missing name attribute. So to execute this result you should return "success", or Action.SUCCESS, or ActionSupport.SUCCESS that are the same string.
See more in the Result Configuration.
When an action class method completes, it returns a String. The
value of the String is used to select a result element. An action
mapping will often have a set of results representing different
possible outcomes. A standard set of result tokens are defined by the
ActionSupport base class. Predefined result names
String SUCCESS = "success";
String NONE = "none";
String ERROR = "error";
String INPUT = "input";
String LOGIN = "login";
Of course, applications can define other result tokens to match
specific cases.

Adding #RequiredStringValidator causing result not to be found

I have an Apache Struts web application. All of my actions are defined in my struts.xml file. I am trying to add support to my action classes to have validation annotations added to my project.
To try and get this working I added the struts2-convention-plugin.jar and also commons-lang.jar.
I then added an annotation on top of my action method.
jsp
<s:form id="tradingOutageFrm" action="addTradingOutageDo.action"
validate="true" theme="simple">
struts.xml
<action name="addTradingOutageDo" class="com.myproject.action.TradingOutageAction"
method="addDo">
<result name="success" type="tiles">page.tradingOutageAdd</result>
</action>
My action class
public class TradingOutageAction extends ActionSupport {
#RequiredStringValidator(type = ValidatorType.SIMPLE,
fieldName = "storeNo",
message = "Please enter a store.")
public String addDo() throws Exception {
try{
Map<String, Object> session = ActionContext.getContext().getSession();
String userId = session.get("userid").toString();
tradingOutage.setStoreNo(storeNo);
tradingOutage.setStoreServer(storeServer);
tradingOutageDAO.insertOutage(userId, startDate, startTime,
endDate, endTime, tradingOutage);
addActionMessage(MessageConstants.RECORD_INSERTED);
}catch(Exception e){
addActionError(MessageConstants.UPDATE_FAILED + " " + e.getMessage());
}
return SUCCESS;
}
Without the annotation everything works fine but with the annotation I get a
No result defined for action com.myproject.action.TradingOutageAction and result input.
Can anyone help me with what might be wrong here.

Struts 2.0 action method called without actually invoking

Found a strange issue in Struts action,
The scenario is like below ,
When I was in employees.jsp which just shows list of employees fetched from server , when an employee div is clicked, I will create a dynamic form as "employeeDetailsForm" in a javascript method, which has a hidden input field that holds value of employee code,
And I attached an action to the form as "getEmployeeDetails", when an employee div is clicked
It will submit the action and navigates to the employeeDetails.jsp,
In employeeDetails.jsp I will show set of details of that particular employee.
for his list of achievements I have upVote feature.
so when I click on upVote, upVote action gets called using ajax in a js method.
When upVote action is success , immediately again "getEmployeeDetails" action is getting called which is a strange behaviour.
I am not able to backtrace the call stack since many system defined methods are shown,
I just cross checked whether my "employeeDetailsForm" is exist in second jsp page as well and some how the form is being submitted somewhere ?
but when I checked inspector in browser, that form element was not there at all,
I also checked by calling document.getElementById("employeeDetailsFormId") which returned null
Then from where this method is getting called ?
How to trace this issue ?
Update -
Source code for reference
in employees.jsp - JS method to submit form to fetch details
var empDetForm = document.createElement("form");
empDetForm.id=“empDetailsId”;
empDetForm.name=“employeeDetailsForm";
empDetForm.method="POST";
empDetForm.action="getEmployeeDetails";
var empCodeinput = document.createElement("input");
empCodeinput.setAttribute("type","hidden");
empCodeinput.id= empCode;
empCodeinput.name=“empCode”;
empDetForm.appendChild(empCodeinput);
empDetForm.submit();
In employeeDetails.jsp - JS method to call upvote service using ajax
var formdata = "isUpVote="+isUpVote+”&”+”selectedAchievement="+achievementId;
$.ajax({
type: 'POST',
url: ‘achievementUpVote’,
contentType: "application/x-www-form-urlencoded",
async: false,
//processData:false,
data :formdata,
mimeType:"multipart/form-data",
cache: false,
processData:false,
datatype: "json",
success: function(response) {
alert("success upvote for achievement”);
},
error: function(e) {
alert("Fail upvote");
}
});
Java struts action methods
public String getEmployeeDetails() throws JSONException {
EmployeeDetailsIntf empDetailsImplObj = new EmployeeDetailsIml();
JSONObject jsonInput = new JSONObject();
String userName = ApplicationData.getUserName();
String accessCode = ApplicationData.getAccessCode();
jsonInput.put(“empId”, getEmpId());
jsonInput.put("un", userName);
jsonInput.put("ac", accessCode);
status = empDetailsImplObj.callGetEmpDetailsService(jsonInput);
if(status == true){
return "SUCCESS";
}
return "FAIL";
}
Another action
public String achievementRating() {
String userName = ApplicationData.getUserName();
String accessCode = ApplicationData.getAccessCode();
JSONObject jsonInputData = new JSONObject();
try {
jsonInputData.put("un", userName);
jsonInputData.put("ac", accessCode);
jsonInputData.put("aid", selectedAchivement);
EmployeeDetailsIntf empDetailsImplObj = new EmployeeDetailsIml();
boolean status = empDetailsImplObj.upVoteAchievement(jsonInputData, isUpVote);
if (status) {
return "RATE_ACHIEVEMENT_SUCCESS";
}else{
return "FAIL";
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null ;
}
struts.xml
<action name=“getEmployeeDetails” class="com.action.EmployeeDetailsAction"
method="getEmployeeDetails">
<result name="SUCCESS”>../empDetails/employeeDetails.jsp</result>
<result name="FAIL">failure.jsp</result>
</action>
<action name="achievementUpVote" class="com.action.EmployeeDetailsAction"
method="achievementRating">
<result name="RATE_ACHIEVEMENT_SUCCESS" type="json"/>
<result name="FAIL" type="json"/>
<result name="FAIL">failure.jsp</result>
</action>

How to define the annotation for action with image result?

I was ok to define it in struts.xml config.
<action name="getImage" class="my.action.GetImageAction">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="bufferSize">1024</param>
</result>
</action>
And I am now trying to define it by annotation on the class with namesapce, result path, and I have no idea how to do it. Please help :)
I have tried
#Namespace("/my/namespace")
#ResultPath("/")
#Result(name = "success", type = "imageResult")
public class GetImageAction extends ActionSupport {
.....
#Override
#Action("/getImage")
public String execute() throws Exception {
.....
And I got an error
HTTP Status 404 - No result defined for action
As the error says the results have to be defined at the Action.
The definition would look like this
#Action(value = "getImage", results = { #Result(
name = "success",
type = "stream",
params = {"contentType", "application/pdf" }) })
In the example you see the type too and how to define the contentType.
And the stream will be returned by the "getFileInputStream"-method:
public InputStream getFileInputStream() {
return fileInputStream;
}
the "getContentDisposition"-Method has to be available in the Action-class
public String getContentDisposition() {
return "attachment; filename=" + getFilename() + ".pdf";
}

Exception thrown by an interceptor doesn't go to the exception handler.

There's an issue I've experienced this day. I have an interceptor that begins and commits a Hibernate transaction and it may throw an exception on commit (org.hibernate.StaleObjectStateException for instance). That is, it can throw an exception but exception doesn't get to the handler. I thought there's an issue in my code. But then I wrote a simple test and here it is
Package definition in struts.xml:
<package name="basicstruts2" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="dummy" class="test.TestInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="dummy" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
<global-results>
<result name="exception" type="chain">exceptionHandler</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="exception" />
</global-exception-mappings>
<action name="test" class="test.TestAction">
<result>result.jsp</result>
</action>
<action name="exceptionHandler" class="test.ExceptionHandler">
<result>DebugErrorPage.jsp</result>
</action>
</package>
TestAction.java:
package test;
public class TestAction extends ActionSupport {
private BusinessLogic logic = new BusinessLogic();
public String execute() {
logic.test();
return SUCCESS;
}
}
TestInterceptor.java:
package test;
public class TestInterceptor implements Interceptor {
#Override
public String intercept(ActionInvocation arg0) throws Exception {
String result = null;
try {
result = arg0.invoke();
boolean flag = true;
if (flag) throw new RuntimeException("qwerty");
} catch (Exception e) {
System.out.println("exception catched in interceptor, rethrowing " + e);
throw e;
}
return result;
}
}
ExceptionHandler.java:
package test;
public class ExceptionHandler extends ActionSupport {
private Exception exception;
public void setException(Exception e) {
exception = e;
System.out.println("setting exception");
}
public String execute() {
System.out.println("exeption in handler " + exception);
return SUCCESS;
}
}
BusinessLogic.java:
package test;
public class BusinessLogic {
public void test() {
System.out.println("test logic");
// boolean flag = true;
// if (flag) throw new RuntimeException("qwerty");
}
}
So, console output :
test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty
BUT if an exception is thrown by BusinnesLogic, we can uncomment code:
BusinessLogic.java:
package test;
public class BusinessLogic {
public void test() {
System.out.println("test logic");
boolean flag = true;
if (flag) throw new RuntimeException("qwerty");
}
}
and comment out code in interceptor:
#Override
public String intercept(ActionInvocation arg0) throws Exception {
String result = null;
try {
result = arg0.invoke();
// boolean flag = true;
// if (flag) throw new RuntimeException("qwerty");
} catch (Exception e) {
System.out.println("exception catched in interceptor, rethrowing " + e);
throw e;
}
return result;
}
output will be:
test logic
exception catched in interceptor, rethrowing java.lang.RuntimeException: qwerty
setting exception
exeption in handler java.lang.RuntimeException: qwerty
And we will see the error page.
So, can anybody give a good explanation of this behavior? What's the point of putting the exception interceptor at the top of the default struts stack if it can't handle exceptions that was thrown by other interceptors? and why??
I would really appreciate for a good answer.
EDIT:
There is a code I have a problem with:
public String intercept(ActionInvocation arg0) throws Exception {
String result = null;
try {
sf.getCurrentSession().beginTransaction();
result = arg0.invoke();
sf.getCurrentSession().getTransaction().commit();
} catch (StaleObjectStateException staleEx) {
if (sf.getCurrentSession().getTransaction().isActive()) {
sf.getCurrentSession().getTransaction().rollback();
}
throw staleEx;
} catch (Exception ex) {
ex.printStackTrace();
try {
if (sf.getCurrentSession().getTransaction().isActive()) {
sf.getCurrentSession().getTransaction().rollback();
}
} catch (Throwable rbEx) {
}
// Let others handle it... maybe another interceptor for exceptions?
throw new ServletException(ex);
}
return result;
}
What should be done if I want handle exceptions thrown on commit() ?
The exception is thrown by TestInterceptor after the action invocation and result rendering.
From the note on the Writing Interceptors page:
Keep in mind that invoke will return after the result has been called (eg. after you JSP has been rendered), making it perfect for things like open-session-in-view patterns. If you want to do something before the result gets called, you should implement a PreResultListener.
Core Functionality of ExceptionMappingInterceptor
This interceptor forms the core functionality of the exception handling feature. Exception handling allows you to map an exception to a result code, just as if the action returned a result code instead of throwing an unexpected exception. When an exception is encountered, it is wrapped with an ExceptionHolder and pushed on the stack, providing easy access to the exception from within your result. Note: While you can configure exception mapping in your configuration file at any point, the configuration will not have any effect if this interceptor is not in the interceptor stack for your actions. It is recommended that you make this interceptor the first interceptor on the stack, ensuring that it has full access to catch any exception, even those caused by other interceptors.
Example code:
<xwork>
<package name="default" extends="xwork-default">
<global-results>
<result name="error" type="freemarker">error.ftl</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>
<action name="test">
<interceptor-ref name="exception"/>
<interceptor-ref name="basicStack"/>
<exception-mapping exception="com.acme.CustomException" result="custom_error"/>
<result name="custom_error">custom_error.ftl</result>
<result name="success" type="freemarker">test.ftl</result>
</action>
</package>
</xwork>

Categories