Hello-
I am abit confused on what is actually happening here so I was hoping someone
could shed some light. I have an application based on Struts running in the Resin
application server. The application contains a simple user manager that allows you to
create users, assign users a role, and assign users to a company. The problem I am
having is this...
I can add a user just fine, I can also modify and delete the user with no
problem, except for this single problem. When a user comes into the user manager they
are presented with a form that lists the users, the query to get this list is done
setting the database to readonly mode. The user then clicks on the edit button for a
specific user and is taken to a form contains all the user information, part of this
form is a set of four radio buttons representing the users role. I can change anything
about this user but the role with no problem. If I change the role I get the error:
"Object, com.searchdog.sysadmin.application.User@239780, links to another
object, com.searchdog.sysadmin.application.Role@af7a03 that is not
loaded/updated/created in this transaction."
So, to fix this I add the line calling Database.update() on the role object. I
can now save the updated user, unless I don't change the Role, then I get the error:
"org.exolab.castor.jdo.DuplicateIdentityException: update object which is
already in the transaction"
What is going on? I have included my code below so you can view it if
neccessary, I am using the built in database pooling by Resin and the postgres
database.
==============================================
Struts Action Populating Form w/ Existing Data
==============================================
package com.searchdog.sysadmin.struts;
/* Import Struts & Stxx Classes. */
import com.oroad.stxx.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.util.MessageResources;
/* Import JDOM Classes. */
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
/* Import Java Servlet Classes. */
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
/* Import Various Java Utility Classes. */
import java.net.URL;
import java.util.Locale;
/* Import Exception Classes. */
import java.io.IOException;
/* Import Application Classes. */
import com.searchdog.sysadmin.application.*;
/**
* UserEditAction class extends the basic Stxx Action class.
* This class will create a form allowing the user to edit
* a existing database user, it will populate the form with
* the current database information for the user.
*/
public class UserEditAction extends Action {
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
//
// Create the objects this method needs.
//
Document document;
Element doc;
Element body;
Element xmlform;
Element hiddeninput;
Element formaction;
Element inputvalue;
UserManager um;
RoleManager rm;
User user;
Role role;
UserForm uform = (UserForm)form;
//
// Get the base xml representation of the user form from the
// file userForm.xml found in the application classpath.
//
try {
ClassLoader cl=getClass().getClassLoader();
URL u = cl.getResource("userFormEdit.xml");
SAXBuilder parser = new SAXBuilder();
document = parser.build(u);
} catch (Exception e) {
throw new ServletException("Error creating edit user form from xml file.", e);
}
//
// Get the body and form elements we will need to manipulate.
//
doc = document.getRootElement();
body = doc.getChild("body");
xmlform = body.getChild("form");
//
// Populate the user form with data from the database.
//
Integer userId = new Integer(uform.getId());
if (userId != null) {
try {
um = new UserManager();
rm = new RoleManager();
// Set the user id that we want from the database.
um.setCurrentUserId(userId.intValue());
// Get the user from the database.
user = um.getUser();
role = user.getRole();
// Add required hidden input fields.
hiddeninput = new Element("hiddeninput");
hiddeninput.setAttribute("name", "id");
hiddeninput.setAttribute("value", String.valueOf(user.getId()));
xmlform.addContent(hiddeninput);
/* Add the form values to the xml document. */
inputvalue = new Element("inputvalue");
inputvalue.setAttribute("name", "firstName");
inputvalue.setText(user.getFirstName());
xmlform.addContent(inputvalue);
inputvalue = new Element("inputvalue");
inputvalue.setAttribute("name", "lastName");
inputvalue.setText(user.getLastName());
xmlform.addContent(inputvalue);
inputvalue = new Element("inputvalue");
inputvalue.setAttribute("name", "email");
inputvalue.setText(user.getEmail());
xmlform.addContent(inputvalue);
inputvalue = new Element("inputvalue");
inputvalue.setAttribute("name", "password");
inputvalue.setText(user.getPassword());
xmlform.addContent(inputvalue);
inputvalue = new Element("inputvalue");
inputvalue.setAttribute("name", "pwConfirm");
inputvalue.setText(user.getPassword());
xmlform.addContent(inputvalue);
inputvalue = new Element("inputvalue");
inputvalue.setAttribute("name", "roleId");
inputvalue.setText(String.valueOf(role.getId()) );
xmlform.addContent(inputvalue);
} catch (Exception e) {
throw new ServletException("An error occured populating the edit user form.",
e);
}
} else {
throw new ServletException("Cannot create an edit user form without a system
id.");
}
//
// Save the document to the request object.
//
saveDocument(request, document);
//
// Nothing went wrong so forward success.
//
return mapping.findForward("success");
}
}
============================
Struts Action Saving Changes
============================
package com.searchdog.sysadmin.struts;
/* Import Struts & Stxx Classes. */
import com.oroad.stxx.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.util.MessageResources;
/* Import JDOM Classes. */
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
/* Import Java Servlet Classes. */
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
/* Import Various Java Utility Classes. */
import java.net.URL;
import java.util.Locale;
/* Import Exception Classes. */
import java.io.IOException;
/* Import Application Classes. */
import com.searchdog.sysadmin.application.*;
/**
* UserEditAction class extends the basic Stxx Action class.
* This class will create a form allowing the user to edit
* a existing database user, it will populate the form with
* the current database information for the user.
*/
public class UserSaveAction extends Action {
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
//
// Create the objects this method needs.
//
Document document;
Element doc;
Element body;
Element xmlform;
Element hiddeninput;
Element formaction;
Element inputvalue;
UserManager um;
RoleManager rm;
User user;
Role role;
String action;
UserForm uform = (UserForm)form;
//
// Get the base xml representation of the user form from the
// file userForm.xml found in the application classpath.
//
try {
ClassLoader cl=getClass().getClassLoader();
URL u = cl.getResource("userFormEdit.xml");
SAXBuilder parser = new SAXBuilder();
document = parser.build(u);
} catch (Exception e) {
throw new ServletException("Error creating edit user form from xml file.", e);
}
//
// Get the body and form elements we will need to manipulate.
//
doc = document.getRootElement();
body = doc.getChild("body");
xmlform = body.getChild("form");
//
// Find out what this action should do according to request.
//
action = uform.getAction();
//
// Save a new user represented by the submitted form.
//
if(action.equals("saveNew")) {
try {
// Instantiat Required Objects.
um = new UserManager();
rm = new RoleManager();
user = new User();
role = new Role();
// Get the role object specified by the form.
rm.setCurrentRoleId(uform.getRoleId());
role = rm.getRole();
// Add values to the user.
user.setFirstName(uform.getFirstName());
user.setLastName(uform.getLastName());
user.setEmail(uform.getEmail());
user.setPassword(uform.getPassword());
user.setRole(role);
// Add the user object to the database.
um.addUser(user);
// Go back to the user list.
return mapping.findForward("success");
} catch (Exception e) {
throw new ServletException("An error occured saving the new user.", e);
}
}
//
// Save existing user represented by form.
//
if(action.equals("saveExisting")) {
Integer userId = new Integer(uform.getId());
if (userId != null) {
try {
// Instantiat Required Objects.
um = new UserManager();
rm = new RoleManager();
user = new User();
role = new Role();
// Get the role object specified by the form.
rm.setCurrentRoleId(uform.getRoleId());
role = rm.getRole();
// Add values to the user object.
user.setId(userId.intValue());
user.setFirstName(uform.getFirstName());
user.setLastName(uform.getLastName());
user.setEmail(uform.getEmail());
user.setPassword(uform.getPassword());
user.setRole(role);
// Update the existing user object with new values.
um.updateUser(user);
// Go back to the user list.
return mapping.findForward("success");
} catch (Exception e) {
throw new ServletException("An error occured while updating the user.", e);
}
} else {
throw new ServletException("Cannot save existing user without system id.");
}
}
//
// Delete existing user represented by form.
//
if(action.equals("deleteExisting")) {
Integer userId = new Integer(uform.getId());
if (userId != null) {
try {
// Instantiat Required Objects.
um = new UserManager();
rm = new RoleManager();
user = new User();
role = new Role();
// Add values to the user object.
user.setId(uform.getId());
// Delete the specified user.
um.deleteUser(user);
// Go back to the user list.
return mapping.findForward("success");
} catch (Exception e) {
throw new ServletException("An error occured delete the user.", e);
}
} else {
throw new ServletException("Cannot delete existing user without system id.");
}
}
//
// Should never reach this point.
//
return mapping.findForward("success");
}
}
=================
UserManager Class
=================
package com.searchdog.sysadmin.application;
/* Import Castor classes. */
import org.exolab.castor.jdo.JDO;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.OQLQuery;
import org.exolab.castor.jdo.QueryResults;
/* Import JNDI classes. */
import javax.naming.InitialContext;
import javax.naming.Context;
/* Import application classes. */
import com.searchdog.sysadmin.application.*;
/**
* UserManager handles the creating, fetching, updating and
* deleting of User objects from the database using Castor
* JDO. These actions are accomplished manipulating objects which
* implement the TimeStampable class inside of a Castor JDO
* transaction.
*/
public class UserManager extends Object {
/*
* Castor JDO database connection and query objects.
*/
private Context env;
private JDO jdo;
private Database db;
private OQLQuery oql;
private QueryResults result;
/*
* Application sepecific objects to be manipulated.
*/
private User user;
private Role role;
private int currentUserId;
/**
* Constructor method for the UserManager class this method
* gets a JDO object via a JNDI lookup and sets it for use by other
* methods in this class.
*/
public UserManager() throws Exception {
super();
env = (Context)new InitialContext().lookup("java:comp/env");
jdo = (JDO)env.lookup("jdo/pbuilder");
}
/**
* Setter method for the company object.
*/
public void setUser(User user) throws Exception {
this.user = user;
}
/**
* Getter method for the user object. This method returns a
* User object from the database using our OR software. The
* query used in this method uses the currentUserId value
* which is setable from outside this class.
*/
public User getUser() throws Exception {
// Get a database connection.
db = jdo.getDatabase();
// Get the user from the database.
try {
db.begin();
oql = db.getOQLQuery( "SELECT u FROM com.searchdog.sysadmin.application.User u
WHERE id = $1" );
oql.bind( currentUserId );
result = oql.execute(db.ReadOnly);
while ( result.hasMore() ) {
this.user = (User)result.next();
}
result.close();
oql.close();
db.commit();
db.close();
} catch (Exception e) {
// Rollback transaction on failure, throw exception.
db.rollback();
throw new Exception("Error retrieving User object from database.", e);
}
return this.user;
}
/**
* Setter method for the currentUserId method.
*/
public void setCurrentUserId(int id) {
this.currentUserId = id;
}
/**
* Getter method for the currentCompanyId method.
*/
public int getCurrentUserId() {
return this.currentUserId;
}
/**
* AddUser method adds the submitted User object to the
* database using or OR software.
*/
public void addUser(User user) throws Exception {
// Get a database connection.
db = jdo.getDatabase();
// Add the user to the database.
try {
db.begin();
db.create( user );
db.commit();
db.close();
} catch (Exception e) {
// Rollback transaction on failure, throw exception.
db.rollback();
throw new Exception("Error adding User object to the database.", e);
}
}
/**
* UpdateUser method updates the submitted User object in the
* database using our OR software.
*/
public void updateUser(User updatedUser) throws Exception {
// Get a database connection.
db = jdo.getDatabase();
// Update the company in the database.
try {
// Get the user from the database.
db.begin();
oql = db.getOQLQuery( "SELECT u FROM com.searchdog.sysadmin.application.User u
WHERE id = $1" );
oql.bind( updatedUser.getId() );
result = oql.execute();
while (result.hasMore()) {
this.user = (User)result.next();
}
result.close();
// Update the general user settings.
this.user.setFirstName( updatedUser.getFirstName() );
this.user.setLastName( updatedUser.getLastName() );
this.user.setEmail( updatedUser.getEmail() );
this.user.setPassword( updatedUser.getPassword() );
// Udate the role information.
Role updatedRole = updatedUser.getRole();
db.update(updatedRole);
this.user.setRole( updatedRole );
// Save the updated user to the database.
oql.close();
db.commit();
db.close();
} catch (Exception e) {
// Rollback transaction on failure, throw exception.
if (db.isActive()) {
db.rollback();
}
throw new Exception("Error updating User object in the database.", e);
}
}
/**
* DeleteUser method deletes the submitted User object from
* the database.
*/
public void deleteUser(User deletedUser) throws Exception {
// Get a database connection.
db = jdo.getDatabase();
// Remove the company from the database.
try {
// Get the user from the database.
db.begin();
oql = db.getOQLQuery( "SELECT u FROM com.searchdog.sysadmin.application.User u
WHERE id = $1" );
oql.bind( deletedUser.getId() );
result = oql.execute();
while (result.hasMore()) {
this.user = (User)result.next();
}
result.close();
// Remove user from the database.
oql.close();
db.remove(this.user);
// Commit changes and close database.
db.commit();
db.close();
} catch (Exception e) {
// Rollback transaction on failure, throw exception.
db.rollback();
throw new Exception("Error removing User object from the database.", e);
}
}
}
=================
RoleManager Class
=================
package com.searchdog.sysadmin.application;
/* Import Castor classes. */
import org.exolab.castor.jdo.JDO;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.OQLQuery;
import org.exolab.castor.jdo.QueryResults;
/* Import JNDI classes. */
import javax.naming.InitialContext;
import javax.naming.Context;
/* Import application classes. */
import com.searchdog.sysadmin.application.*;
/**
* RoleManager handles the fetching of Company objects from the
* database using Castor JDO. These actions are accomplished
* manipulating objects which implement the TimeStampable class
* inside of a Castor JDO transaction.
*/
public class RoleManager extends Object {
/*
* Castor JDO database connection and query objects.
*/
private Context env;
private JDO jdo;
private Database db;
private OQLQuery oql;
private QueryResults result;
/*
* Application sepecific objects to be manipulated.
*/
private Role role;
private int currentRoleId;
/**
* Constructor method for the RoleManager class this method
* gets a JDO object via a JNDI lookup and sets it for use by other
* methods in this class.
*/
public RoleManager() throws Exception {
super();
env = (Context)new InitialContext().lookup("java:comp/env");
jdo = (JDO)env.lookup("jdo/pbuilder");
}
/**
* Setter method for the Role object.
*/
public void setRole(Role role) throws Exception {
this.role = role;
}
/**
* Getter method for the Role object. This method returns a
* Role object from the database using our OR software. The
* query used in this method uses the currentRoleId value
* which is setable from outside this class.
*/
public Role getRole() throws Exception {
// Get a database connection.
db = jdo.getDatabase();
// Get the Role from the database.
try {
db.begin();
oql = db.getOQLQuery( "SELECT r FROM com.searchdog.sysadmin.application.Role r
WHERE id = $1" );
oql.bind( currentRoleId );
result = oql.execute(db.ReadOnly);
while ( result.hasMore() ) {
this.role = (Role)result.next();
}
oql.close();
db.commit();
db.close();
} catch (Exception e) {
// Rollback transaction on failure, throw exception.
db.rollback();
throw new Exception("Error retrieving Role object from database.", e);
}
return this.role;
}
/**
* Setter method for the currentRoleId property.
*/
public void setCurrentRoleId(int id) {
this.currentRoleId = id;
}
/**
* Getter method for the currentRoleId property.
*/
public int getCurrentRoleId() {
return this.currentRoleId;
}
}
Craig Anderson
Netstat Resources, LLC.
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev