docs: CompleteMultipartUploadResult uploadObject(final UploadObjectRequest req)
              throws IOException, InterruptedException, ExecutionException {
          // Set up the pipeline for concurrent encrypt and upload
          // Set up a thread pool for this pipeline
          ExecutorService es = req.getExecutorService();
          final boolean defaultExecutorService = es == null;
          if (es == null)
              es = Executors.newFixedThreadPool(clientConfiguration.getMaxConnections());
          UploadObjectObserver observer = req.getUploadObjectObserver();
          if (observer == null)
              observer = new UploadObjectObserver();
          // initialize the observer
          observer.init(req, this, this, es);
          // Initiate upload
          observer.onUploadInitiation(req);
          final List<PartETag> partETags = new ArrayList<PartETag>();
          MultiFileOutputStream mfos = req.getMultiFileOutputStream();
          if (mfos == null)
              mfos = new MultiFileOutputStream();
          try {
              // initialize the multi-file output stream
              mfos.init(observer, req.getPartSize(), req.getDiskLimit());
              // Kicks off the encryption-upload pipeline;
              // Note mfos is automatically closed upon method completion.
              putLocalObject(req, mfos);
              // block till all part have been uploaded
              for (Future<UploadPartResult> future: observer.getFutures()) {
                  UploadPartResult partResult = future.get();
                  partETags.add(new PartETag(partResult.getPartNumber(), partResult.getETag()));
              }
          } finally {
              if (defaultExecutorService)
                  es.shutdownNow();   // shut down the locally created thread pool
              mfos.cleanup();       // delete left-over temp files
          }
          // Complete upload
          return observer.onCompletion(partETags);
      }