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