/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.test.rule.callback;
import com.liferay.portal.kernel.model.Company;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.model.LayoutPrototype;
import com.liferay.portal.kernel.model.LayoutSetPrototype;
import com.liferay.portal.kernel.model.Organization;
import com.liferay.portal.kernel.model.PersistedModel;
import com.liferay.portal.kernel.model.Role;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.model.UserGroup;
import com.liferay.portal.kernel.service.PersistedModelLocalService;
import com.liferay.portal.kernel.service.PersistedModelLocalServiceRegistryUtil;
import com.liferay.portal.kernel.test.rule.DeleteAfterTestRun;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.StringBundler;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.junit.runner.Description;
/**
* @author Shuyang Zhou
*/
public class DeleteAfterTestRunTestCallback
extends BaseTestCallback<Object, Object> {
public static final DeleteAfterTestRunTestCallback INSTANCE =
new DeleteAfterTestRunTestCallback();
@Override
public void afterMethod(
Description description, Object object, Object target)
throws Exception {
Class<?> testClass = description.getTestClass();
Map<Class<?>, FieldBag> deleteAfterTestRunFieldBags = new HashMap<>();
while (testClass != null) {
for (Field field : testClass.getDeclaredFields()) {
DeleteAfterTestRun deleteAfterTestRun = field.getAnnotation(
DeleteAfterTestRun.class);
if (deleteAfterTestRun == null) {
continue;
}
Class<?> fieldClass = field.getType();
if (PersistedModel.class.isAssignableFrom(fieldClass)) {
addField(deleteAfterTestRunFieldBags, fieldClass, field);
continue;
}
if (fieldClass.isArray()) {
if (!PersistedModel.class.isAssignableFrom(
fieldClass.getComponentType())) {
throw new IllegalArgumentException(
"Unable to annotate field " + field +
" because it is not an array of type " +
PersistedModel.class.getName());
}
addField(
deleteAfterTestRunFieldBags,
fieldClass.getComponentType(), field);
continue;
}
if (Collection.class.isAssignableFrom(fieldClass)) {
field.setAccessible(true);
Collection<?> collection = (Collection<?>)field.get(target);
if ((collection == null) || collection.isEmpty()) {
continue;
}
Class<?> collectionType = getCollectionType(collection);
if (collectionType == null) {
throw new IllegalArgumentException(
"Unable to annotate field " + field +
" because it is not a collection of type " +
PersistedModel.class.getName());
}
addField(
deleteAfterTestRunFieldBags, collectionType, field);
continue;
}
StringBundler sb = new StringBundler(6);
sb.append("Unable to annotate field ");
sb.append(field);
sb.append(" because it is not type of ");
sb.append(PersistedModel.class.getName());
sb.append(" nor an array or collection of ");
sb.append(PersistedModel.class.getName());
throw new IllegalArgumentException(sb.toString());
}
testClass = testClass.getSuperclass();
}
Set<Map.Entry<Class<?>, FieldBag>> set =
deleteAfterTestRunFieldBags.entrySet();
Iterator<Map.Entry<Class<?>, FieldBag>> iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry<Class<?>, FieldBag> entry = iterator.next();
Class<?> clazz = entry.getKey();
if (_orderedClasses.contains(clazz)) {
continue;
}
iterator.remove();
removeField(entry.getValue(), target);
}
for (Class<?> clazz : _orderedClasses) {
FieldBag fieldBag = deleteAfterTestRunFieldBags.remove(clazz);
if (fieldBag == null) {
continue;
}
removeField(fieldBag, target);
}
}
protected void addField(
Map<Class<?>, FieldBag> deleteAfterTestRunFieldBags, Class<?> clazz,
Field field) {
FieldBag fieldBag = deleteAfterTestRunFieldBags.get(clazz);
if (fieldBag == null) {
fieldBag = new FieldBag(clazz);
deleteAfterTestRunFieldBags.put(clazz, fieldBag);
}
field.setAccessible(true);
fieldBag.addField(field);
}
protected Class<? extends PersistedModel> getCollectionType(
Collection<?> collection) {
Class<? extends PersistedModel> collectionType = null;
for (Object object : collection) {
Queue<Class<?>> classes = new LinkedList<>();
classes.add(object.getClass());
Class<?> clazz = null;
while ((clazz = classes.poll()) != null) {
if (ArrayUtil.contains(
clazz.getInterfaces(), PersistedModel.class)) {
if (collectionType == null) {
collectionType = (Class<? extends PersistedModel>)clazz;
}
else if (collectionType != clazz) {
return null;
}
break;
}
classes.add(clazz.getSuperclass());
Collections.addAll(classes, clazz.getInterfaces());
}
}
return collectionType;
}
protected void removeField(FieldBag fieldBag, Object instance)
throws Exception {
Class<?> fieldClass = fieldBag.getFieldClass();
PersistedModelLocalService persistedModelLocalService =
PersistedModelLocalServiceRegistryUtil.
getPersistedModelLocalService(fieldClass.getName());
for (Field field : fieldBag.getFields()) {
Object object = field.get(instance);
if (object == null) {
continue;
}
Class<?> objectClass = object.getClass();
if (objectClass.isArray()) {
for (PersistedModel persistedModel : (PersistedModel[])object) {
if (persistedModel == null) {
continue;
}
persistedModelLocalService.deletePersistedModel(
persistedModel);
}
}
else if (Collection.class.isAssignableFrom(objectClass)) {
Collection<? extends PersistedModel> collection =
(Collection<? extends PersistedModel>)object;
for (PersistedModel persistedModel : collection) {
persistedModelLocalService.deletePersistedModel(
persistedModel);
}
}
else {
persistedModelLocalService.deletePersistedModel(
(PersistedModel)object);
}
field.set(instance, null);
}
}
protected static class FieldBag {
public FieldBag(Class<?> fieldClass) {
_fieldClass = fieldClass;
}
public void addField(Field field) {
_fields.add(field);
}
public Class<?> getFieldClass() {
return _fieldClass;
}
public List<Field> getFields() {
return _fields;
}
private final Class<?> _fieldClass;
private final List<Field> _fields = new ArrayList<>();
}
private DeleteAfterTestRunTestCallback() {
}
private static final Set<Class<?>> _orderedClasses = new LinkedHashSet<>(
Arrays.<Class<?>>asList(
User.class, Organization.class, Role.class, UserGroup.class,
Group.class, LayoutPrototype.class, LayoutSetPrototype.class,
Company.class));
}