1
2
3
4
5
6 package mockit.internal.injection.full;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9 import edu.umd.cs.findbugs.annotations.Nullable;
10
11 import java.beans.BeanInfo;
12 import java.beans.IntrospectionException;
13 import java.beans.Introspector;
14 import java.beans.PropertyDescriptor;
15 import java.lang.annotation.Annotation;
16 import java.lang.reflect.InvocationTargetException;
17 import java.lang.reflect.Method;
18
19 import javax.sql.CommonDataSource;
20
21 import mockit.internal.injection.InjectionPoint;
22 import mockit.internal.injection.TestedClass;
23
24 final class TestDataSource {
25 @Nullable
26 private final String dsName;
27 private Class<? extends CommonDataSource> dsClass;
28 private CommonDataSource ds;
29
30 TestDataSource(@NonNull InjectionPoint injectionPoint) {
31 dsName = injectionPoint.name;
32 }
33
34 @Nullable
35 CommonDataSource createIfDataSourceDefinitionAvailable(@NonNull TestedClass testedClass) {
36 TestedClass testedClassWithDataSource = testedClass.parent;
37
38 if (testedClassWithDataSource == null || dsName == null) {
39 return null;
40 }
41
42 Class<?> testClass = testedClassWithDataSource.testClass;
43
44 if (testClass != null) {
45 createFromTestedClassOrASuperclass(testClass);
46 }
47
48 if (ds != null) {
49 return ds;
50 }
51
52 TestedClass testedClassToBeSearched = testedClassWithDataSource;
53
54 do {
55 createFromTestedClassOrASuperclass(testedClassToBeSearched.targetClass);
56
57 if (ds != null) {
58 return ds;
59 }
60
61 testedClassToBeSearched = testedClassToBeSearched.parent;
62 } while (testedClassToBeSearched != null);
63
64 throw new IllegalStateException("Missing @DataSourceDefinition of name \"" + dsName + "\" on "
65 + testedClassWithDataSource.nameOfTestedClass + " or on a super/parent class");
66 }
67
68 private void createFromTestedClassOrASuperclass(@NonNull Class<?> targetClass) {
69 do {
70 createDataSource(targetClass);
71
72 if (ds != null) {
73 return;
74 }
75
76 targetClass = targetClass.getSuperclass();
77 } while (targetClass != null && targetClass != Object.class);
78 }
79
80 private void createDataSource(@NonNull Class<?> targetClass) {
81 for (Annotation annotation : targetClass.getDeclaredAnnotations()) {
82 String annotationName = annotation.annotationType().getName();
83
84 if ("jakarta.annotation.sql.DataSourceDefinitions".equals(annotationName)) {
85 createDataSourceJakarta((jakarta.annotation.sql.DataSourceDefinitions) annotation);
86 } else if ("jakarta.annotation.sql.DataSourceDefinition".equals(annotationName)) {
87 createDataSourceJakarta((jakarta.annotation.sql.DataSourceDefinition) annotation);
88 } else if ("javax.annotation.sql.DataSourceDefinitions".equals(annotationName)) {
89 createDataSourceJavax((javax.annotation.sql.DataSourceDefinitions) annotation);
90 } else if ("javax.annotation.sql.DataSourceDefinition".equals(annotationName)) {
91 createDataSourceJavax((javax.annotation.sql.DataSourceDefinition) annotation);
92 }
93
94 if (ds != null) {
95 return;
96 }
97 }
98 }
99
100 private void createDataSourceJakarta(@NonNull jakarta.annotation.sql.DataSourceDefinitions dsDefs) {
101 for (jakarta.annotation.sql.DataSourceDefinition dsDef : dsDefs.value()) {
102 createDataSourceJakarta(dsDef);
103
104 if (ds != null) {
105 return;
106 }
107 }
108 }
109
110 private void createDataSourceJakarta(@NonNull jakarta.annotation.sql.DataSourceDefinition dsDef) {
111 String configuredDataSourceName = InjectionPoint.getNameFromJNDILookup(dsDef.name());
112
113 if (configuredDataSourceName.equals(dsName)) {
114 instantiateConfiguredDataSourceClassJakarta(dsDef);
115 setDataSourcePropertiesFromConfiguredValuesJakarta(dsDef);
116 }
117 }
118
119 private void instantiateConfiguredDataSourceClassJakarta(
120 @NonNull jakarta.annotation.sql.DataSourceDefinition dsDef) {
121 String className = dsDef.className();
122
123 try {
124
125 dsClass = (Class<? extends CommonDataSource>) Class.forName(className);
126
127 ds = dsClass.getDeclaredConstructor().newInstance();
128 } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | IllegalArgumentException
129 | InvocationTargetException | NoSuchMethodException | SecurityException e) {
130 throw new RuntimeException(e instanceof InstantiationException ? e.getCause() : e);
131 }
132 }
133
134 private void setDataSourcePropertiesFromConfiguredValuesJakarta(
135 @NonNull jakarta.annotation.sql.DataSourceDefinition dsDef) {
136 try {
137 BeanInfo beanInfo = Introspector.getBeanInfo(dsClass, Object.class);
138 PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
139
140 setProperty(properties, "url", dsDef.url());
141 setProperty(properties, "user", dsDef.user());
142 setProperty(properties, "password", dsDef.password());
143 } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
144 throw new RuntimeException(e);
145 }
146 }
147
148 private void createDataSourceJavax(@NonNull javax.annotation.sql.DataSourceDefinitions dsDefs) {
149 for (javax.annotation.sql.DataSourceDefinition dsDef : dsDefs.value()) {
150 createDataSourceJavax(dsDef);
151
152 if (ds != null) {
153 return;
154 }
155 }
156 }
157
158 private void createDataSourceJavax(@NonNull javax.annotation.sql.DataSourceDefinition dsDef) {
159 String configuredDataSourceName = InjectionPoint.getNameFromJNDILookup(dsDef.name());
160
161 if (configuredDataSourceName.equals(dsName)) {
162 instantiateConfiguredDataSourceClassJavax(dsDef);
163 setDataSourcePropertiesFromConfiguredValuesJavax(dsDef);
164 }
165 }
166
167 private void instantiateConfiguredDataSourceClassJavax(@NonNull javax.annotation.sql.DataSourceDefinition dsDef) {
168 String className = dsDef.className();
169
170 try {
171
172 dsClass = (Class<? extends CommonDataSource>) Class.forName(className);
173
174 ds = dsClass.getDeclaredConstructor().newInstance();
175 } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | IllegalArgumentException
176 | InvocationTargetException | NoSuchMethodException | SecurityException e) {
177 throw new RuntimeException(e instanceof InstantiationException ? e.getCause() : e);
178 }
179 }
180
181 private void setDataSourcePropertiesFromConfiguredValuesJavax(
182 @NonNull javax.annotation.sql.DataSourceDefinition dsDef) {
183 try {
184 BeanInfo beanInfo = Introspector.getBeanInfo(dsClass, Object.class);
185 PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
186
187 setProperty(properties, "url", dsDef.url());
188 setProperty(properties, "user", dsDef.user());
189 setProperty(properties, "password", dsDef.password());
190 } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
191 throw new RuntimeException(e);
192 }
193 }
194
195 private void setProperty(@NonNull PropertyDescriptor[] properties, @NonNull String name, @NonNull String value)
196 throws InvocationTargetException, IllegalAccessException {
197 for (PropertyDescriptor property : properties) {
198 if (property.getName().equals(name)) {
199 Method writeMethod = property.getWriteMethod();
200
201 if (writeMethod != null) {
202 writeMethod.invoke(ds, value);
203 }
204
205 return;
206 }
207 }
208 }
209 }