5 Replies Latest reply on Feb 17, 2009 7:28 PM by Val Sw

    EntityHome validations

    Miguel Cohnen Newbie

      Hi,
      I would like to know if it is possible to return a certain value in persist or update methods of EntityHome class, so that it fails and does not show the 'Succesfully updated' message. I want this because I'm validating some fields that are not part of the Entity itself (and therefor not affected by any hibernate validators...). I'm trying returning null from those methods but this doesn't seem to work...


      any suggestions? Thank you!

        • 1. Re: EntityHome validations
          Val Sw Expert
          Are you trying to provide validation, if so this is simple sample, it checks for duplicate value.

          Home
          ----
          public String persist(){
          try {
              boolean boolDup = ValidationUtil.findDup(alKey);     
              if(boolDup){
               return "duplicateValue";
              }else{
               .....
              }
             catch (Exception e) {
              return "persistError";               
          }
          super.persist();
          }

          xxxx.Page.xml
          -------------
          <navigation from-action="#{xxxxHome.persist}">
                    <rule if-outcome="duplicateValue">
                         <render view-id="/xxxxxEdit.xhtml">
                              <message severity="error">
                                   Duplicate value found, please select different value.
                              </message>
                         </render>
                    </rule>
                    
                    <rule if-outcome="persisted">
                         <end-conversation />
                         <redirect view-id="/xxxxxList.xhtml" />
                    </rule>
          </navigation>
          • 2. Re: EntityHome validations
            Miguel Cohnen Newbie

            Thank you for answer! Actually, my case is more complicated. I have a translation table, to apply i18n translations to jpa. This translations are not part of the Entity Object, but just a map in the EntityHome object. So, if there are errors in the validation of this fields, I should rollback all operations taken in the persist method. Is this possible? I'm returning persistError but this does not rollback all the operations done in the database (ie already added one of the translations).


            Is this approach possible?


            Thank you!

            • 3. Re: EntityHome validations
              Val Sw Expert

              Trying to understand your issue, if Translation table is not part of entity, are the values inserted using jdbc or how ?


              It will be nice if code block is posted.

              • 4. Re: EntityHome validations
                Miguel Cohnen Newbie

                Hi, I am using this library: http://code.google.com/p/jpa-translator


                It basically adds some interceptors to the Entity. You configure the translation tables (using jpa) and then simply:


                Translator translator = new Translator( Locale.GERMAN );
                Hotel translatedHotel = translator.translate( hotel );
                translatedHotel.getDescription(); // return description in german
                translatedHotel.setDescription( "die Beschreibung" ); // persist german description



                Before saving this translated versions, I validate against the Hotel hibernate validations using ClassValidator. This is the code of my HomeEntity class:



                public class TranslationEntityHome<E> extends EntityHome<E> {
                
                     @In
                     protected SeamTranslator translator;
                     
                     @In
                     FacesMessages facesMessages;
                     
                     @In
                     protected LocaleSelector localeSelector;
                     
                     @RequestParameter
                     protected Boolean loadTranslations;
                
                     private Map<String, Map<String, String>> translations;
                
                     @Override
                     @Begin
                     public void create() {
                          super.create();
                          translations = new HashMap<String, Map<String, String>>();
                          for (SelectItem locale:localeSelector.getSupportedLocales()){
                               if (!locale.getValue().toString().equals(LocaleConfig.instance().getDefaultLocale())){
                                    translations.put(locale.getValue().toString(), new HashMap<String, String>());
                               }
                          }
                     }
                
                     @Override
                     public String update() {
                          if (persistTranslations()==null){
                               return "persistError";
                          }
                          return super.update();
                     }
                
                     private String persistTranslations() {
                          //getEntityManager().refresh(getInstance());
                          try {
                               for (Map.Entry<String, Map<String, String>> entry : translations
                                         .entrySet()) {
                                    translator.setLocale(new Locale(entry.getKey()));
                                    E trans = translator.translate(getInstance());
                                    for (Map.Entry<String, String> entry2 : entry.getValue()
                                              .entrySet()) {
                                         // Always allow blank messages
                                         if (entry2.getValue()==null || entry2.getValue().trim().length()==0){
                                              continue;
                                         }else{
                                              // Validation
                                              ClassValidator<E> validator = new ClassValidator<E>(getEntityClass());
                                              InvalidValue[] errors = validator.getPotentialInvalidValues(entry2.getKey(), entry2.getValue());
                                              for(InvalidValue iv:errors){
                                                   facesMessages.addToControl(iv);
                                              }
                                              if (errors.length>0){
                                                   return null;
                                              }
                                         }
                                         Class<?> c = getInstance().getClass();
                                         Method m = c.getDeclaredMethod("set"
                                                   + StringUtil.capitalize(entry2.getKey()),
                                                   String.class);
                                         m.invoke(trans, entry2.getValue());
                                    }
                               }
                          } catch (Exception e) {
                               // TODO
                               e.printStackTrace();
                               return null;
                          }finally{
                               translator.resetLocale();
                          }
                          return "persisted";
                     }
                
                     @Override
                     public String persist() {
                          String res = super.persist();
                          if (persistTranslations()==null){
                               return null;
                          }
                          getEntityManager().flush();
                          return res;
                     }
                
                     @Override
                     public E find() { 
                          E res = super.find();
                          if (loadTranslations!=null && loadTranslations) {
                               try {
                                    for (Map.Entry<String, Map<String, String>> entry : translations
                                              .entrySet()) {
                                         translator.setLocale(new Locale(entry.getKey()));
                                         E trans = translator.translate(res);
                                         Class<?> c = res.getClass();
                                         for (Field f : c.getDeclaredFields()) {
                                              if (f.isAnnotationPresent(Translate.class)) {
                                                   String value = (String) c.getMethod(
                                                             "get" + StringUtil.capitalize(f.getName()))
                                                             .invoke(trans);
                                                   translations.get(entry.getKey()).put(f.getName(),
                                                             value);
                                              }
                                         }
                                    }
                                    
                               } catch (Exception e) {
                                    // TODO
                                    e.printStackTrace();
                               }finally{
                                    translator.resetLocale();
                               }
                          }else{
                               translator.resetLocale();
                               res = translator.translate(res);
                          }
                          return res;
                     }
                
                     public Map<String, Map<String, String>> getTranslations() {
                          return translations;
                     }
                
                     public void setTranslations(Map<String, Map<String, String>> translations) {
                          this.translations = translations;
                     }
                }



                As you can see, I first save/validate the translations, that are hold in a map on the HomeEntity (just temporary), and then call super.persist() if everything goes fine. The problem is that I'm saving every translation (adding those interceptors) once it passes validation. Let's say validation is OK for translation in spanish (I call setMethod in the translated instance, but the second one fails. persistTranslations method will return null, so super.persist() won't be called, but the first interceptor (the one for the spanish translation) has already been set, and therefor commits. I want to rollback everything in the persist method if a validation error occurs...


                I hope you can understand it now. If now, I will try to make it clearer.


                Just want to rollback everything that happened in the persist method if some programatically circunstances (validation errors) occur.


                Thank you very much!




                • 5. Re: EntityHome validations
                  Val Sw Expert
                  Your "programatically circumstances" will return null if any error, right?

                  I would say I am not an expert, so please don't mind if I am wrong. I can test it...

                  Why "getEntityManager().flush();" is called, I think super.persist() will take care of it.

                  a) You can try this, also you can try using "FlushModeType.MANUAL", I used it some time back in one of my entityHome.update

                  @Override
                  public String persist() {     
                       if (persistTranslations()==null){
                            return null;
                       }else{
                            return super.persist();
                       }
                  }

                  b) @Begin(join=true, flushMode=org.jboss.seam.annotations.FlushModeType.MANUAL)
                      public String persist(){          
                            //// SOME VALIDATIONS
                            return super.persist();
                       }