/**
  * Retrieve the persistent bean with id <code>form.getIdFromForm()</code> from the persistent
  * storage, and set it in the form. This method does not deal with transactions. A transaction
  * needs to be started and closed around a call to this method.
  *
  * @pre form != null;
  * @pre asyncCRUD != null;
  */
 private void retrieveWithId(final CrudDynaActionForm form, final AsynchronousCRUD asyncCRUD)
     throws IdException, TechnicalException {
   assert form != null;
   assert asyncCRUD != null;
   Long id = form.getIdFromForm(); // IdException
   Class type = form.getPersistentBeanType();
   if (id == null) {
     throw new IdException("ID_NULL", null, type); // $NON-NLS-1$
   }
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "retrieving persistent bean with id " //$NON-NLS-1$
             + id.toString()
             + " and type " //$NON-NLS-1$
             + type.getName()
             + "..."); //$NON-NLS-1$
   }
   form.setPersistentBean(asyncCRUD.retrievePersistentBean(id, type));
   // pre id != null; IdNotFoundException
   if (LOG.isDebugEnabled()) {
     // if makes that there really is lazy loading if not in debug
     LOG.debug(
         "retrieved persistent bean is " //$NON-NLS-1$
             + form.getPersistentBean());
   }
   assert form.getPersistentBean() != null;
   assert form.getPersistentBean()
       .getId()
       .toString()
       .equals(form.get(CrudDynaActionForm.ID_PROPERTY_NAME));
 }
 /**
  * Display request mode means that the user requested the application to display an object. In
  * display request mode, data is retrieved from persistent storage and simply displayed in a
  * non-editable way. The request should provide an {@link PersistentBean#getId()}. Edit request
  * mode means that the user request the application to display an existing object for editing. In
  * edit request mode, data is retrieved from persistent storage and displayed in an HTML form, so
  * that it can be edited. The request should provide an {@link PersistentBean#getId()}.
  *
  * @pre form.getPersistentBean() != null;
  * @pre request != null;
  */
 private void templateRetrieve(
     final CrudDynaActionForm form, final boolean viewModeEdit, final HttpServletRequest request)
     throws IdException, TechnicalException {
   assert request != null;
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "retrieve for " //$NON-NLS-1$
             + (viewModeEdit
                 ? "edit" //$NON-NLS-1$
                 : "display") //$NON-NLS-1$
             + " ..."); //$NON-NLS-1$
   }
   AsynchronousCRUD asyncCRUD = createAsynchronousCRUD(request);
   try {
     // we are not doing this in a transaction, deliberately
     retrieveWithId(form, asyncCRUD); // IdException
     if (LOG.isDebugEnabled()) {
       LOG.debug("retrieve action succeeded"); // $NON-NLS-1$
     }
     form.beanToForm(asyncCRUD);
     /*
      * We are not doing this in a transaction, deliberately. This means data
      * that is shown could be out of sync; but chances are this will hardly
      * occur, and if it does, errors will be caught when something is really
      * done. @todo (jand): think more about this
      */
     /*
      * on IdException, we go to a different page that shows a not found
      * message. For this page we do not need to set any information
      */
   } finally {
     releaseAsynchronousCRUD(asyncCRUD);
   }
   form.setViewModeEdit(viewModeEdit);
   form.setViewModeDeleted(false);
   form.setViewModeNew(false);
 }
 /**
  * New request mode means that the user requests the application to present a form with default
  * information, to be able to request the application to create a new object in the next step. In
  * new request mode, a new persistent bean is created with default data and displayed in an HTML
  * form, so that it can be edited. All the data that is already in this request is used to display
  * the new entity the first time.
  *
  * @throws BeanInstantiationException Could not create a new bean of the expected type.
  * @throws TechnicalException Could evaluate data for a technical reason
  * @throws CompoundPropertyException Some of the provided data is wrong.
  */
 private void templateNew(final CrudDynaActionForm form, final HttpServletRequest request)
     throws BeanInstantiationException, TechnicalException, CompoundPropertyException {
   if (LOG.isDebugEnabled()) {
     LOG.debug("new action ..."); // $NON-NLS-1$
   }
   form.initBean(); // bean contains programmatic defaults
   /*
    * BeanInstantiationException; this means that the app is wrongly
    * configured; this will generate a general error page.
    */
   assert form.getPersistentBean() != null;
   assert form.getPersistentBean().getId() == null;
   form.beanToId();
   AsynchronousCRUD asyncCRUD = createAsynchronousCRUD(request);
   CompoundPropertyException cpExcStore = null;
   try {
     // @todo (dvankeer): Why re-use the data?
     try {
       form.formToBean(asyncCRUD);
       /* get the data that is already in this request,
       overwriting programmatic defaults */
     } catch (CompoundPropertyException cpExc) {
       cpExcStore = cpExc;
       // remember this exception
     }
     // we are not doing this in a transaction, deliberately
     // @todo (jand): is this a good idea?
     form.beanToForm(asyncCRUD);
     // copy default data and data already set into the form
   } finally {
     releaseAsynchronousCRUD(asyncCRUD);
   }
   form.setViewModeNew(true);
   assert form.isViewModeEdit();
   assert !form.isViewModeDeleted();
   if (LOG.isDebugEnabled()) {
     LOG.debug("new action succeeded"); // $NON-NLS-1$
   }
   if (cpExcStore != null) {
     throw cpExcStore;
   }
 }
 /**
  * Delete request mode means that the user requests the application to delete an existing bean. In
  * delete request mode, existing data is deleted from persistent storage. The request should
  * provide data for the {@link PersistentBean#getId()}. If the delete operation succeeds, the data
  * is displayed in a non-editable way, with a notice that signifies successful deletion. If the
  * delete operation fails, the data is displayed in a non-editable way, with an error notice. This
  * method first sets the id of the persistent bean from the request. Next, the persistent bean is
  * retrieved from the database. Only after that, the persistent bean will be deleted. This is done
  * to have an early warning of errors in the key, or access violations.
  *
  * @idea (jand) This would also make it possible to check here whether all information in the
  *     request matches the information in persistent storage during this transaction.
  * @pre form != null;
  * @pre form.getPersistentBean() != null;
  * @pre request != null;
  */
 private void templateDelete(final CrudDynaActionForm form, final HttpServletRequest request)
     throws CompoundPropertyException, IdException, TechnicalException {
   assert form != null;
   // assert form.getPersistentBean() != null;
   assert request != null;
   if (LOG.isDebugEnabled()) {
     LOG.debug("delete action ..."); // $NON-NLS-1$
   }
   form.setViewModeEdit(false);
   AsynchronousCRUD asyncCRUD = createAsynchronousCRUD(request);
   DeletedEvent pbdEvent = null;
   try {
     asyncCRUD.startTransaction();
     retrieveWithId(form, asyncCRUD); // IdException
     assert form.getPersistentBean() != null;
     pbdEvent = new DeletedEvent(form.getPersistentBean());
     asyncCRUD.deletePersistentBean(form.getPersistentBean());
     asyncCRUD.commitTransaction(form.getPersistentBean());
     assert form.getPersistentBean().getId() == null;
     form.beanToId(); // must be null
     form.setViewModeDeleted(true); // rae.isEmpty());
     if (LOG.isDebugEnabled()) {
       LOG.debug("delete action succeeded"); // $NON-NLS-1$
     }
   } catch (CompoundPropertyException cpExc) {
     asyncCRUD.cancelTransaction();
     form.setViewModeDeleted(false);
     throw cpExc;
   } catch (IdException pkvExc) {
     asyncCRUD.cancelTransaction();
     form.setViewModeDeleted(false);
     throw pkvExc;
   } finally {
     form.beanToForm(asyncCRUD);
     releaseAsynchronousCRUD(asyncCRUD);
   }
   fireCommittedEvent(pbdEvent);
   assert !form.isViewModeNew();
   assert !form.isViewModeEdit();
 }
 /**
  * Create request mode means that the user requests the application to create a new persistent
  * bean with supplied information.. In create request mode, new data is stored in persistent
  * storage. The request should provide data for all properties of the {@link PersistentBean},
  * except the {@link PersistentBean#getId()}. If the create operation succeeds, the data is simply
  * displayed in a non-editable way. If the create operation fails, the data is displayed in an
  * HTML form, so that it can be corrected.
  *
  * @pre form != null;
  * @pre form.getPersistentBean() != null;
  * @pre request != null;
  */
 private void templateCreate(final CrudDynaActionForm form, final HttpServletRequest request)
     throws CompoundPropertyException, TechnicalException {
   assert form != null;
   assert request != null;
   if (LOG.isDebugEnabled()) {
     LOG.debug("create action ..."); // $NON-NLS-1$
   }
   form.initBean();
   /*
    * BeanInstantiationException; this means that the app is wrongly
    * configured; this will generate a general error page.
    */
   assert form.getPersistentBean() != null;
   assert form.getPersistentBean().getId() == null;
   form.setViewModeDeleted(false);
   AsynchronousCRUD asyncCRUD = createAsynchronousCRUD(request);
   try {
     asyncCRUD.startTransaction();
     form.formToBean(asyncCRUD); // PropertyException, inside transaction
     form.getPersistentBean().setId(null);
     asyncCRUD.createPersistentBean(form.getPersistentBean());
     // PropertyException
     form.beanToId();
     form.beanToForm(asyncCRUD); // inside transaction
     asyncCRUD.commitTransaction(form.getPersistentBean());
     form.setViewModeEdit(false);
     CreatedEvent pbnEvent = new CreatedEvent(form.getPersistentBean());
     fireCommittedEvent(pbnEvent);
     assert !form.isViewModeNew();
     assert !form.isViewModeDeleted();
     if (LOG.isDebugEnabled()) {
       LOG.debug("create action succeeded"); // $NON-NLS-1$
     }
   } catch (CompoundPropertyException cpExc) {
     form.beanToForm(asyncCRUD);
     asyncCRUD.cancelTransaction();
     form.setViewModeNew(true);
     assert form.isViewModeEdit();
     assert !form.isViewModeDeleted();
     throw cpExc;
   } finally {
     releaseAsynchronousCRUD(asyncCRUD);
   }
 }
 /**
  * Update request mode means that the user requests the application to update existing information
  * with supplied information. In update request mode, data is stored in persistent storage. The
  * request should provide data for all properties of the {@link PersistentBean}. If the update
  * operation succeeds, the data is imply displayed in a non-editable way. If the update operation
  * fails, the data is displayed in an HTML form, so that it can be corrected. This method first
  * sets the id of the persistent bean from the request. Next, the persistent bean is retrieved
  * from the database. Only after that, the information from the request is filled out into the
  * bean. This is done to have an early warning of errors in the key, or access violations, but
  * mainly to make it possible to operate easily with a request that contains only partial
  * information, i.e., a request that only carries values for a subset of the properties of the
  * persistent bean. With this protocol, the given information will overwrite information that is
  * currently in persistent storage, but if there is no data in the request for a given property,
  * it's old value is retained. Once the data that is offered in the request is copied successfully
  * in the persistent bean, it is stored.
  *
  * @pre form != null;
  * @pre form.getPersistentBean() != null;
  * @pre request != null;
  */
 private void templateUpdate(final CrudDynaActionForm form, final HttpServletRequest request)
     throws IdException, CompoundPropertyException, TechnicalException {
   assert form != null;
   assert request != null;
   if (LOG.isDebugEnabled()) {
     LOG.debug("update action ..."); // $NON-NLS-1$
   }
   AsynchronousCRUD asyncCRUD = createAsynchronousCRUD(request);
   try {
     asyncCRUD.startTransaction();
     retrieveWithId(form, asyncCRUD); // IdException, TechnicalException
     assert form.getPersistentBean() != null;
     // @mudo (dvankeer): toString() needs to be replaced by something more
     //                   usefull.
     String oldBeanString = form.getPersistentBean().toString();
     form.formToBean(asyncCRUD); // PropertyException, inside transaction
     asyncCRUD.updatePersistentBean(form.getPersistentBean()); // PropertyException
     form.beanToForm(asyncCRUD); // inside transaction
     asyncCRUD.commitTransaction(form.getPersistentBean());
     releaseAsynchronousCRUD(asyncCRUD);
     // do not do this in a finally block; this can throw exceptions too
     form.setViewModeEdit(false);
     // @todo (jand): try to move this delta stuff to AsynchronousCRUD instead
     //               of here
     fireCommittedEvent(new UpdatedEvent(form.getPersistentBean(), oldBeanString));
   } catch (CompoundPropertyException cpExc) {
     form.beanToForm(asyncCRUD);
     if (LOG.isDebugEnabled()) {
       LOG.debug("update action failed; cancelling ...", cpExc); // $NON-NLS-1$
     }
     asyncCRUD.cancelTransaction();
     releaseAsynchronousCRUD(asyncCRUD);
     // do not do this in a finally block; this can throw exceptions too
     form.setViewModeEdit(true);
     LOG.debug("update action cancelled; rethrowing exeption"); // $NON-NLS-1$
     throw cpExc;
   }
   /*
    * on IdException, we go to a different page that shows a not found message.
    * For this page we do not need to set any information
    */
   form.setViewModeDeleted(false);
   form.setViewModeNew(false);
 }
 /**
  * @see Action#execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse)
  * @param actionMapping The ActionMapping used to select this instance
  * @param actionForm The optional ActionForm bean for this request (if any)
  * @param request The request we are processing
  * @param response The response we are creating
  * @pre actionForm instanceof CrudDynaActionForm;
  * @pre ; actionMapping contains forward with name "success"
  * @throws TechnicalException A fatal error from which recovery is not possible.
  */
 public final ActionForward execute(
     final ActionMapping actionMapping,
     final ActionForm actionForm,
     final HttpServletRequest request,
     final HttpServletResponse response)
     throws TechnicalException {
   if (LOG.isDebugEnabled()) {
     LOG.debug("start action request processing ..."); // $NON-NLS-1$
   }
   assert actionForm instanceof CrudDynaActionForm;
   CrudDynaActionForm form = ((CrudDynaActionForm) actionForm);
   ActionForward forward = actionMapping.findForward(ILLEGAL_ACCESS);
   if (requestParamExistsAndIsNotEmpty(REQUEST_MODE_CANCEL_NEW, request)) {
     String referer = request.getParameter("referer"); // $NON-NLS-1$
     referer = referer.replaceAll("https?://.*/.*/", "/"); // $NON-NLS-1$ //$NON-NLS-2$
     forward = new ActionForward(referer, true);
   } else { // handle each mode, after checking that this user has the rights
     try {
       if (requestParamExistsAndIsNotEmpty(REQUEST_MODE_EDIT, request)) {
         if ((getSecurityStrategy() != null)
             && getSecurityStrategy().hasEditRights(request, actionMapping, actionForm)) {
           forward = actionMapping.getInputForward();
           templateRetrieve(form, true, request);
         }
       } else if (requestParamExistsAndIsNotEmpty(REQUEST_MODE_NEW, request)) {
         if ((getSecurityStrategy() != null)
             && getSecurityStrategy().hasNewRights(request, actionMapping, actionForm)) {
           forward = actionMapping.getInputForward();
           templateNew(form, request);
         }
       } else if (requestParamExistsAndIsNotEmpty(REQUEST_MODE_UPDATE, request)) {
         if ((getSecurityStrategy() != null)
             && getSecurityStrategy().hasUpdateRights(request, actionMapping, actionForm)) {
           forward = actionMapping.getInputForward();
           templateUpdate(form, request); // return to edit mode on errors
         }
       } else if (requestParamExistsAndIsNotEmpty(REQUEST_MODE_CREATE, request)) {
         if ((getSecurityStrategy() != null)
             && getSecurityStrategy().hasCreateRights(request, actionMapping, actionForm)) {
           forward = actionMapping.getInputForward();
           templateCreate(form, request);
         }
       } else if (requestParamExistsAndIsNotEmpty(REQUEST_MODE_DELETE, request)) {
         if ((getSecurityStrategy() != null)
             && getSecurityStrategy().hasDeleteRights(request, actionMapping, actionForm)) {
           forward = actionMapping.getInputForward();
           templateDelete(form, request);
         }
       } else { // display mode
         if (LOG.isDebugEnabled()
             && !requestParamExistsAndIsNotEmpty(REQUEST_MODE_DISPLAY, request)) {
           LOG.debug(
               "no dispatch parameter match found; " //$NON-NLS-1$
                   + "doing default display retrieve"); //$NON-NLS-1$
         }
         if ((getSecurityStrategy() != null)
             && getSecurityStrategy().hasDisplayRigths(request, actionMapping, actionForm)) {
           forward = actionMapping.getInputForward();
           templateRetrieve(form, false, request);
         }
       }
       form.releaseBean();
       if (getSecurityStrategy() != null) {
         // which buttons do we want to show on the next page?
         form.setCreateable(
             getSecurityStrategy().hasCreateRights(request, actionMapping, actionForm));
         form.setEditable(getSecurityStrategy().hasEditRights(request, actionMapping, actionForm));
         form.setDeleteable(
             getSecurityStrategy().hasDeleteRights(request, actionMapping, actionForm));
       } else { // no security strategy: all is allowed
         form.setCreateable(true);
         form.setEditable(true);
         form.setDeleteable(true);
       }
     } catch (IdException idExc) {
       if (LOG.isDebugEnabled()) {
         LOG.debug("id exception", idExc); // $NON-NLS-1$
       }
       request.setAttribute(REQUEST_ATTRIBUTE_KEY_NOTFOUND, idExc);
       forward = actionMapping.findForward(FORWARD_NOTFOUND);
     } catch (CompoundPropertyException cpExc) {
       if (LOG.isDebugEnabled()) {
         LOG.debug("property exception", cpExc); // $NON-NLS-1$
       }
       assert cpExc.isClosed();
       form.setCompoundPropertyException(cpExc);
       forward = actionMapping.getInputForward();
       form.releaseBean();
     }
   }
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "action request processing completed; forward = " //$NON-NLS-1$
             + forward.toString());
   }
   return forward;
 }