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