001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.systemevent;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.systemevent.SystemEvent;
020    import com.liferay.portal.kernel.systemevent.SystemEventHierarchyEntry;
021    import com.liferay.portal.kernel.systemevent.SystemEventHierarchyEntryThreadLocal;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.model.AuditedModel;
025    import com.liferay.portal.model.ClassedModel;
026    import com.liferay.portal.model.GroupedModel;
027    import com.liferay.portal.model.StagedModel;
028    import com.liferay.portal.model.SystemEventConstants;
029    import com.liferay.portal.model.TypedModel;
030    import com.liferay.portal.service.SystemEventLocalServiceUtil;
031    import com.liferay.portal.spring.aop.AnnotationChainableMethodAdvice;
032    import com.liferay.portlet.exportimport.lar.StagedModelType;
033    
034    import java.io.Serializable;
035    
036    import java.lang.annotation.Annotation;
037    import java.lang.reflect.Method;
038    
039    import org.aopalliance.intercept.MethodInvocation;
040    
041    /**
042     * @author Zsolt Berentey
043     */
044    public class SystemEventAdvice
045            extends AnnotationChainableMethodAdvice<SystemEvent> {
046    
047            @Override
048            public void afterReturning(MethodInvocation methodInvocation, Object result)
049                    throws Throwable {
050    
051                    SystemEvent systemEvent = findAnnotation(methodInvocation);
052    
053                    if ((systemEvent == _nullSystemEvent) || !systemEvent.send()) {
054                            return;
055                    }
056    
057                    if (!isValid(methodInvocation, _PHASE_AFTER_RETURNING)) {
058                            return;
059                    }
060    
061                    Object[] arguments = methodInvocation.getArguments();
062    
063                    ClassedModel classedModel = (ClassedModel)arguments[0];
064    
065                    long groupId = getGroupId(classedModel);
066    
067                    String className = getClassName(classedModel);
068    
069                    String referrerClassName = null;
070    
071                    if (classedModel instanceof TypedModel) {
072                            TypedModel typedModel = (TypedModel)classedModel;
073    
074                            referrerClassName = typedModel.getClassName();
075                    }
076    
077                    long classPK = getClassPK(classedModel);
078    
079                    SystemEventHierarchyEntry systemEventHierarchyEntry =
080                            SystemEventHierarchyEntryThreadLocal.peek();
081    
082                    if ((systemEventHierarchyEntry != null) &&
083                            systemEventHierarchyEntry.hasTypedModel(className, classPK)) {
084    
085                            if (groupId > 0) {
086                                    SystemEventLocalServiceUtil.addSystemEvent(
087                                            0, groupId, systemEventHierarchyEntry.getClassName(),
088                                            classPK, systemEventHierarchyEntry.getUuid(),
089                                            referrerClassName, systemEvent.type(),
090                                            systemEventHierarchyEntry.getExtraData());
091                            }
092                            else {
093                                    SystemEventLocalServiceUtil.addSystemEvent(
094                                            getCompanyId(classedModel),
095                                            systemEventHierarchyEntry.getClassName(), classPK,
096                                            systemEventHierarchyEntry.getUuid(), referrerClassName,
097                                            systemEvent.type(),
098                                            systemEventHierarchyEntry.getExtraData());
099                            }
100                    }
101                    else if (groupId > 0) {
102                            SystemEventLocalServiceUtil.addSystemEvent(
103                                    0, groupId, className, classPK, getUuid(classedModel),
104                                    referrerClassName, systemEvent.type(), StringPool.BLANK);
105                    }
106                    else {
107                            SystemEventLocalServiceUtil.addSystemEvent(
108                                    getCompanyId(classedModel), className, classPK,
109                                    getUuid(classedModel), referrerClassName, systemEvent.type(),
110                                    StringPool.BLANK);
111                    }
112            }
113    
114            @Override
115            public Object before(MethodInvocation methodInvocation) throws Throwable {
116                    SystemEvent systemEvent = findAnnotation(methodInvocation);
117    
118                    if (systemEvent == _nullSystemEvent) {
119                            return null;
120                    }
121    
122                    if (systemEvent.action() != SystemEventConstants.ACTION_NONE) {
123                            if (!isValid(methodInvocation, _PHASE_BEFORE)) {
124                                    return null;
125                            }
126    
127                            Object[] arguments = methodInvocation.getArguments();
128    
129                            ClassedModel classedModel = (ClassedModel)arguments[0];
130    
131                            SystemEventHierarchyEntry systemEventHierarchyEntry =
132                                    SystemEventHierarchyEntryThreadLocal.push(
133                                            getClassName(classedModel), getClassPK(classedModel),
134                                            systemEvent.action());
135    
136                            if (systemEventHierarchyEntry != null) {
137                                    systemEventHierarchyEntry.setUuid(getUuid(classedModel));
138                            }
139                    }
140    
141                    return null;
142            }
143    
144            @Override
145            public void duringFinally(MethodInvocation methodInvocation) {
146                    SystemEvent systemEvent = findAnnotation(methodInvocation);
147    
148                    if (systemEvent == _nullSystemEvent) {
149                            return;
150                    }
151    
152                    if (!isValid(methodInvocation, _PHASE_DURING_FINALLY)) {
153                            return;
154                    }
155    
156                    if (systemEvent.action() == SystemEventConstants.ACTION_NONE) {
157                            return;
158                    }
159    
160                    Object[] arguments = methodInvocation.getArguments();
161    
162                    ClassedModel classedModel = (ClassedModel)arguments[0];
163    
164                    long classPK = getClassPK(classedModel);
165    
166                    if (classPK == 0) {
167                            return;
168                    }
169    
170                    SystemEventHierarchyEntryThreadLocal.pop(
171                            getClassName(classedModel), classPK);
172            }
173    
174            @Override
175            public SystemEvent getNullAnnotation() {
176                    return _nullSystemEvent;
177            }
178    
179            protected String getClassName(ClassedModel classedModel) {
180                    String className = classedModel.getModelClassName();
181    
182                    if (classedModel instanceof StagedModel) {
183                            StagedModel stagedModel = (StagedModel)classedModel;
184    
185                            StagedModelType stagedModelType = stagedModel.getStagedModelType();
186    
187                            className = stagedModelType.getClassName();
188                    }
189    
190                    return className;
191            }
192    
193            protected long getClassPK(ClassedModel classedModel) {
194                    Serializable primaryKeyObj = classedModel.getPrimaryKeyObj();
195    
196                    if (!(primaryKeyObj instanceof Long)) {
197                            return 0;
198                    }
199    
200                    return (Long)primaryKeyObj;
201            }
202    
203            protected long getCompanyId(ClassedModel classedModel) {
204                    if (classedModel instanceof AuditedModel) {
205                            AuditedModel auditedModel = (AuditedModel)classedModel;
206    
207                            return auditedModel.getCompanyId();
208                    }
209    
210                    if (classedModel instanceof GroupedModel) {
211                            GroupedModel groupedModel = (GroupedModel)classedModel;
212    
213                            return groupedModel.getCompanyId();
214                    }
215    
216                    if (classedModel instanceof StagedModel) {
217                            StagedModel stagedModel = (StagedModel)classedModel;
218    
219                            return stagedModel.getCompanyId();
220                    }
221    
222                    return 0;
223            }
224    
225            protected long getGroupId(ClassedModel classedModel) {
226                    if (!(classedModel instanceof GroupedModel)) {
227                            return 0;
228                    }
229    
230                    GroupedModel groupedModel = (GroupedModel)classedModel;
231    
232                    return groupedModel.getGroupId();
233            }
234    
235            protected String getUuid(ClassedModel classedModel) throws Exception {
236                    if (classedModel instanceof StagedModel) {
237                            StagedModel stagedModel = (StagedModel)classedModel;
238    
239                            return stagedModel.getUuid();
240                    }
241    
242                    Method getUuidMethod = null;
243    
244                    try {
245                            Class<?> modelClass = classedModel.getClass();
246    
247                            getUuidMethod = modelClass.getMethod("getUuid", new Class[0]);
248                    }
249                    catch (Exception e) {
250                            return StringPool.BLANK;
251                    }
252    
253                    return (String)getUuidMethod.invoke(classedModel, new Object[0]);
254            }
255    
256            protected boolean isValid(MethodInvocation methodInvocation, int phase) {
257                    Method method = methodInvocation.getMethod();
258    
259                    Class<?>[] parameterTypes = method.getParameterTypes();
260    
261                    if (parameterTypes.length == 0) {
262                            if (_log.isDebugEnabled() && (phase == _PHASE_BEFORE)) {
263                                    _log.debug(
264                                            "The method " + methodInvocation +
265                                                    " must have at least one parameter");
266                            }
267    
268                            return false;
269                    }
270    
271                    Class<?> parameterType = parameterTypes[0];
272    
273                    if (!ClassedModel.class.isAssignableFrom(parameterType)) {
274                            if (_log.isDebugEnabled() && (phase == _PHASE_BEFORE)) {
275                                    _log.debug(
276                                            "The first parameter of " + methodInvocation +
277                                                    " must implement ClassedModel");
278                            }
279    
280                            return false;
281                    }
282    
283                    Object[] arguments = methodInvocation.getArguments();
284    
285                    ClassedModel classedModel = (ClassedModel)arguments[0];
286    
287                    if ((classedModel == null) ||
288                            !(classedModel.getPrimaryKeyObj() instanceof Long)) {
289    
290                            if (_log.isDebugEnabled() && (phase == _PHASE_BEFORE)) {
291                                    _log.debug(
292                                            "The first parameter of " + methodInvocation +
293                                                    " must be a long");
294                            }
295    
296                            return false;
297                    }
298    
299                    if (phase != _PHASE_AFTER_RETURNING) {
300                            return true;
301                    }
302    
303                    if (!AuditedModel.class.isAssignableFrom(parameterType) &&
304                            !GroupedModel.class.isAssignableFrom(parameterType) &&
305                            !StagedModel.class.isAssignableFrom(parameterType)) {
306    
307                            if (_log.isDebugEnabled()) {
308                                    StringBundler sb = new StringBundler(4);
309    
310                                    sb.append("If send is true, the first parameter of ");
311                                    sb.append(methodInvocation);
312                                    sb.append(" must implement AuditedModel, GroupedModel, or ");
313                                    sb.append("StagedModel");
314    
315                                    _log.debug(sb.toString());
316                            }
317    
318                            return false;
319                    }
320    
321                    return true;
322            }
323    
324            private static final int _PHASE_AFTER_RETURNING = 1;
325    
326            private static final int _PHASE_BEFORE = 0;
327    
328            private static final int _PHASE_DURING_FINALLY = 2;
329    
330            private static final Log _log = LogFactoryUtil.getLog(
331                    SystemEventAdvice.class);
332    
333            private static final SystemEvent _nullSystemEvent = new SystemEvent() {
334    
335                    @Override
336                    public Class<? extends Annotation> annotationType() {
337                            return SystemEvent.class;
338                    }
339    
340                    @Override
341                    public int action() {
342                            return SystemEventConstants.ACTION_NONE;
343                    }
344    
345                    @Override
346                    public boolean send() {
347                            return false;
348                    }
349    
350                    @Override
351                    public int type() {
352                            return 0;
353                    }
354    
355            };
356    
357    }