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

Reply via email to