001
014
015 package com.liferay.portal.kernel.test.rule.callback;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.test.rule.DeleteAfterTestRun;
020 import com.liferay.portal.kernel.util.ArrayUtil;
021 import com.liferay.portal.kernel.util.StringBundler;
022 import com.liferay.portal.model.Company;
023 import com.liferay.portal.model.Group;
024 import com.liferay.portal.model.LayoutPrototype;
025 import com.liferay.portal.model.LayoutSetPrototype;
026 import com.liferay.portal.model.Organization;
027 import com.liferay.portal.model.PersistedModel;
028 import com.liferay.portal.model.Role;
029 import com.liferay.portal.model.User;
030 import com.liferay.portal.model.UserGroup;
031 import com.liferay.portal.service.PersistedModelLocalService;
032 import com.liferay.portal.service.PersistedModelLocalServiceRegistryUtil;
033
034 import java.lang.reflect.Field;
035
036 import java.util.ArrayList;
037 import java.util.Arrays;
038 import java.util.Collection;
039 import java.util.HashMap;
040 import java.util.Iterator;
041 import java.util.LinkedHashSet;
042 import java.util.LinkedList;
043 import java.util.List;
044 import java.util.Map;
045 import java.util.Queue;
046 import java.util.Set;
047
048 import org.junit.runner.Description;
049
050
053 public class DeleteAfterTestRunTestCallback
054 extends BaseTestCallback<Object, Object> {
055
056 public static final DeleteAfterTestRunTestCallback INSTANCE =
057 new DeleteAfterTestRunTestCallback();
058
059 @Override
060 public void afterMethod(
061 Description description, Object object, Object target) {
062
063 Class<?> testClass = description.getTestClass();
064
065 Map<Class<?>, FieldBag> deleteAfterTestRunFieldBags = new HashMap<>();
066
067 while (testClass != null) {
068 for (Field field : testClass.getDeclaredFields()) {
069 DeleteAfterTestRun deleteAfterTestRun = field.getAnnotation(
070 DeleteAfterTestRun.class);
071
072 if (deleteAfterTestRun == null) {
073 continue;
074 }
075
076 Class<?> fieldClass = field.getType();
077
078 if (PersistedModel.class.isAssignableFrom(fieldClass)) {
079 addField(deleteAfterTestRunFieldBags, fieldClass, field);
080
081 continue;
082 }
083
084 if (fieldClass.isArray()) {
085 if (!PersistedModel.class.isAssignableFrom(
086 fieldClass.getComponentType())) {
087
088 throw new IllegalArgumentException(
089 "Unable to annotate field " + field +
090 " because it is not an array of type " +
091 PersistedModel.class.getName());
092 }
093
094 addField(
095 deleteAfterTestRunFieldBags,
096 fieldClass.getComponentType(), field);
097
098 continue;
099 }
100
101 if (Collection.class.isAssignableFrom(fieldClass)) {
102 try {
103 field.setAccessible(true);
104
105 Collection<?> collection = (Collection<?>)field.get(
106 target);
107
108 if ((collection == null) || collection.isEmpty()) {
109 continue;
110 }
111
112 Class<?> collectionType = getCollectionType(collection);
113
114 if (collectionType == null) {
115 throw new IllegalArgumentException(
116 "Unable to annotate field " + field +
117 " because it is not a collection of type " +
118 PersistedModel.class.getName());
119 }
120
121 addField(
122 deleteAfterTestRunFieldBags, collectionType, field);
123 }
124 catch (Exception e) {
125 _log.error(
126 "Unable to detect collection element type", e);
127 }
128
129 continue;
130 }
131
132 StringBundler sb = new StringBundler(6);
133
134 sb.append("Unable to annotate field ");
135 sb.append(field);
136 sb.append(" because it is not type of ");
137 sb.append(PersistedModel.class.getName());
138 sb.append(" nor an array or collection of ");
139 sb.append(PersistedModel.class.getName());
140
141 throw new IllegalArgumentException(sb.toString());
142 }
143
144 testClass = testClass.getSuperclass();
145 }
146
147 Set<Map.Entry<Class<?>, FieldBag>> set =
148 deleteAfterTestRunFieldBags.entrySet();
149
150 Iterator<Map.Entry<Class<?>, FieldBag>> iterator = set.iterator();
151
152 while (iterator.hasNext()) {
153 Map.Entry<Class<?>, FieldBag> entry = iterator.next();
154
155 Class<?> clazz = entry.getKey();
156
157 if (_orderedClasses.contains(clazz)) {
158 continue;
159 }
160
161 iterator.remove();
162
163 removeField(entry.getValue(), target);
164 }
165
166 for (Class<?> clazz : _orderedClasses) {
167 FieldBag fieldBag = deleteAfterTestRunFieldBags.remove(clazz);
168
169 if (fieldBag == null) {
170 continue;
171 }
172
173 removeField(fieldBag, target);
174 }
175 }
176
177 protected void addField(
178 Map<Class<?>, FieldBag> deleteAfterTestRunFieldBags, Class<?> clazz,
179 Field field) {
180
181 FieldBag fieldBag = deleteAfterTestRunFieldBags.get(clazz);
182
183 if (fieldBag == null) {
184 fieldBag = new FieldBag(clazz);
185
186 deleteAfterTestRunFieldBags.put(clazz, fieldBag);
187 }
188
189 field.setAccessible(true);
190
191 fieldBag.addField(field);
192 }
193
194 protected Class<? extends PersistedModel> getCollectionType(
195 Collection<?> collection) {
196
197 Class<? extends PersistedModel> collectionType = null;
198
199 for (Object object : collection) {
200 Queue<Class<?>> classes = new LinkedList<>();
201
202 classes.add(object.getClass());
203
204 Class<?> clazz = null;
205
206 while ((clazz = classes.poll()) != null) {
207 if (ArrayUtil.contains(
208 clazz.getInterfaces(), PersistedModel.class)) {
209
210 if (collectionType == null) {
211 collectionType = (Class<? extends PersistedModel>)clazz;
212 }
213 else if (collectionType != clazz) {
214 return null;
215 }
216
217 break;
218 }
219
220 classes.add(clazz.getSuperclass());
221 classes.addAll(Arrays.asList(clazz.getInterfaces()));
222 }
223 }
224
225 return collectionType;
226 }
227
228 protected void removeField(FieldBag fieldBag, Object instance) {
229 try {
230 Class<?> fieldClass = fieldBag.getFieldClass();
231
232 PersistedModelLocalService persistedModelLocalService =
233 PersistedModelLocalServiceRegistryUtil.
234 getPersistedModelLocalService(fieldClass.getName());
235
236 for (Field field : fieldBag.getFields()) {
237 Object object = field.get(instance);
238
239 if (object == null) {
240 continue;
241 }
242
243 Class<?> objectClass = object.getClass();
244
245 if (objectClass.isArray()) {
246 for (PersistedModel persistedModel :
247 (PersistedModel[])object) {
248
249 if (persistedModel == null) {
250 continue;
251 }
252
253 persistedModelLocalService.deletePersistedModel(
254 persistedModel);
255 }
256 }
257 else if (Collection.class.isAssignableFrom(objectClass)) {
258 Collection<? extends PersistedModel> collection =
259 (Collection<? extends PersistedModel>)object;
260
261 for (PersistedModel persistedModel : collection) {
262 persistedModelLocalService.deletePersistedModel(
263 persistedModel);
264 }
265 }
266 else {
267 persistedModelLocalService.deletePersistedModel(
268 (PersistedModel)object);
269 }
270
271 field.set(instance, null);
272 }
273 }
274 catch (Exception e) {
275 _log.error("Unable to delete", e);
276 }
277 }
278
279 protected static class FieldBag {
280
281 public FieldBag(Class<?> fieldClass) {
282 _fieldClass = fieldClass;
283 }
284
285 public void addField(Field field) {
286 _fields.add(field);
287 }
288
289 public Class<?> getFieldClass() {
290 return _fieldClass;
291 }
292
293 public List<Field> getFields() {
294 return _fields;
295 }
296
297 private final Class<?> _fieldClass;
298 private final List<Field> _fields = new ArrayList<>();
299
300 }
301
302 private DeleteAfterTestRunTestCallback() {
303 }
304
305 private static final Log _log = LogFactoryUtil.getLog(
306 DeleteAfterTestRunTestCallback.class);
307
308 private static final Set<Class<?>> _orderedClasses = new LinkedHashSet<>(
309 Arrays.<Class<?>>asList(
310 User.class, Organization.class, Role.class, UserGroup.class,
311 Group.class, LayoutPrototype.class, LayoutSetPrototype.class,
312 Company.class));
313
314 }