docs: void executeBulkUpdate(final TSDB tsdb, final HttpMethod method, HttpQuery query) {
      final List<Annotation> notes;
      try {
        notes = query.serializer().parseAnnotationsV1();
      } catch (IllegalArgumentException e){
        throw new BadRequestException(e);
      } catch (JSONException e){
        throw new BadRequestException(e);
      }
      final List<Deferred<Annotation>> callbacks = 
          new ArrayList<Deferred<Annotation>>(notes.size());
      
      /**
       * Storage callback used to determine if the storage call was successful
       * or not. Also returns the updated object from storage.
       */
      class SyncCB implements Callback<Deferred<Annotation>, Boolean> {
        final private Annotation note;
        
        public SyncCB(final Annotation note) {
          this.note = note;
        }
        
        @Override
        public Deferred<Annotation> call(Boolean success) throws Exception {
          if (!success) {
            throw new BadRequestException(
                HttpResponseStatus.INTERNAL_SERVER_ERROR,
                "Failed to save an Annotation to storage", 
                "This may be caused by another process modifying storage data: "
                + note);
          }
          
          return Annotation.getAnnotation(tsdb, note.getTSUID(), 
              note.getStartTime());
        }
      }
      
      /**
       * Simple callback that will index the updated annotation
       */
      class IndexCB implements Callback<Deferred<Annotation>, Annotation> {
        @Override
        public Deferred<Annotation> call(final Annotation note) throws Exception {
          tsdb.indexAnnotation(note);
          return Deferred.fromResult(note);
        }
      }
      
      for (Annotation note : notes) {
        try {
          Deferred<Annotation> deferred = 
              note.syncToStorage(tsdb, method == HttpMethod.PUT)
              .addCallbackDeferring(new SyncCB(note));
          Deferred<Annotation> indexer = 
              deferred.addCallbackDeferring(new IndexCB());
          callbacks.add(indexer);
        } catch (IllegalStateException e) {
          LOG.info("No changes for annotation: " + note);
        } catch (IllegalArgumentException e) {
          throw new BadRequestException(HttpResponseStatus.BAD_REQUEST, 
              e.getMessage(), "Annotation error: " + note, e);
        }
      }
      
      try {
        // wait untill all of the syncs have completed, then rebuild the list
        // of annotations using the data synced from storage.
        Deferred.group(callbacks).joinUninterruptibly();
        notes.clear();
        for (Deferred<Annotation> note : callbacks) {
          notes.add(note.joinUninterruptibly());
        }
        query.sendReply(query.serializer().formatAnnotationsV1(notes));
      } catch (IllegalArgumentException e) {
        throw new BadRequestException(e);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }