001package com.mrivanplays.process; 002 003import java.util.Objects; 004import java.util.function.Supplier; 005 006/** 007 * Represents a {@link Process} that has a result. 008 * 009 * @param <T> result value type parameter 010 * @author <a href="mailto:[email protected]">Ivan Pekov</a> 011 * @since 0.0.1 012 */ 013public abstract class ResultedProcess<T> { 014 015 /** 016 * Creates a new {@code ResultedProcess} from a {@link Supplier} 017 * 018 * @param identifier resulted process identifier 019 * @param supplier input supplier 020 * @return resulted process 021 * @param <T> result value type parameter 022 */ 023 public static <T> ResultedProcess<T> fromSupplier(String identifier, Supplier<T> supplier) { 024 return new ResultedProcess<T>(identifier) { 025 @Override 026 public T run() { 027 return supplier.get(); 028 } 029 }; 030 } 031 032 private final String identifier; 033 034 /** 035 * Base constructor for all {@code ResultedProcess} implementations. 036 * 037 * @param identifier the identifier of this resulted process. It is good to set it every time 038 * implementation class(es) are created in order to properly defer results. 039 */ 040 public ResultedProcess(String identifier) { 041 this.identifier = Objects.requireNonNull(identifier, "identifier"); 042 } 043 044 /** 045 * Main logic for running the process 046 * 047 * @return a non null result value 048 * @throws Throwable if anything goes wrong, the implementation can throw any exception. 049 */ 050 protected abstract T run() throws Throwable; 051 052 // ==================================== 053 054 final void runProcess(ResultedProcessesCompletion<T> completion) { 055 try { 056 T result = this.run(); 057 if (result != null) { 058 completion.countDown(this.identifier, ProcessResult.success(result)); 059 } else { 060 throw new ProcessException( 061 "Null result in ResultedProcess '" + this.identifier + "' without errors!"); 062 } 063 } catch (Throwable e) { 064 ProcessException error = 065 new ProcessException("in ResultedProcess '" + this.identifier + "'", e); 066 if (e instanceof ProcessException) { 067 error = (ProcessException) e; 068 } 069 completion.countDown(this.identifier, ProcessResult.failure(error)); 070 } 071 } 072}