99import org .comroid .api .data .seri .Serializer ;
1010import org .comroid .api .func .exc .ThrowingSupplier ;
1111import org .comroid .api .func .util .Debug ;
12+ import org .comroid .api .func .util .RootContextSource ;
1213import org .comroid .api .java .ReflectionHelper ;
1314import org .jetbrains .annotations .ApiStatus .Experimental ;
1415import org .jetbrains .annotations .ApiStatus .Internal ;
1920import java .io .IOException ;
2021import java .io .InputStream ;
2122import java .util .Arrays ;
23+ import java .util .Collection ;
24+ import java .util .Collections ;
2225import java .util .HashSet ;
2326import java .util .Map ;
2427import java .util .NoSuchElementException ;
2528import java .util .Objects ;
2629import java .util .Properties ;
30+ import java .util .ServiceLoader ;
2731import java .util .Set ;
2832import java .util .function .Supplier ;
2933import java .util .logging .Level ;
5357@ MustExtend (Context .Base .class )
5458public interface Context extends Named , Convertible , LoggerCarrier {
5559 static Context root () {
56- return Base .ROOT ;
60+ return Base .ROOT . get () ;
5761 }
5862
5963 static <T > @ Nullable T get (Class <T > type ) {
@@ -120,7 +124,9 @@ static <T> Wrap<T> getFromContexts(final Class<T> member) {
120124
121125 @ Deprecated (forRemoval = true )
122126 static <T > Wrap <T > getFromContexts (final Class <T > member , boolean includeChildren ) {
123- return () -> Base .ROOT .children .stream ()
127+ return () -> Base .ROOT .get ()
128+ .getChildren ()
129+ .stream ()
124130 .flatMap (sub -> sub .getFromContext (member , includeChildren ).stream ())
125131 .findFirst ()
126132 .orElse (null );
@@ -142,6 +148,10 @@ static <T> T getFromRoot(Class<T> type, Supplier<? extends T> elseGet) {
142148 return wrap (type ).orElseGet (elseGet );
143149 }
144150
151+ default Collection <Context > getChildren () {
152+ return Collections .emptySet ();
153+ }
154+
145155 @ Internal
146156 @ NonExtendable
147157 default boolean isRoot () {
@@ -294,50 +304,60 @@ default Context plus(Object... plus) {
294304
295305 @ Internal
296306 class Base implements Context {
297- @ SuppressWarnings ("ConstantConditions" ) public static final Context . Base ROOT ;
307+ @ SuppressWarnings ("ConstantConditions" ) public static final Supplier < Context > ROOT ;
298308
299309 static {
300- try {
301- ROOT = new Context .Base (null , "ROOT" , new Object [0 ]);
302- InputStream resource = ClassLoader .getSystemClassLoader ()
303- .getResourceAsStream ("org/comroid/api/context.properties" );
304- if (resource != null ) {
305- Properties props = new Properties ();
306- props .load (resource );
307-
308- int c = 0 ;
309- Object [] values = new Object [props .size ()];
310- for (Map .Entry <Object , Object > entry : props .entrySet ()) {
311- final int fc = c ;
312- Class <?> targetClass = Class .forName (String .valueOf (entry .getValue ()));
313- createInstance (targetClass ).ifPresent (it -> values [fc ] = it );
314- c ++;
315- }
316- Debug .logger .log (Level .FINE ,
317- "Initializing ContextualProvider Root with: {}" ,
318- Arrays .toString (values ));
319- ROOT .addToContext (values );
320- }
321- } catch (IOException e ) {
322- throw new RuntimeException ("Could not read context properties" , e );
323- } catch (ClassNotFoundException e ) {
324- throw new RuntimeException ("Could not find Context Class" , e );
325- }
310+ ROOT = Wrap .onDemand (() -> ServiceLoader .load (RootContextSource .class )
311+ .findFirst ()
312+ .map (RootContextSource ::getRootContext )
313+ .orElseGet (() -> {
314+ try {
315+ var rootContext = new Context .Base (null , "ROOT" , new Object [0 ]);
316+ InputStream resource = ClassLoader .getSystemClassLoader ()
317+ .getResourceAsStream ("org/comroid/api/context.properties" );
318+ if (resource != null ) {
319+ Properties props = new Properties ();
320+ props .load (resource );
321+
322+ int c = 0 ;
323+ Object [] values = new Object [props .size ()];
324+ for (Map .Entry <Object , Object > entry : props .entrySet ()) {
325+ final int fc = c ;
326+ Class <?> targetClass = Class .forName (String .valueOf (entry .getValue ()));
327+ createInstance (targetClass ).ifPresent (it -> values [fc ] = it );
328+ c ++;
329+ }
330+ Debug .logger .log (Level .FINE ,
331+ "Initializing ContextualProvider Root with: {}" ,
332+ Arrays .toString (values ));
333+ rootContext .addToContext (values );
334+ }
335+ return rootContext ;
336+ } catch (IOException e ) {
337+ throw new RuntimeException ("Could not read context properties" , e );
338+ } catch (ClassNotFoundException e ) {
339+ throw new RuntimeException ("Could not find Context Class" , e );
340+ }
341+ }));
326342 }
327343
328344 @ Getter protected final Set <Context > children ;
329345 @ Getter private final Set <Object > myMembers ;
330346 private final Context parent ;
331347 private final String name ;
332348
333- protected Base (Object ... initialMembers ) {
334- this (ROOT , initialMembers );
335- }
336-
337349 protected Base (@ NotNull Context parent , Object ... initialMembers ) {
338350 this (parent , callerClass (1 ).getSimpleName (), initialMembers );
339351 }
340352
353+ protected Base (String name , Object ... initialMembers ) {
354+ this (null , name , initialMembers );
355+ }
356+
357+ protected Base (Object ... initialMembers ) {
358+ this (null , "ROOT" , initialMembers );
359+ }
360+
341361 protected Base (Context parent , String name , Object ... initialMembers ) {
342362 this .myMembers = new HashSet <>();
343363 this .children = new HashSet <>();
@@ -349,10 +369,6 @@ protected Base(Context parent, String name, Object... initialMembers) {
349369 addToContext (initialMembers );
350370 }
351371
352- protected Base (String name , Object ... initialMembers ) {
353- this (ROOT , name , initialMembers );
354- }
355-
356372 @ Override
357373 public final @ Nullable Context getParentContext () {
358374 return parent ;
0 commit comments