001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.servlet.filters.monitoring;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.messaging.DestinationNames;
020    import com.liferay.portal.kernel.messaging.MessageBusUtil;
021    import com.liferay.portal.kernel.monitoring.RequestStatus;
022    import com.liferay.portal.kernel.monitoring.statistics.DataSampleThreadLocal;
023    import com.liferay.portal.kernel.servlet.HttpHeaders;
024    import com.liferay.portal.kernel.util.AutoResetThreadLocal;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.ParamUtil;
027    import com.liferay.portal.kernel.util.WebKeys;
028    import com.liferay.portal.model.Layout;
029    import com.liferay.portal.monitoring.statistics.portal.PortalRequestDataSample;
030    import com.liferay.portal.monitoring.statistics.service.ServiceMonitorAdvice;
031    import com.liferay.portal.service.LayoutLocalServiceUtil;
032    import com.liferay.portal.servlet.filters.BasePortalFilter;
033    import com.liferay.portal.util.PortalUtil;
034    import com.liferay.portal.util.PropsValues;
035    import com.liferay.portlet.MonitoringPortlet;
036    
037    import java.io.IOException;
038    
039    import java.lang.reflect.Method;
040    
041    import java.util.concurrent.atomic.AtomicInteger;
042    
043    import javax.servlet.FilterChain;
044    import javax.servlet.ServletException;
045    import javax.servlet.http.HttpServletRequest;
046    import javax.servlet.http.HttpServletResponse;
047    
048    /**
049     * @author Rajesh Thiagarajan
050     * @author Michael C. Han
051     */
052    public class MonitoringFilter extends BasePortalFilter {
053    
054            public static boolean isMonitoringPortalRequest() {
055                    return _monitoringPortalRequest;
056            }
057    
058            public static void setMonitoringPortalRequest(
059                    boolean monitoringPortalRequest) {
060    
061                    _monitoringPortalRequest = monitoringPortalRequest;
062            }
063    
064            @Override
065            public boolean isFilterEnabled() {
066                    if (!super.isFilterEnabled()) {
067                            return false;
068                    }
069    
070                    if (!_monitoringPortalRequest &&
071                            !MonitoringPortlet.isMonitoringPortletActionRequest() &&
072                            !MonitoringPortlet.isMonitoringPortletEventRequest() &&
073                            !MonitoringPortlet.isMonitoringPortletRenderRequest() &&
074                            !MonitoringPortlet.isMonitoringPortletResourceRequest() &&
075                            !ServiceMonitorAdvice.isActive()) {
076    
077                            return false;
078                    }
079    
080                    return true;
081            }
082    
083            protected int decrementProcessFilterCount() {
084                    AtomicInteger processFilterCount = _processFilterCount.get();
085    
086                    return processFilterCount.decrementAndGet();
087            }
088    
089            protected long getGroupId(HttpServletRequest request) {
090                    long groupId = ParamUtil.getLong(request, "groupId");
091    
092                    if (groupId > 0) {
093                            return groupId;
094                    }
095    
096                    Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
097    
098                    if (layout != null) {
099                            return layout.getGroupId();
100                    }
101    
102                    long plid = ParamUtil.getLong(request, "p_l_id");
103    
104                    if (plid > 0) {
105                            try {
106                                    layout = LayoutLocalServiceUtil.getLayout(plid);
107    
108                                    groupId = layout.getGroupId();
109                            }
110                            catch (Exception e) {
111                                    if (_log.isDebugEnabled()) {
112                                            _log.debug("Unable to retrieve layout " + plid, e);
113                                    }
114                            }
115                    }
116    
117                    return groupId;
118            }
119    
120            protected String getRemoteUser(HttpServletRequest request) {
121                    String remoteUser = request.getRemoteUser();
122    
123                    if (remoteUser == null) {
124                            remoteUser = String.valueOf(request.getAttribute(WebKeys.USER_ID));
125                    }
126    
127                    return remoteUser;
128            }
129    
130            protected void incrementProcessFilterCount() {
131                    AtomicInteger processFilterCount = _processFilterCount.get();
132    
133                    processFilterCount.incrementAndGet();
134            }
135    
136            @Override
137            protected void processFilter(
138                            HttpServletRequest request, HttpServletResponse response,
139                            FilterChain filterChain)
140                    throws IOException, ServletException {
141    
142                    long companyId = PortalUtil.getCompanyId(request);
143                    long groupId = getGroupId(request);
144                    String remoteUser = getRemoteUser(request);
145    
146                    PortalRequestDataSample portalRequestDataSample = null;
147    
148                    incrementProcessFilterCount();
149    
150                    if (_monitoringPortalRequest) {
151                            portalRequestDataSample = new PortalRequestDataSample(
152                                    companyId, groupId, request.getHeader(HttpHeaders.REFERER),
153                                    request.getRemoteAddr(), remoteUser, request.getRequestURI(),
154                                    GetterUtil.getString(request.getRequestURL()),
155                                    request.getHeader(HttpHeaders.USER_AGENT));
156    
157                            DataSampleThreadLocal.initialize();
158                    }
159    
160                    try {
161                            if (portalRequestDataSample != null) {
162                                    portalRequestDataSample.prepare();
163                            }
164    
165                            processFilter(
166                                    MonitoringFilter.class, request, response, filterChain);
167    
168                            if (portalRequestDataSample != null) {
169                                    portalRequestDataSample.capture(RequestStatus.SUCCESS);
170    
171                                    portalRequestDataSample.setGroupId(getGroupId(request));
172    
173                                    try {
174                                            Method getStatusMethod =
175                                                    HttpServletResponse.class.getDeclaredMethod(
176                                                            "getStatus");
177    
178                                            int status = (Integer)getStatusMethod.invoke(response);
179    
180                                            portalRequestDataSample.setStatusCode(status);
181                                    }
182                                    catch (Exception e) {
183                                            if (_log.isDebugEnabled()) {
184                                                    _log.debug(e, e);
185                                            }
186                                    }
187                            }
188                    }
189                    catch (Exception e) {
190                            if (portalRequestDataSample != null) {
191                                    portalRequestDataSample.capture(RequestStatus.ERROR);
192                            }
193    
194                            if (e instanceof IOException) {
195                                    throw (IOException)e;
196                            }
197                            else if (e instanceof ServletException) {
198                                    throw (ServletException)e;
199                            }
200                            else {
201                                    throw new ServletException("Unable to execute request", e);
202                            }
203                    }
204                    finally {
205                            if (portalRequestDataSample != null) {
206                                    DataSampleThreadLocal.addDataSample(portalRequestDataSample);
207                            }
208    
209                            if (decrementProcessFilterCount() == 0) {
210                                    MessageBusUtil.sendMessage(
211                                                    DestinationNames.MONITORING,
212                                                    DataSampleThreadLocal.getDataSamples());
213    
214                                    _processFilterCount.remove();
215                            }
216                    }
217            }
218    
219            private static Log _log = LogFactoryUtil.getLog(MonitoringFilter.class);
220    
221            private static final ThreadLocal<AtomicInteger> _processFilterCount =
222                    new AutoResetThreadLocal<AtomicInteger>(
223                            MonitoringFilter.class + "._processFilterCount",
224                            new AtomicInteger(0));
225    
226            private static boolean _monitoringPortalRequest =
227                    PropsValues.MONITORING_PORTAL_REQUEST;
228    
229    }