1919import org .hibernate .boot .registry .selector .spi .StrategySelectionException ;
2020import org .hibernate .boot .registry .selector .spi .StrategySelector ;
2121
22+ import org .hibernate .boot .registry .selector .spi .NamedStrategyContributions ;
23+ import org .hibernate .boot .registry .selector .spi .NamedStrategyContributor ;
2224import org .jboss .logging .Logger ;
2325
2426/**
2527 * Standard implementation of the {@link StrategySelector} contract.
2628 *
29+ * @implNote Supports both {@linkplain #namedStrategyImplementorByStrategyMap normal}
30+ * and {@linkplain #lazyStrategyImplementorByStrategyMap lazy} registration.
31+ *
2732 * @author Steve Ebersole
2833 */
2934public class StrategySelectorImpl implements StrategySelector {
30-
3135 private static final Logger log = Logger .getLogger ( StrategySelectorImpl .class );
3236
33- private static final StrategyCreator STANDARD_STRATEGY_CREATOR = strategyClass -> {
34- try {
35- return strategyClass .newInstance ();
36- }
37- catch (Exception e ) {
38- throw new StrategySelectionException (
39- String .format ( "Could not instantiate named strategy class [%s]" , strategyClass .getName () ),
40- e
41- );
42- }
43- };
44-
45- //Map based approach: most suited for explicit registrations from integrators
46- private final Map <Class ,Map <String ,Class >> namedStrategyImplementorByStrategyMap = new ConcurrentHashMap <>();
37+ private static final StrategyCreator <?> STANDARD_STRATEGY_CREATOR = StrategySelectorImpl ::create ;
4738
48- //"Lazy" approach: more efficient as we aim to not initialize all implementation classes;
49- //this is preferable for internal services such as Dialect, as we have a significant amount of them, making
50- //it worthwhile to try be a bit more efficient about them.
51- private final Map <Class , LazyServiceResolver > lazyStrategyImplementorByStrategyMap = new ConcurrentHashMap <>();
39+ private final Map <Class <?>,Map <String ,Class <?>>> namedStrategyImplementorByStrategyMap = new ConcurrentHashMap <>();
40+ private final Map <Class <?>, LazyServiceResolver <?>> lazyStrategyImplementorByStrategyMap = new ConcurrentHashMap <>();
5241
5342 private final ClassLoaderService classLoaderService ;
43+ private final Collection <NamedStrategyContributor > contributors ;
5444
5545 /**
5646 * Constructs a StrategySelectorImpl using the given class loader service.
@@ -59,88 +49,29 @@ public class StrategySelectorImpl implements StrategySelector {
5949 */
6050 public StrategySelectorImpl (ClassLoaderService classLoaderService ) {
6151 this .classLoaderService = classLoaderService ;
62- }
63-
64- public <T > void registerStrategyLazily (Class <T > strategy , LazyServiceResolver <T > resolver ) {
65- LazyServiceResolver previous = lazyStrategyImplementorByStrategyMap .put ( strategy , resolver );
66- if ( previous != null ) {
67- throw new HibernateException ( "Detected a second LazyServiceResolver replacing an existing LazyServiceResolver implementation for strategy " + strategy .getName () );
68- }
69- }
70-
71- @ Override
72- public <T > void registerStrategyImplementor (Class <T > strategy , String name , Class <? extends T > implementation ) {
73- final Map <String ,Class > namedStrategyImplementorMap = namedStrategyImplementorByStrategyMap .computeIfAbsent (
74- strategy ,
75- aClass -> new ConcurrentHashMap <>()
76- );
77-
78- final Class old = namedStrategyImplementorMap .put ( name , implementation );
79- if ( old == null ) {
80- if ( log .isTraceEnabled () ) {
81- log .trace (
82- String .format (
83- "Registering named strategy selector [%s] : [%s] -> [%s]" ,
84- strategy .getName (),
85- name ,
86- implementation .getName ()
87- )
88- );
89- }
90- }
91- else {
92- if ( log .isDebugEnabled () ) {
93- log .debug (
94- String .format (
95- "Registering named strategy selector [%s] : [%s] -> [%s] (replacing [%s])" ,
96- strategy .getName (),
97- name ,
98- implementation .getName (),
99- old .getName ()
100- )
101- );
102- }
103- }
104- }
105-
106- @ Override
107- public <T > void unRegisterStrategyImplementor (Class <T > strategy , Class <? extends T > implementation ) {
108- final Map <String ,Class > namedStrategyImplementorMap = namedStrategyImplementorByStrategyMap .get ( strategy );
109- if ( namedStrategyImplementorMap == null ) {
110- log .debug ( "Named strategy map did not exist on call to un-register" );
111- return ;
112- }
113-
114- final Iterator itr = namedStrategyImplementorMap .values ().iterator ();
115- while ( itr .hasNext () ) {
116- final Class registered = (Class ) itr .next ();
117- if ( registered .equals ( implementation ) ) {
118- itr .remove ();
119- }
120- }
12152
122- // try to clean up after ourselves...
123- if ( namedStrategyImplementorMap . isEmpty () ) {
124- namedStrategyImplementorByStrategyMap . remove ( strategy );
53+ this . contributors = classLoaderService . loadJavaServices ( NamedStrategyContributor . class );
54+ for ( NamedStrategyContributor contributor : contributors ) {
55+ contributor . contributeStrategyImplementations ( new StartupContributions () );
12556 }
12657 }
12758
12859 @ Override
12960 @ SuppressWarnings ("unchecked" )
13061 public <T > Class <? extends T > selectStrategyImplementor (Class <T > strategy , String name ) {
131- final Map <String ,Class > namedStrategyImplementorMap = namedStrategyImplementorByStrategyMap .get ( strategy );
62+ final Map <String ,Class <?> > namedStrategyImplementorMap = namedStrategyImplementorByStrategyMap .get ( strategy );
13263 if ( namedStrategyImplementorMap != null ) {
133- final Class registered = namedStrategyImplementorMap .get ( name );
64+ final Class <?> registered = namedStrategyImplementorMap .get ( name );
13465 if ( registered != null ) {
13566 return (Class <T >) registered ;
13667 }
13768 }
13869
139- LazyServiceResolver lazyServiceResolver = lazyStrategyImplementorByStrategyMap .get ( strategy );
70+ final LazyServiceResolver <?> lazyServiceResolver = lazyStrategyImplementorByStrategyMap .get ( strategy );
14071 if ( lazyServiceResolver != null ) {
141- Class resolve = lazyServiceResolver .resolve ( name );
72+ final Class <?> resolve = lazyServiceResolver .resolve ( name );
14273 if ( resolve != null ) {
143- return resolve ;
74+ return ( Class <? extends T >) resolve ;
14475 }
14576 }
14677
@@ -175,7 +106,7 @@ public <T> T resolveDefaultableStrategy(
175106 Class <T > strategy ,
176107 Object strategyReference ,
177108 Callable <T > defaultResolver ) {
178- return (T ) resolveStrategy ( strategy , strategyReference , defaultResolver , STANDARD_STRATEGY_CREATOR );
109+ return (T ) resolveStrategy ( strategy , strategyReference , defaultResolver , ( StrategyCreator < T >) STANDARD_STRATEGY_CREATOR );
179110 }
180111
181112 @ Override
@@ -193,17 +124,17 @@ public <T> T resolveStrategy(
193124 }
194125
195126 @ Override
196- @ SuppressWarnings ("unchecked" )
197- public Collection getRegisteredStrategyImplementors (Class strategy ) {
198- LazyServiceResolver lazyServiceResolver = lazyStrategyImplementorByStrategyMap .get ( strategy );
127+ public <T > Collection <Class <? extends T >> getRegisteredStrategyImplementors (Class <T > strategy ) {
128+ final LazyServiceResolver <?> lazyServiceResolver = lazyStrategyImplementorByStrategyMap .get ( strategy );
199129 if ( lazyServiceResolver != null ) {
200130 throw new StrategySelectionException ( "Can't use this method on for strategy types which are embedded in the core library" );
201131 }
202- final Map <String , Class > registrations = namedStrategyImplementorByStrategyMap .get ( strategy );
132+ final Map <String , Class <?> > registrations = namedStrategyImplementorByStrategyMap .get ( strategy );
203133 if ( registrations == null ) {
204134 return Collections .emptySet ();
205135 }
206- return new HashSet ( registrations .values () );
136+ //noinspection unchecked,rawtypes
137+ return (Collection ) new HashSet <>( registrations .values () );
207138 }
208139
209140 @ SuppressWarnings ("unchecked" )
@@ -244,4 +175,121 @@ public <T> T resolveStrategy(
244175 );
245176 }
246177 }
178+
179+ private static <T > T create (Class <T > strategyClass ) {
180+ try {
181+ return strategyClass .getDeclaredConstructor ().newInstance ();
182+ }
183+ catch (Exception e ) {
184+ throw new StrategySelectionException (
185+ String .format ( "Could not instantiate named strategy class [%s]" , strategyClass .getName () ),
186+ e
187+ );
188+ }
189+ }
190+
191+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192+ // Lifecycle
193+
194+ public <T > void registerStrategyLazily (Class <T > strategy , LazyServiceResolver <T > resolver ) {
195+ LazyServiceResolver <?> previous = lazyStrategyImplementorByStrategyMap .put ( strategy , resolver );
196+ if ( previous != null ) {
197+ throw new HibernateException ( "Detected a second LazyServiceResolver replacing an existing LazyServiceResolver implementation for strategy " + strategy .getName () );
198+ }
199+ }
200+
201+ private <T > void contributeImplementation (Class <T > strategy , Class <? extends T > implementation , String ... names ) {
202+ final Map <String ,Class <?>> namedStrategyImplementorMap = namedStrategyImplementorByStrategyMap .computeIfAbsent (
203+ strategy ,
204+ aClass -> new ConcurrentHashMap <>()
205+ );
206+
207+ for ( int i = 0 ; i < names .length ; i ++ ) {
208+ final String name = names [i ];
209+
210+ final Class <?> old = namedStrategyImplementorMap .put ( name , implementation );
211+ if ( old == null ) {
212+ if ( log .isTraceEnabled () ) {
213+ log .trace (
214+ String .format (
215+ "Registering named strategy selector [%s] : [%s] -> [%s]" ,
216+ strategy .getName (),
217+ name ,
218+ implementation .getName ()
219+ )
220+ );
221+ }
222+ }
223+ else {
224+ if ( log .isDebugEnabled () ) {
225+ log .debug (
226+ String .format (
227+ "Registering named strategy selector [%s] : [%s] -> [%s] (replacing [%s])" ,
228+ strategy .getName (),
229+ name ,
230+ implementation .getName (),
231+ old .getName ()
232+ )
233+ );
234+ }
235+ }
236+ }
237+ }
238+
239+ private <T > void removeImplementation (Class <T > strategy , Class <? extends T > implementation ) {
240+ final Map <String ,Class <?>> namedStrategyImplementorMap = namedStrategyImplementorByStrategyMap .get ( strategy );
241+ if ( namedStrategyImplementorMap == null ) {
242+ log .debug ( "Named strategy map did not exist on call to un-register" );
243+ return ;
244+ }
245+
246+ final Iterator <Class <?>> itr = namedStrategyImplementorMap .values ().iterator ();
247+ while ( itr .hasNext () ) {
248+ final Class <?> registered = itr .next ();
249+ if ( registered .equals ( implementation ) ) {
250+ itr .remove ();
251+ }
252+ }
253+
254+ // try to clean up after ourselves...
255+ if ( namedStrategyImplementorMap .isEmpty () ) {
256+ namedStrategyImplementorByStrategyMap .remove ( strategy );
257+ }
258+ }
259+
260+ @ Override
261+ public void stop () {
262+ for ( NamedStrategyContributor contributor : contributors ) {
263+ contributor .clearStrategyImplementations ( new ShutdownContributions () );
264+ }
265+ }
266+
267+ private class StartupContributions implements NamedStrategyContributions {
268+ @ Override
269+ public <T > void contributeStrategyImplementor (Class <T > strategy , Class <? extends T > implementation , String ... names ) {
270+ contributeImplementation ( strategy , implementation , names );
271+ }
272+
273+ @ Override
274+ public <T > void removeStrategyImplementor (Class <T > strategy , Class <? extends T > implementation ) {
275+ removeImplementation ( strategy , implementation );
276+ }
277+ }
278+
279+ private class ShutdownContributions extends StartupContributions {
280+ @ Override
281+ public <T > void contributeStrategyImplementor (Class <T > strategy , Class <? extends T > implementation , String ... names ) {
282+ throw new IllegalStateException ( "Should not register strategies during shutdown" );
283+ }
284+ }
285+
286+ @ Override
287+ public <T > void registerStrategyImplementor (Class <T > strategy , String name , Class <? extends T > implementation ) {
288+ contributeImplementation ( strategy , implementation , name );
289+ }
290+
291+ @ Override
292+ public <T > void unRegisterStrategyImplementor (Class <T > strategy , Class <? extends T > implementation ) {
293+ removeImplementation ( strategy , implementation );
294+ }
247295}
0 commit comments