code: @Override
      public void onEvent(EventIterator events) {
          try {
              // this resolver should be the only one (for this handling thread)
              ResourceResolver resolver = getResolver();
              if (resolver != null) {
                  try {
                      Session session = resolver.adaptTo(Session.class);
                      String serviceUserId = getServiceUserId();
                      // collect changed nodes
                      ChangeCollection changedNodes = new ChangeCollection();
                      while (events.hasNext()) {
                          Event event = events.nextEvent();
                          if (ignoreEvent(event)) continue;
                          try {
                              String path = event.getPath();
                              String user = event.getUserID();
                              // if the service user is the initiator this is a self initiated event - ignore it
                              if (!serviceUserId.equals(user)) {
                                  Calendar time = Calendar.getInstance();
                                  time.setTime(new Date(event.getDate()));
                                  int type = event.getType();
                                  if (isPropertyEvent(type)) {
                                      if (getPropertyPathFilter().accept(path)) {
                                          changedNodes.registerChange(session, resolver, path, time, user);
                                      }
                                  } else {
                                      if (getNodePathFilter().accept(path)) {
                                          changedNodes.registerChange(session, resolver, path, time, user);
                                      }
                                  }
                              }
                          } catch (RepositoryException rex) {
                              LOG.error(rex.getMessage(), rex);
                          }
                      }
                      // handle change actions on the detected nodes
                      if (changedNodes.size() > 0) {
                          for (ChangedResource change : changedNodes.values()) {
                              try {
                                  doOnChange(resolver, change);
                              } catch (RepositoryException ex) {
                                  LOG.error(ex.getMessage(), ex);
                              }
                          }
                          changedNodes.clear();
                          resolver.commit();
                      }
                  } catch (PersistenceException ex) {
                      LOG.error(ex.getMessage(), ex);
                  } finally {
                      resolver.close();
                  }
              }
          } catch (LoginException ex) {
              LOG.error(ex.getMessage(), ex);
          }
      }
docs: collects the changed nodes and calls the observers strategy (doOnChange) for each node found