0 Replies Latest reply on Jun 4, 2013 2:23 PM by mateusz.lewandowski90

    CDI based custom framework

    mateusz.lewandowski90

      Hi everyone,

       

      I'm trying to write custom web framework for my study and hobby. And I have some problems. First of all: the framework should use thymeleaf as view layer, for validation there should be BeansValidation, JAAS as security standard, it should use EJB beans for business logic, JPA for database connection and CDI for connect this all things together. I have one servlet as an entry point to application and there should be controllers classes with appropriete annotation with specified path to controller and method in this controllers also could have annotations with paths. I managed to initialize all CDI contextx from my servlet, lookup for controllers in CDI extension class, add controllers as ApplicationScoped CDI beans to CDI container and push all CDI beans into thymeleaf elResolver context. So it almost works. EJB and JPA started to work out of box. But I have problems with mapping request parameters to CDI beans, apply beans validation and set up JAAS.

       

      When I got a request in my servlet, for each request parameter I search appropriete cdi bean and its property to set as this parameter variable. So if I for example have parameter with name user.email and named bean user with email property I lookup via BeanManager for bean user and via reflection I call setEmail if that methot exists to set email. After parse all parameters for each changed beans I call validator and here is where the problems begun. If in my controller I inject user beand wie @Inject and call getEmail method, I recieve a new email value from request, but when in method where I set this parameter from request I make breakpoint, then after setting parameter in debugger I still see the old value, also validator from BeansValidation seems to see this old email value. So, how should I map request parameter to CDI beans that everything will be ok?

       

      Here is code for setting new parameters:

       

              String[] keyPath = path.split("\\."); //split parameter name
              if (keyPath.length > 0) {
                  BeanWithClass bean = getBean(keyPath);
                  if (bean != null && bean.bean != null) {
                      if (bean.beanClass == null) {
                          bean.beanClass = bean.bean.getClass();
                      }
                      try {
                          setValue(bean, keyPath[keyPath.length - 1], value);
                      } catch (....) { // catch errors and log them
                          //but there are no errors here at this time
                      }
                  }
              }
      
      

       

      getBean method:

       

          private BeanWithClass getBean(String[] path) {
              Object bean = null;
              Class<?> beanClass = null;
              if (path.length > 0) {
                  Set<?> beans = bm.getBeans(path[0]); //bm is injected BeanManager
                  if (beans.size() > 0) {
                      Bean<?> beanDescriptor = (Bean<?>) beans.iterator().next();
                      CreationalContext creationalContext = bm.createCreationalContext(null);
                      bean = bm.getReference(beanDescriptor, beanDescriptor.getClass(), creationalContext);
                      beanClass = beanDescriptor.getBeanClass();
      
                      //here I go down into "objects tree"
                      for (int i = 1; i < path.length - 1; i++) {
                          try {
                              Field field = beanClass.getDeclaredField(path[i]);
                              beanClass = field.getType();
                              bean = field.get(bean);
                          } catch (IllegalAccessException e) {
                              logger.error(String.format("Cannot access field %s", path[i]));
                              throw new RuntimeException(e);
                          } catch (NoSuchFieldException e) {
                              logger.error(String.format("Field %s does not exists", path[i]));
                              throw new RuntimeException(e);
                          }
                      }
                  }
              }
              BeanWithClass beanWithClass = new BeanWithClass();
              beanWithClass.bean = bean;
              beanWithClass.beanClass = beanClass;
              return beanWithClass;
          }
      
      

       

      and setValue method:

       

          private void setValue(BeanWithClass bean, String propertyName,
                                Object value) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException,
                  IllegalAccessException {
              Field field = bean.beanClass.getDeclaredField(propertyName);
              String setterName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
              Method setter = bean.beanClass.getDeclaredMethod(setterName, field.getType());
              Object parsedValue = null;
      
      
              boolean canBeCasted = false;
              try {
                  canBeCasted = value.getClass().asSubclass(field.getType()).equals(value.getClass());
              } catch (Exception e) {
                  canBeCasted = false;
              }
      
      
              if (value.getClass().equals(field.getType()) || canBeCasted) {
                  parsedValue = value;
              } else {
                  //try to convert
                  ConverterWrapper converterWrapper = applicationAnalyser.getConverter(value.getClass(), field.getType());
                  if (converterWrapper != null) {
                      parsedValue = converterWrapper.getMethod().invoke(converterWrapper.getConverter(), value);
                  }
              }
      
      
              if (parsedValue != null) {
                  setter.invoke(bean.bean, parsedValue);
              }
          }
      
      

       

      If after that I try to valudate modified bean via injected validator it's always see the old values in beans.

       

      The second problem is JAAS, it just do no work. If I have my controller method annotated with @RolesAllowed annotation or ejb methods used in controller are annotated with this annotation simply nothing happens. I call my conrtroller metods via reflection just like with setting beans properties.

       

      I would be really glad if someone can held me.

       

      Edit:

       

      I have some progress:) JAAS works when secured paths is configured in web.xml, but I also wont annotation configuration to work. The first problem was in Jboss configuration.

      But the bigger problem is still setings cdi beans properties from request.