Uploaded image for project: 'OpenWebBeans'
  1. OpenWebBeans
  2. OWB-803

Forever loop when abstract decorator does not implement invoked method

    XMLWordPrintableJSON

Details

    Description

      If there is a decorated service, where the decorator is abstract and does not implement all methods of the interface,
      then there will occur a forever loop within the org.apache.webbeans.decorator.DelegateHandler#invoke(Object instance, Method method, Object[] arguments) (line: 89),
      if a method, which is not implemented in the abstract decorator, is tried to be invoked on the proxied decorator instance.

      This occured within the openEjb-Lite 4.5.1 which uses openwebbeans 1.1.7.
      As we have seen, owb 1.1.6 did implement it differently, so we switched back to OpebEjb-lite 4.5.0 which uses openwebbeans 1.1.6

      "org.apache.webbeans.decorator.DelegateHandler#invoke(Object instance, Method method, Object[] arguments) openwebbeans 1.1.7"
       public Object invoke(Object instance, Method method, Object[] arguments) throws Exception
          {
              // Tuck away a reference to the bean being Decorated
              if (actualInstance == null)
              {
                  actualInstance = instance;
              }
      
              int hit = 0;
              int decoratorsSize = decorators.size();
              while (position.get().intValue() < decoratorsSize)
              {
                  hit++;
      
                  // !!!!!! Current position will always be 1, this part is implemented differntly in 1.1.6  !!!!!!
                  int currentPosition = position.get().intValue();
                  Object decorator = decorators.get(position.get().getAndIncrement());
                  try
                  {
                      Method decMethod = decorator.getClass().getMethod(method.getName(), method.getParameterTypes());
                      boolean methodInInterface = checkForMethodInInterfaces(decorator.getClass(), method);
      
                      if (decMethod != null && methodInInterface)
                      {
                          if (!decMethod.isAccessible())
                          {
                              bean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(decMethod, true);
                          }
      
                          try
                          {
                              return decMethod.invoke(decorator, arguments);
                          }
                          finally
                          {
                              if (currentPosition == 0) // if we go back on the first decorator no more need of this thread local
                              {
                                  position.remove();
                              }
                          }
                      }
      
                  }
                  catch (SecurityException e)
                  {
                      logger.log(Level.SEVERE, OWBLogConst.ERROR_0011, WebBeansLoggerFacade.args(method.getName(), decorator.getClass().getName()));
                      throw new WebBeansException(e);
      
                  }
                  catch (NoSuchMethodException e)
                  {
                      continue;
                  }
                  catch (InvocationTargetException e)
                  {
                      Throwable cause = e.getCause();
                      //If the wrapped exception tells us the method didn't exist, continue
                      if(cause instanceof NoSuchMethodException)
                      {
                          continue;
                      }
      
                      logger.log(Level.SEVERE, OWBLogConst.ERROR_0012, WebBeansLoggerFacade.args(e.getTargetException(), method.getName(), decorator.getClass().getName()));
      
                      if (cause instanceof Exception)
                      {
                          throw (Exception) cause;
                      }
                      else if (cause instanceof Error)
                      {
                          throw (Error) cause;
                      }
                      else
                      {
                          throw new WebBeansException(e);
                      }
                  }
                  catch (IllegalAccessException e)
                  {
                      logger.log(Level.SEVERE, OWBLogConst.ERROR_0014, WebBeansLoggerFacade.args(method.getName(), decorator.getClass().getName()));
                      throw new WebBeansException(e);
                  }
      
              }
      
              if (hit == decoratorsSize) // if we hit all decorators but noone was called (see while loop) then clean here
              {
                  position.remove();
              }
      
              if (!method.isAccessible())
              {
                  bean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(method, true);
              }
      
              Object result = null;
              
              if(!(bean instanceof EnterpriseBeanMarker))
              {
                  result = method.invoke(actualInstance, arguments);
              }
              else
              {
                  if(ejbContext != null)
                  {
                      Method ejbMethod = ejbContext.getMethod();
                      
                      // don't use method.equals(), it may only differ by being abstract in the EJB proxy.
                       
                      if (method.getName().equals(ejbMethod.getName()) && 
                              method.getReturnType().equals(ejbMethod.getReturnType())) 
                      {
                          result = ejbContext.proceed();
                      }
      
                      else 
                      {
                          Object ejbInstance = ejbContext.getTarget();
                          result = method.invoke(ejbInstance, arguments);
                      }
                  }
              }
      
              return result;
      
          }
      
      "org.apache.webbeans.decorator.DelegateHandler#invoke(Object instance, Method method, Object[] arguments) openwebbeans 1.1.6"
         public Object invoke(Object instance, Method method, Object[] arguments) throws Exception
          {
              // Tuck away a reference to the bean being Decorated
              if (actualInstance == null)
              {
                  actualInstance = instance;
              }
      
              while (position.get().intValue() < decorators.size())
              {
      
      		    // !!!! No current position occurs here !!!!!
      			// !!!! This works when not implemented method of abstract decorator is tried to be invoked !!!!!
                  Object decorator = decorators.get(position.get().getAndIncrement());
      
                  try
                  {
                      Method decMethod = decorator.getClass().getMethod(method.getName(), method.getParameterTypes());
                      boolean methodInInterface = checkForMethodInInterfaces(decorator.getClass(), method);
      
                      if (decMethod != null && methodInInterface)
                      {
                          if (!decMethod.isAccessible())
                          {
                              bean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(decMethod, true);
                          }
      
                          Object returnValue = decMethod.invoke(decorator, arguments);
                          position.remove();
                          return returnValue;
                      }
      
                  }
                  catch (SecurityException e)
                  {
                      logger.log(Level.SEVERE, OWBLogConst.ERROR_0011, WebBeansLoggerFacade.args(method.getName(), decorator.getClass().getName()));
                      throw new WebBeansException(e);
      
                  }
                  catch (NoSuchMethodException e)
                  {
                      continue;
                  }
                  catch (InvocationTargetException e)
                  {
                      Throwable cause = e.getCause();
                      //If the wrapped exception tells us the method didn't exist, continue
                      if(cause instanceof NoSuchMethodException)
                      {
                          continue;
                      }
      
                      logger.log(Level.SEVERE, OWBLogConst.ERROR_0012, WebBeansLoggerFacade.args(e.getTargetException(), method.getName(), decorator.getClass().getName()));
      
                      if (cause instanceof Exception)
                      {
                          throw (Exception) cause;
                      }
                      else if (cause instanceof Error)
                      {
                          throw (Error) cause;
                      }
                      else
                      {
                          throw new WebBeansException(e);
                      }
                  }
                  catch (IllegalAccessException e)
                  {
                      logger.log(Level.SEVERE, OWBLogConst.ERROR_0014, WebBeansLoggerFacade.args(method.getName(), decorator.getClass().getName()));
                      throw new WebBeansException(e);
                  }
      
              }
      
              position.remove();
      
              if (!method.isAccessible())
              {
                  bean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(method, true);
              }
      
              Object result = null;
              
              if(!(bean instanceof EnterpriseBeanMarker))
              {
                  result = method.invoke(actualInstance, arguments);
              }
              else
              {
                  if(ejbContext != null)
                  {
                      Method ejbMethod = ejbContext.getMethod();
                      
                      // don't use method.equals(), it may only differ by being abstract in the EJB proxy.
                       
                      if (method.getName().equals(ejbMethod.getName()) && 
                              method.getReturnType().equals(ejbMethod.getReturnType())) 
                      {
                          result = ejbContext.proceed();
                      }
      
                      else 
                      {
                          Object ejbInstance = ejbContext.getTarget();
                          result = method.invoke(ejbInstance, arguments);
                      }
                  }
              }
              
              return result;
      
          }
      

      Attachments

        1. DecoratorForeverLoopDemo.zip
          8 kB
          Thomas Herzog

        Activity

          People

            romain.manni-bucau Romain Manni-Bucau
            cchet Thomas Herzog
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: