code: private TwillController addCleanupListener(TwillController controller, final File hConfFile,
                                               final File cConfFile, final Program program, final File programDir) {
  
      final AtomicBoolean deleted = new AtomicBoolean(false);
      controller.addListener(new ServiceListenerAdapter() {
        @Override
        public void running() {
          cleanup();
        }
  
        @Override
        public void terminated(Service.State from) {
          cleanup();
        }
  
        @Override
        public void failed(Service.State from, Throwable failure) {
          cleanup();
        }
  
        private void cleanup() {
          if (deleted.compareAndSet(false, true)) {
            LOG.debug("Cleanup tmp files for {}: {} {} {}",
                      program.getName(), hConfFile, cConfFile, program.getJarLocation().toURI());
            hConfFile.delete();
            cConfFile.delete();
            try {
              program.getJarLocation().delete();
            } catch (IOException e) {
              LOG.warn("Failed to delete program jar {}", program.getJarLocation().toURI(), e);
            }
            try {
              FileUtils.deleteDirectory(programDir);
            } catch (IOException e) {
              LOG.warn("Failed to delete program directory {}", programDir, e);
            }
          }
        }
      }, Threads.SAME_THREAD_EXECUTOR);
      return controller;
    }
docs: Adds a listener to the given TwillController to delete local temp files when the program has started/terminated.
  The local temp files could be removed once the program is started, since Twill would keep the files in
  HDFS and no long needs the local temp files once program is started.
  
  @return The same TwillController instance.