001    /**
002     * Copyright (c) 2000-2011 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.monitoring.statistics.service;
016    
017    import com.liferay.portal.kernel.exception.SystemException;
018    import com.liferay.portal.kernel.messaging.MessageBusUtil;
019    import com.liferay.portal.kernel.util.AutoResetThreadLocal;
020    import com.liferay.portal.kernel.util.MethodKey;
021    import com.liferay.portal.monitoring.MonitoringService;
022    import com.liferay.portal.monitoring.RequestStatus;
023    import com.liferay.portal.monitoring.statistics.DataSampleThreadLocal;
024    import com.liferay.portal.spring.aop.ChainableMethodAdvice;
025    
026    import java.lang.reflect.Method;
027    
028    import java.util.HashSet;
029    import java.util.Set;
030    
031    import org.aopalliance.intercept.MethodInvocation;
032    
033    /**
034     * @author Michael C. Han
035     */
036    public class ServiceMonitorAdvice extends ChainableMethodAdvice {
037    
038            public static ServiceMonitorAdvice getInstance() {
039                    return _instance;
040            }
041    
042            public void addMonitoredClass(String className) {
043                    _monitoredClasses.add(className);
044            }
045    
046            public void addMonitoredMethod(
047                            String className, String methodName, String[] parameterTypes)
048                    throws SystemException {
049    
050                    try {
051                            MethodKey methodKey = new MethodKey(
052                                    className, methodName, parameterTypes);
053    
054                            _monitoredMethods.add(methodKey);
055                    }
056                    catch (ClassNotFoundException cnfe) {
057                            throw new SystemException("Unable to add method", cnfe);
058                    }
059            }
060    
061            public void afterReturning(MethodInvocation methodInvocation, Object result)
062                    throws Throwable {
063    
064                    ServiceRequestDataSample serviceRequestDataSample =
065                            _serviceRequestDataSampleThreadLocal.get();
066    
067                    if (serviceRequestDataSample != null) {
068                            serviceRequestDataSample.capture(RequestStatus.SUCCESS);
069                    }
070            }
071    
072            public void afterThrowing(
073                            MethodInvocation methodInvocation, Throwable throwable)
074                    throws Throwable {
075    
076                    ServiceRequestDataSample serviceRequestDataSample =
077                            _serviceRequestDataSampleThreadLocal.get();
078    
079                    if (serviceRequestDataSample != null) {
080                            serviceRequestDataSample.capture(RequestStatus.ERROR);
081                    }
082            }
083    
084            public Object before(MethodInvocation methodInvocation) throws Throwable {
085                    if (!_active) {
086                            return null;
087                    }
088    
089                    Class<?> classObj = methodInvocation.getThis().getClass();
090    
091                    Class<?>[] interfaces = classObj.getInterfaces();
092    
093                    for (int i = 0; i < interfaces.length; i++) {
094                            if (interfaces[i].isAssignableFrom(MonitoringService.class)) {
095                                    return null;
096                            }
097                    }
098    
099                    if (!_permissiveMode && !isMonitored(methodInvocation)) {
100                            return null;
101                    }
102    
103                    ServiceRequestDataSample serviceRequestDataSample =
104                            new ServiceRequestDataSample(methodInvocation);
105    
106                    serviceRequestDataSample.prepare();
107    
108                    _serviceRequestDataSampleThreadLocal.set(serviceRequestDataSample);
109    
110                    return null;
111            }
112    
113            public void duringFinally(MethodInvocation methodInvocation) {
114                    ServiceRequestDataSample serviceRequestDataSample =
115                            _serviceRequestDataSampleThreadLocal.get();
116    
117                    if (serviceRequestDataSample != null) {
118                            _serviceRequestDataSampleThreadLocal.remove();
119    
120                            DataSampleThreadLocal.addDataSample(serviceRequestDataSample);
121    
122                            MessageBusUtil.sendMessage(
123                                    _monitoringDestinationName, serviceRequestDataSample);
124                    }
125            }
126    
127            public Set<String> getMonitoredClasses() {
128                    return _monitoredClasses;
129            }
130    
131            public Set<MethodKey> getMonitoredMethods() {
132                    return _monitoredMethods;
133            }
134    
135            public String getMonitoringDestinationName() {
136                    return _monitoringDestinationName;
137            }
138    
139            public boolean isActive() {
140                    return _active;
141            }
142    
143            public boolean isPermissiveMode() {
144                    return _permissiveMode;
145            }
146    
147            public void setActive(boolean active) {
148                    _active = active;
149            }
150    
151            public void setMonitoredClasses(Set<String> monitoredClasses) {
152                    _monitoredClasses = monitoredClasses;
153            }
154    
155            public void setMonitoredMethods(Set<MethodKey> monitoredMethods) {
156                    _monitoredMethods = monitoredMethods;
157            }
158    
159            public void setMonitoringDestinationName(String monitoringDestinationName) {
160                    _monitoringDestinationName = monitoringDestinationName;
161            }
162    
163            public void setPermissiveMode(boolean permissiveMode) {
164                    _permissiveMode = permissiveMode;
165            }
166    
167            protected boolean isMonitored(MethodInvocation methodInvocation) {
168                    Method method = methodInvocation.getMethod();
169    
170                    Class<?> declaringClass = method.getDeclaringClass();
171    
172                    String className = declaringClass.getName();
173    
174                    if (_monitoredClasses.contains(className)) {
175                            return true;
176                    }
177    
178                    String methodName = method.getName();
179                    Class<?>[] parameterTypes = method.getParameterTypes();
180    
181                    MethodKey methodKey = new MethodKey(
182                            className, methodName, parameterTypes);
183    
184                    if (_monitoredMethods.contains(methodKey)) {
185                            return true;
186                    }
187    
188                    return false;
189            }
190    
191            private static ServiceMonitorAdvice _instance = new ServiceMonitorAdvice();
192    
193            private static ThreadLocal<ServiceRequestDataSample>
194                    _serviceRequestDataSampleThreadLocal =
195                            new AutoResetThreadLocal<ServiceRequestDataSample>(
196                                    ServiceRequestDataSample.class +
197                                            "._serviceRequestDataSampleThreadLocal");
198    
199            private boolean _active;
200            private Set<String> _monitoredClasses = new HashSet<String>();
201            private Set<MethodKey> _monitoredMethods = new HashSet<MethodKey>();
202            private String _monitoringDestinationName;
203            private boolean _permissiveMode;
204    
205    }