22
33import com .github .containersolutions .operator .api .Controller ;
44import com .github .containersolutions .operator .api .ResourceController ;
5+ import io .fabric8 .kubernetes .api .builder .Function ;
56import io .fabric8 .kubernetes .client .CustomResource ;
67import io .fabric8 .kubernetes .client .CustomResourceDoneable ;
78import javassist .*;
8- import org .apache .commons .lang3 .StringUtils ;
99import org .slf4j .Logger ;
1010import org .slf4j .LoggerFactory ;
1111
12+ import java .util .HashMap ;
13+ import java .util .Map ;
14+
1215
1316class ControllerUtils {
1417
1518 private final static Logger log = LoggerFactory .getLogger (Operator .class );
16- private static ClassPool pool ;
17- private static Class generatedCustomResourceDoneable ;
19+
20+ // this is just to support testing, this way we don't try to create class multiple times in memory with same name.
21+ // note that other solution is to add a random string to doneable class name
22+ private static Map <Class <? extends CustomResource >, Class <? extends CustomResourceDoneable <? extends CustomResource >>>
23+ doneableClassCache = new HashMap <>();
1824
1925 static String getDefaultFinalizer (ResourceController controller ) {
2026 return getAnnotation (controller ).finalizerName ();
@@ -29,71 +35,36 @@ static String getCrdName(ResourceController controller) {
2935 }
3036
3137
32- public static <R extends CustomResource > Class <? extends CustomResourceDoneable <R >> getCustomResourceDoneableClass (ResourceController <R > controller ) {
33- return createCustomResourceDoneableClass (controller );
34- }
38+ public static <T extends CustomResource > Class <? extends CustomResourceDoneable <T >>
39+ getCustomResourceDoneableClass (ResourceController <T > controller ) {
40+ try {
41+ Class <? extends CustomResource > customResourceClass = getAnnotation (controller ).customResourceClass ();
42+ String className = customResourceClass .getPackage ().getName () + "." + customResourceClass .getSimpleName () + "CustomResourceDoneable" ;
3543
36- private static < R extends CustomResource > Class <? extends CustomResourceDoneable < R >> createCustomResourceDoneableClass ( ResourceController < R > controller ) {
37- pool = ClassPool . getDefault ( );
38- pool . appendClassPath ( new ClassClassPath ( ControllerUtils . class ));
44+ if ( doneableClassCache . containsKey ( customResourceClass ) ) {
45+ return ( Class <? extends CustomResourceDoneable < T >>) doneableClassCache . get ( customResourceClass );
46+ }
3947
40- String controllerName = StringUtils . substringAfterLast ( controller . getClass (). toString (), "." );
41- Class < R > customResourceClass = ( Class < R >) getAnnotation ( controller ). customResourceClass ( );
48+ ClassPool pool = ClassPool . getDefault ( );
49+ pool . appendClassPath ( new LoaderClassPath ( Thread . currentThread (). getContextClassLoader ()) );
4250
43- String className = getPackageName (customResourceClass .getName (), controllerName + "CustomResourceDoneable" );
44- if (isClassInPool (className )) {
45- return generatedCustomResourceDoneable ;
46- }
47- CtClass customDoneable = null ;
48- try {
49- CtClass superClass = pool .get ("io.fabric8.kubernetes.client.CustomResourceDoneable" );
50- CtClass function = pool .get ("io.fabric8.kubernetes.api.builder.Function" );
51+ CtClass superClass = pool .get (CustomResourceDoneable .class .getName ());
52+ CtClass function = pool .get (Function .class .getName ());
5153 CtClass customResource = pool .get (customResourceClass .getName ());
5254 CtClass [] argTypes = {customResource , function };
53- customDoneable = pool .makeClass (className , superClass );
55+ CtClass customDoneable = pool .makeClass (className , superClass );
5456 CtConstructor ctConstructor = CtNewConstructor .make (argTypes , null , "super($1, $2);" , customDoneable );
5557 customDoneable .addConstructor (ctConstructor );
5658
59+ Class <? extends CustomResourceDoneable <T >> doneableClass = customDoneable .toClass ();
60+ doneableClassCache .put (customResourceClass , doneableClass );
61+ return doneableClass ;
5762 } catch (CannotCompileException | NotFoundException e ) {
58- log .error ("Error creating CustomResourceDoneable CtClass: {}" , e );
59- }
60- Class <? extends CustomResourceDoneable <R >> doneableClass = getClassFromCtClass (customDoneable );
61- generatedCustomResourceDoneable = doneableClass ;
62- return doneableClass ;
63- }
64-
65- private static boolean isClassInPool (String className ) {
66- try {
67- pool .get (className );
68- return true ;
69- } catch (NotFoundException e ) {
70- log .debug ("Class {} not in pool" , className );
71- return false ;
63+ throw new IllegalStateException (e );
7264 }
7365 }
7466
7567 private static Controller getAnnotation (ResourceController controller ) {
7668 return controller .getClass ().getAnnotation (Controller .class );
7769 }
78-
79- private static String getPackageName (String customResourceName , String newClassName ) {
80- CtClass customResource = null ;
81- try {
82- customResource = pool .get (customResourceName );
83- } catch (NotFoundException e ) {
84- log .error ("Error getting class: {}" , e );
85- }
86- String packageName = customResource != null ? customResource .getPackageName () : "" ;
87- return packageName + "." + newClassName ;
88- }
89-
90- private static Class getClassFromCtClass (CtClass customCtClass ) {
91- Class customClass = null ;
92- try {
93- customClass = customCtClass .toClass ();
94- } catch (CannotCompileException e ) {
95- log .error ("Error transforming CtClass to Class: {}" , e );
96- }
97- return customClass ;
98- }
99- }
70+ }
0 commit comments