@Override
 public JythonCommandInterpreter createInstance() throws CommandInterpreterException {
   JythonCommandInterpreter interpreter = new JythonCommandInterpreter(executorService);
   try {
     serviceManager.register(interpreter);
   } catch (ServiceInitializationException e) {
     throw new CommandInterpreterException("Unable to load Python Interpreter", e);
   }
   return interpreter;
 }
 @Override
 public void close() {
   serviceManager.unregister(this);
 }
 @Override
 public void init() throws ServiceInitializationException {
   final AppsManager appsManager = serviceManager.getService(AppsManager.class);
   appsManager.addObserver(this);
 }
@Scan
public class DefaultInstallerDownloaderEntityProvider implements InstallerDownloaderEntityProvider {
  public static final double PERCENTAGE = 100.;

  @Inject static AnyScriptFactory scriptFactory;

  @Inject static ServiceManager serviceManager;

  private final DownloadManager downloadManager = serviceManager.getService(DownloadManager.class);

  private final Logger LOGGER =
      LoggerFactory.getLogger(DefaultInstallerDownloaderEntityProvider.class);
  private final HTTPDownloader httpDownloader;
  private final File localFile;
  private final SignatureChecker signatureChecker;
  // TODO Couldn't find any class using it, double check
  private Consumer<InstallerDownloaderEntity> onChange;

  DefaultInstallerDownloaderEntityProvider(
      HTTPDownloader httpDownloader, SignatureChecker signatureChecker) {
    this.httpDownloader = httpDownloader;
    this.signatureChecker = signatureChecker;

    try {
      this.localFile = File.createTempFile("script", "pol");
      this.localFile.deleteOnExit();
    } catch (IOException e) {
      throw new IllegalStateException(e);
    }
  }

  @Override
  public void getScript() {
    httpDownloader.setOnChange(this::update);
    downloadManager.submit(httpDownloader, this::success, this::failure);
  }

  private void success(byte[] bytes) {
    try (FileOutputStream fileOutputStream = new FileOutputStream(localFile)) {
      fileOutputStream.write(bytes);
      terminateDownload();
    } catch (IOException e) {
      LOGGER.error("Failed to write entity", e);
      failure(e);
    }
  }

  private void failure(Exception e) {
    LOGGER.warn("Failure", e);
    this.changeState(State.FAILED);
  }

  private void changeState(State state) {
    changeState(state, 0.);
  }

  private void changeState(State state, double percentage) {
    changeState(state, percentage, null);
  }

  private void changeState(State state, double percentage, String scriptContent) {
    if (onChange != null) {
      final boolean finished = state == State.SUCCESS || state == State.FAILED;
      final boolean failed = state == State.FAILED;
      final boolean signatureError = state == State.SIGNATURE_ERROR;

      onChange.accept(
          new InstallerDownloaderEntity(
              finished, failed, signatureError, percentage, scriptContent));
    }
  }

  public enum State {
    READY,
    PROGRESSING,
    SUCCESS,
    FAILED,
    SIGNATURE_ERROR
  }

  public void update(ProgressEntity argument) {
    if (argument.getState() == ProgressState.PROGRESSING) {
      changeState(State.PROGRESSING, argument.getPercent());
    }
  }

  private void terminateDownload() {
    try {
      final Script script = scriptFactory.createInstanceFromFile(localFile);
      final String scriptContent = script.extractContent();

      this.signatureChecker
          .withSignature(script.extractSignature())
          .withData(scriptContent)
          .withPublicKey(SignatureChecker.getPublicKey());

      if (!signatureChecker.check()) {
        changeState(State.SIGNATURE_ERROR, 100., scriptContent);
      } else {
        changeState(State.SUCCESS, PERCENTAGE);
        startScript(script);
      }
    } catch (SignatureException e) {
      LOGGER.error("Failed to validate signature", e);
      changeState(State.SIGNATURE_ERROR, 100.);
    } catch (ServiceInitializationException e) {
      LOGGER.info("Failed to initialize service", e);
    } catch (ScriptFailureException e) {
      LOGGER.error("Failed to execute script", e);
      changeState(State.FAILED);
    }
  }

  private void startScript(Script script) {
    serviceManager.register(script);
  }

  public void setOnChange(Consumer<InstallerDownloaderEntity> onChange) {
    this.onChange = onChange;
  }
}
 private void startScript(Script script) {
   serviceManager.register(script);
 }