001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.protocol.http;
018
019import javax.servlet.http.HttpServletRequest;
020
021import org.apache.wicket.Application;
022import org.apache.wicket.request.IRequestHandler;
023import org.apache.wicket.request.cycle.IRequestCycleListener;
024import org.apache.wicket.request.cycle.RequestCycle;
025import org.apache.wicket.settings.RequestLoggerSettings;
026import org.apache.wicket.util.string.AppendingStringBuffer;
027
028/**
029 * Listener that logs request details in the {@link Application#getRequestLogger()} request logger.
030 */
031public class RequestLoggerRequestCycleListener implements IRequestCycleListener
032{
033        /**
034         * Listeners are not thread safe. In order to keep track if a handler was the first in the
035         * request cycle, register a {@code ThreadLocal} that gets cleared out at the
036         * {@link #onEndRequest(RequestCycle) end of the request}
037         */
038        private static final ThreadLocal<IRequestHandler> first = new ThreadLocal<IRequestHandler>();
039
040        @Override
041        public void onBeginRequest(RequestCycle cycle)
042        {
043                if (!isRequestLoggingEnabled())
044                        return;
045
046                registerRequestedUrl(cycle);
047        }
048
049        @Override
050        public void onRequestHandlerScheduled(RequestCycle cycle, IRequestHandler handler)
051        {
052                if (!isRequestLoggingEnabled())
053                        return;
054
055                registerHandler(handler);
056        }
057
058        @Override
059        public void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler)
060        {
061                if (!isRequestLoggingEnabled())
062                        return;
063
064                registerHandler(handler);
065        }
066
067        @Override
068        public void onExceptionRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler,
069                Exception exception)
070        {
071                if (!isRequestLoggingEnabled())
072                        return;
073
074                registerHandler(handler);
075        }
076
077        @Override
078        public void onEndRequest(RequestCycle cycle)
079        {
080                first.remove();
081        }
082
083        /**
084         * Determine whether a IRequestLogger is provided, and whether request logging has been enabled.
085         * 
086         * @return true when request logging is enabled.
087         */
088        private boolean isRequestLoggingEnabled()
089        {
090                IRequestLogger requestLogger = Application.get().getRequestLogger();
091                RequestLoggerSettings settings = Application.get().getRequestLoggerSettings();
092                return requestLogger != null && settings.isRequestLoggerEnabled();
093        }
094
095        /**
096         * Registers the requested URL with the request logger, if one can be determined.
097         * 
098         * @param cycle
099         */
100        private void registerRequestedUrl(RequestCycle cycle)
101        {
102                IRequestLogger requestLogger = Application.get().getRequestLogger();
103                if (cycle.getRequest().getContainerRequest() instanceof HttpServletRequest)
104                {
105                        HttpServletRequest containerRequest = (HttpServletRequest)cycle.getRequest()
106                                .getContainerRequest();
107
108                        AppendingStringBuffer url = new AppendingStringBuffer(containerRequest.getRequestURL());
109                        if (containerRequest.getQueryString() != null)
110                                url.append("?").append(containerRequest.getQueryString());
111
112                        requestLogger.logRequestedUrl(url.toString());
113                }
114        }
115
116        /**
117         * Registers the handler with the request logger. The first handler is used as the incoming
118         * request handler, and the last registered handler as the outgoing response handler.
119         * 
120         * @param handler
121         */
122        private void registerHandler(IRequestHandler handler)
123        {
124                IRequestLogger requestLogger = Application.get().getRequestLogger();
125
126                if (first.get() == null)
127                {
128                        first.set(handler);
129                        requestLogger.logEventTarget(handler);
130                }
131                requestLogger.logResponseTarget(handler);
132        }
133}