docs: private static void addEJBInterceptorMethod(ClassWriter cw,
                                                  String className,
                                                  String implClassName,
                                                  Method method)
                      throws EJBConfigurationException
      {
          GeneratorAdapter mg;
          String methodName = method.getName();
          String methodSignature = MethodAttribUtils.jdiMethodSignature(method);
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              Tr.debug(tc, INDENT + "adding method : " +
                           methodName + " " + methodSignature +
                           " : isBridge = " + method.isBridge() +
                           " : aroundInvoke = true");
  
          // Determine the list of all exceptions, which will be on the throws
          // clause of the proxy method.  This will be all of the exceptions
          // on the bean implementation method throws clause.  This may not be
          // the same as the throws clause of the corresponding method on the
          // enpoint interface (if present), as the endpoint interface methods
          // may also throw RemoteException.  A Proxy represents the actual
          // bean implementation, unlike a Wrapper, which represents the
          // interface.
          Class<?>[] methodExceptions = method.getExceptionTypes();
  
          // Determine the list of 'checked' exceptions, which will need to have
          // catch blocks in the proxy. Exceptions that are subclasses of other
          // 'checked' exceptions will be eliminated, to avoid 'unreachable' code.
          Class<?>[] checkedExceptions = sortExceptions(methodExceptions,
                                                        true);
  
          // Convert the return value, arguments, and exception classes to
          // ASM Type objects, and create the ASM Method object which will
          // be used to actually add the method and method code.
          Type returnType = Type.getType(method.getReturnType());
          Type[] argTypes = getTypes(method.getParameterTypes());
          Type[] exceptionTypes = getTypes(methodExceptions);
  
          org.objectweb.asm.commons.Method m =
                          new org.objectweb.asm.commons.Method(methodName,
                                          returnType,
                                          argTypes);
  
          // Create an ASM GeneratorAdapter object for the ASM Method, which
          // makes generating dynamic code much easier... as it keeps track
          // of the position of the arguements and local variables, etc.
          mg = new GeneratorAdapter(ACC_PUBLIC, m, null, exceptionTypes, cw);
  
          // -----------------------------------------------------------------------
          // Begin Method Code...
          // -----------------------------------------------------------------------
          mg.visitCode();
  
          // -----------------------------------------------------------------------
          // <return type> returnValue = false | 0 | null;
          // -----------------------------------------------------------------------
          int returnValue = -1;
          if (returnType != Type.VOID_TYPE)
          {
              returnValue = mg.newLocal(returnType);
              switch (returnType.getSort())
              {
                  case Type.BOOLEAN:
                      mg.push(false);
                      break;
  
                  case Type.CHAR:
                  case Type.BYTE:
                  case Type.SHORT:
                  case Type.INT:
                      mg.push(0);
                      break;
  
                  case Type.FLOAT:
                      mg.push((float) 0);
                      break;
  
                  case Type.LONG:
                      mg.push((long) 0);
                      break;
  
                  case Type.DOUBLE:
                      mg.push((double) 0);
                      break;
  
                  // ARRAY & OBJECT - push a null on the stack
                  default:
                      mg.visitInsn(ACONST_NULL);
                      break;
              }
              mg.storeLocal(returnValue);
          }
  
          // -----------------------------------------------------------------------
          // Parameters were not available during preInvoke, so must be captured
          // here to pass to the around invoke interceptor processing.       d507967
          //
          // Object[] args = new Object[# of args];
          // args[i] = "parameter";   ->  for each parameter
          // -----------------------------------------------------------------------
          int args = createParameterArray(mg, argTypes);
  
          // -----------------------------------------------------------------------
          // Now invoke the business method;
          // - Through the interceptors via EJSContainer.invoke()
          // -----------------------------------------------------------------------
  
          // -----------------------------------------------------------------------
          // try
          // {
          // -----------------------------------------------------------------------
          Label main_try_begin = new Label();
          mg.visitLabel(main_try_begin);
  
          // --------------------------------------------------------------------
          //   ivContainer.invoke(s, args);
          //      or
          //   rtnValue = (type)ivContainer.invoke(s, args);
          //      or
          //   rtnValue = ((object type)ivContainer.invoke(s, args)).<type>Value();  // unbox
          // --------------------------------------------------------------------
          mg.loadThis();
          mg.visitFieldInsn(GETFIELD, className, "ivContainer", "Lcom/ibm/ejs/container/EJSContainer;");
          mg.loadThis();
          mg.visitFieldInsn(GETFIELD, className, "ivMethodContext",
                            "Lcom/ibm/ejs/container/EJSDeployedSupport;");
          mg.loadLocal(args); // d507967
          mg.visitMethodInsn(INVOKEVIRTUAL, "com/ibm/ejs/container/EJSContainer",
                             "invoke",
                             "(Lcom/ibm/ejs/container/EJSDeployedSupport;[Ljava/lang/Object;)Ljava/lang/Object;");
  
          if (returnType == Type.VOID_TYPE)
          {
              // No return value, just pop the returned value (null) off the stack
              mg.pop();
          }
          else
          {
              // Unbox any primitive values or add the appropriate cast
              // for object/array values, and then store in local variable.
              unbox(mg, returnType);
              mg.storeLocal(returnValue);
          }
  
          // -----------------------------------------------------------------------
          // }                     // end of try
          // -----------------------------------------------------------------------
          Label main_try_end = new Label();
          mg.visitLabel(main_try_end); // mark the end
  
          Label main_tcf_exit = new Label();
          mg.visitJumpInsn(GOTO, main_tcf_exit); // Skip to very end
  
          // -----------------------------------------------------------------------
          // Appear as if bean instance was called directly and just re-throw.
          //
          // catch (<checked exception> <ex>)  ->  for each <checked exception>
          // {
          //   throw <ex>;
          // }
          // -----------------------------------------------------------------------
          Label[] main_catch_label = new Label[checkedExceptions.length];
          int caught_ex = mg.newLocal(TYPE_Exception);
  
          for (int i = 0; i < checkedExceptions.length; i++)
          {
              main_catch_label[i] = new Label();
              mg.visitLabel(main_catch_label[i]);
              mg.storeLocal(caught_ex);
              mg.loadLocal(caught_ex);
              mg.visitInsn(ATHROW);
          }
  
          // -----------------------------------------------------------------------
          // Appear as if bean instance was called directly and just re-throw.
          //
          // catch (RuntimeException <ex>)
          // {
          //   throw <ex>;
          // }
          // -----------------------------------------------------------------------
          Label main_catch_runtime = new Label();
          mg.visitLabel(main_catch_runtime);
          mg.storeLocal(caught_ex);
          mg.loadLocal(caught_ex);
          mg.visitInsn(ATHROW);
  
          // -----------------------------------------------------------------------
          // Appear as if bean instance was called directly and just re-throw.
          //
          // catch (Error <ex>)
          // {
          //   throw <ex>;
          // }
          // -----------------------------------------------------------------------
          Label main_catch_error = new Label();
          mg.visitLabel(main_catch_error);
          mg.storeLocal(caught_ex);
          mg.loadLocal(caught_ex);
          mg.visitInsn(ATHROW);
  
          // -----------------------------------------------------------------------
          // Bean instance could not possibly have thrown this (unless Throwable
          // itself), so this must be coming from a poorly behaving interceptor.
          // This is a spec violation and cannot be reported dirctly.  Do the best
          // we can, and wrap it in an EJBException (i.e. RuntimeException).
          //
          // catch (Throwable <ex>)
          // {
          //   throw ExceptionUtil.EJBException( <ex> );
          // }
          // -----------------------------------------------------------------------
          Label main_catch_throwable = new Label();
          mg.visitLabel(main_catch_throwable);
          mg.storeLocal(caught_ex);
          mg.loadLocal(caught_ex);
          mg.visitMethodInsn(INVOKESTATIC, "com/ibm/ejs/container/util/ExceptionUtil",
                             "EJBException", "(Ljava/lang/Throwable;)Ljavax/ejb/EJBException;");
          mg.visitInsn(ATHROW);
  
          // -----------------------------------------------------------------------
          // }                     // end of try / catch / finally
          // -----------------------------------------------------------------------
          mg.visitLabel(main_tcf_exit);
  
          // -----------------------------------------------------------------------
          // return
          // -----------------------------------------------------------------------
          if (returnType != Type.VOID_TYPE)
          {
              mg.loadLocal(returnValue);
          }
          mg.returnValue();
  
          // -----------------------------------------------------------------------
          // All Try-Catch-Finally definitions for above
          // -----------------------------------------------------------------------
          for (int i = 0; i < checkedExceptions.length; i++)
          {
              mg.visitTryCatchBlock(main_try_begin, main_try_end,
                                    main_catch_label[i],
                                    convertClassName(checkedExceptions[i].getName()));
          }
  
          mg.visitTryCatchBlock(main_try_begin, main_try_end,
                                main_catch_runtime, "java/lang/RuntimeException");
          mg.visitTryCatchBlock(main_try_begin, main_try_end,
                                main_catch_error, "java/lang/Error");
          mg.visitTryCatchBlock(main_try_begin, main_try_end,
                                main_catch_throwable, "java/lang/Throwable");
  
          // -----------------------------------------------------------------------
          // End Method Code...
          // -----------------------------------------------------------------------
          mg.endMethod(); // GeneratorAdapter accounts for visitMaxs(x,y)
          mg.visitEnd();
      }