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