@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; } }