docs: public boolean redefineClasses(Notification notification) {
          // if there are no paths to process, then there is nothing to do
          if (notification.getPaths().isEmpty()) {
              return true;
          }
  
          Container container = notification.getContainer();
          // No need to do any processing if we are unable to redefine classes.
          boolean success;
          if (!smartClassPath.containsContainer(container)) {
              // This classloader is not associated with any container that has classes being modified,
              // so we can claim success.
              success = true;
          } else {
  
              // we only want to process *.class files
              List<String> classFilePaths = new ArrayList<String>();
              for (String path : notification.getPaths()) {
                  if (path.endsWith(".class")) {
                      classFilePaths.add(path);
                  }
              }
  
              if (classFilePaths.isEmpty()) {
                  // no class files to process, we must return true.
                  return true;
              }
  
              // This classloader is associated with a container that has classes being modified.
              // Success depends on whether we can redefine those classes or not.
              if (redefiner != null && redefiner.canRedefine()) {
                  success = true;
                  Set<ClassDefinition> classesToRedefine = new HashSet<ClassDefinition>();
                  for (String path : classFilePaths) {
  
                      String className = convertToClassName(path);
                      // We only want to redefine classes that have been loaded.  Unloaded classes
                      // don't need to be redefined.
                      Class<?> clazz = findLoadedClass(className);
                      if (clazz != null && clazz.getClassLoader() == this) {
                          try {
                              InputStream is = container.getEntry(path).adapt(InputStream.class);
                              byte[] classBytes = loadBytes(is);
                              ClassDefinition def = new ClassDefinition(clazz, classBytes);
                              classesToRedefine.add(def);
                          } catch (Exception e) {
                              // This should be either an IOException or an UnableToAdaptException
                              FFDCFilter.processException(e, this.getClass().getName() + ".redefineClasses", "1557", this,
                                                          new Object[] { className, notification.getContainer(), path });
                              // failed to read class bytes - not good - probably something wrong
                              // on the file system - FFDC - and restart the app
                              success = false;
                              break;
                          }
                      } // temporary until metadata processing can identify newly added Java EE components:
                      else if (clazz == null) {
                          // hasn't been loaded -return false for now in case the class contains EE metadata,
                          // like @WebServlet, or @EJB, etc. that needs to be processed.
                          // TODO: remove this else block and return true for unloaded classes once new
                          // metadata processing is in place
                          return false;
                      }
  
                  }
  
                  if (success/* still */ && !classesToRedefine.isEmpty()) {
                      success = redefiner.redefineClasses(classesToRedefine);
                  }
  
              } else {
                  // classes were changed, but redefiner is null or cannot redefine classes, so we must return false
                  success = false;
              }
          }
          return success;
      }