public <T extends BusinessObject> void save(T bo) throws DataException {
    // reset the cache timer
    Cache.getInstance().put(bo.getId(), bo);

    // if the object isn't dirty, don't bother saving
    if (!bo.isDirty()) {
      return;
    }

    // save in the database
    Connection conn = ConnectionPool.getInstance().get();
    try {
      // get the superclasses of this object, putting them in reverse order (since they need to save that way for referential integrity).
      Class boClass = bo.getClass();
      List<Class> inheritance = new LinkedList<Class>();
      while (boClass != BusinessObject.class) {
        inheritance.add(0, boClass);
        boClass = boClass.getSuperclass();
      }

      // save the information in the businessobject table
      String sql = "INSERT INTO businessobject (botype, id) VALUES (?, ?)";
      if (bo.isObjectAlreadyInDB()) {
        sql = "UPDATE businessobject SET botype=? WHERE id=?";
      }
      PreparedStatement pstmt = conn.prepareStatement(sql);
      try {
        pstmt.setString(1, bo.getClass().getName());
        pstmt.setString(2, bo.getId());
        pstmt.execute();
      }finally{
        pstmt.close();
      }

      // step through the class hierarchy under BusinessObject and let each save to the database
      for (Class klass: inheritance) {
        if (bo.isObjectAlreadyInDB()) {
          update(bo, klass, conn);
        }else{
          insert(bo, klass, conn);
        }//if
      }

      // commit the changes
      conn.commit();

      // update the variables
      bo.setDirty(false);
      bo.setObjectAlreadyInDB(true);
    }catch (Exception e) {
      e.printStackTrace();
      try{
        conn.rollback();
      }catch (SQLException e2) {
        throw new DataException("Could not roll back the database transaction!", e2);
      }
      throw new DataException("An error occurred while saving the business object information.", e);
    }finally {
      ConnectionPool.getInstance().release(conn);
    }
  }//update