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 org.apache.wicket.request.ILogData;
020import org.apache.wicket.request.ILoggableRequestHandler;
021import org.apache.wicket.request.IRequestHandler;
022import org.apache.wicket.request.handler.logger.NoLogData;
023import org.apache.wicket.session.ISessionStore;
024import org.apache.wicket.util.io.IClusterable;
025import org.apache.wicket.util.string.Strings;
026
027import java.util.ArrayList;
028import java.util.Date;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033/**
034 * Interface for the request logger and viewer.
035 * 
036 * @see org.apache.wicket.Application#newRequestLogger()
037 * 
038 * @author jcompagner
039 */
040public interface IRequestLogger
041{
042        /**
043         * @return The total created sessions counter
044         */
045        int getTotalCreatedSessions();
046
047        /**
048         * @return The peak sessions counter
049         */
050        int getPeakSessions();
051
052        /**
053         * This method returns a List of the current requests that are in mem. This is a readonly list.
054         * 
055         * @return Collection of the current requests
056         */
057        List<RequestData> getRequests();
058
059        /**
060         * @return Collection of live Sessions Data
061         */
062        SessionData[] getLiveSessions();
063
064        /**
065         * @return The current active requests
066         */
067        int getCurrentActiveRequestCount();
068
069        /**
070         * @return The {@link org.apache.wicket.protocol.http.IRequestLogger.RequestData} for the current request.
071         */
072        RequestData getCurrentRequest();
073
074        /**
075         * @return The peak active requests
076         */
077        int getPeakActiveRequestCount();
078
079        /**
080         * @return The number of requests per minute.
081         */
082        long getRequestsPerMinute();
083
084        /**
085         * @return The average request time.
086         */
087        long getAverageRequestTime();
088
089        /**
090         * called when the session is created and has an id. (for http it means that the http session is
091         * created)
092         * 
093         * @param id
094         *            the session id
095         */
096        void sessionCreated(String id);
097
098        /**
099         * Method used to cleanup a livesession when the session was invalidated by the webcontainer
100         * 
101         * @param sessionId
102         *            the session id
103         */
104        void sessionDestroyed(String sessionId);
105
106        /**
107         * This method is called when the request is over. This will set the total time a request takes
108         * and cleans up the current request data.
109         * 
110         * @param timeTaken
111         *            the time taken in milliseconds
112         */
113        void requestTime(long timeTaken);
114
115        /**
116         * Called to monitor removals of objects out of the {@link ISessionStore}
117         * 
118         * @param value
119         *            the object being removed
120         */
121        void objectRemoved(Object value);
122
123        /**
124         * Called to monitor updates of objects in the {@link ISessionStore}
125         * 
126         * @param value
127         *            the object being updated
128         */
129        void objectUpdated(Object value);
130
131        /**
132         * Called to monitor additions of objects in the {@link ISessionStore}
133         * 
134         * @param value
135         *            the object being created/added
136         */
137        void objectCreated(Object value);
138
139        /**
140         * Sets the target that was the response target for the current request
141         * 
142         * @param target
143         *            the response target
144         */
145        void logResponseTarget(IRequestHandler target);
146
147        /**
148         * Sets the target that was the event target for the current request
149         * 
150         * @param target
151         *            the event target
152         */
153        void logEventTarget(IRequestHandler target);
154
155        /**
156         * Logs the URL that was requested by the browser.
157         * 
158         * @param url
159         *            the requested URL
160         */
161        void logRequestedUrl(String url);
162
163        /**
164         * Perform the actual logging
165         */
166        void performLogging();
167
168        /**
169         * This class hold the information one request of a session has.
170         * 
171         * @author jcompagner
172         */
173        class SessionData implements IClusterable, Comparable<SessionData>
174        {
175                private static final long serialVersionUID = 1L;
176
177                private final String sessionId;
178                private final long startDate;
179                private long lastActive;
180                private long numberOfRequests;
181                private long totalTimeTaken;
182                private long sessionSize;
183                private Object sessionInfo;
184
185                /**
186                 * Construct.
187                 * 
188                 * @param sessionId
189                 */
190                public SessionData(String sessionId)
191                {
192                        this.sessionId = sessionId;
193                        startDate = System.currentTimeMillis();
194                        numberOfRequests = 1;
195                }
196
197                /**
198                 * @return The last active date.
199                 */
200                public Date getLastActive()
201                {
202                        return new Date(lastActive);
203                }
204
205                /**
206                 * @return The start date of this session
207                 */
208                public Date getStartDate()
209                {
210                        return new Date(startDate);
211                }
212
213                /**
214                 * @return The number of request for this session
215                 */
216                public long getNumberOfRequests()
217                {
218                        return numberOfRequests;
219                }
220
221                /**
222                 * @return Returns the session size.
223                 */
224                public long getSessionSize()
225                {
226                        return sessionSize;
227                }
228
229                /**
230                 * @return Returns the total time this session has spent in ms.
231                 */
232                public long getTotalTimeTaken()
233                {
234                        return totalTimeTaken;
235                }
236
237                /**
238                 * @return The session info object given by the {@link ISessionLogInfo#getSessionInfo()}
239                 *         session method.
240                 */
241                public Object getSessionInfo()
242                {
243                        return sessionInfo;
244                }
245
246                /**
247                 * @return The session id
248                 */
249                public String getSessionId()
250                {
251                        return sessionId;
252                }
253
254                /**
255                 * Adds {@code time} to the total server time.
256                 * 
257                 * @param time
258                 */
259                public void addTimeTaken(long time)
260                {
261                        lastActive = System.currentTimeMillis();
262                        numberOfRequests++;
263                        totalTimeTaken += time;
264                }
265
266                /**
267                 * Sets additional session info (e.g. logged in user).
268                 * 
269                 * @param sessionInfo
270                 */
271                public void setSessionInfo(Object sessionInfo)
272                {
273                        this.sessionInfo = sessionInfo;
274                }
275
276                /**
277                 * Sets the recorded session size.
278                 * 
279                 * @param size
280                 */
281                public void setSessionSize(long size)
282                {
283                        sessionSize = size;
284                }
285
286                @Override
287                public int compareTo(SessionData sd)
288                {
289                        if (sd.startDate > startDate)
290                        {
291                                return 1;
292                        }
293                        else if (sd.startDate < startDate)
294                        {
295                                return -1;
296                        }
297                        return 0;
298                }
299        }
300
301
302        /**
303         * This class hold the information one request of a session has.
304         * 
305         * @author jcompagner
306         */
307        class RequestData implements IClusterable
308        {
309                private static final long serialVersionUID = 1L;
310
311                private long startDate;
312                private long timeTaken;
313                private final List<String> entries = new ArrayList<>(5);
314                private Map<String, Object> userData;
315                private String requestedUrl;
316                private IRequestHandler eventTarget;
317                private IRequestHandler responseTarget;
318                private String sessionId;
319                private long totalSessionSize;
320                private Object sessionInfo;
321                private int activeRequest;
322
323                /**
324                 * @return The time taken for this request
325                 */
326                public Long getTimeTaken()
327                {
328                        return timeTaken;
329                }
330
331                /**
332                 * @param activeRequest
333                 *            The number of active request when this request happened
334                 */
335                public void setActiveRequest(int activeRequest)
336                {
337                        this.activeRequest = activeRequest;
338                }
339
340                /**
341                 * @return The number of active request when this request happened
342                 */
343                public int getActiveRequest()
344                {
345                        return activeRequest;
346                }
347
348                /**
349                 * @return The session object info, created by {@link ISessionLogInfo#getSessionInfo()}
350                 */
351                public Object getSessionInfo()
352                {
353                        return sessionInfo;
354                }
355
356                /**
357                 * Set the session info object of the session for this request.
358                 * 
359                 * @param sessionInfo
360                 */
361                public void setSessionInfo(Object sessionInfo)
362                {
363                        this.sessionInfo = sessionInfo;
364                }
365
366                /**
367                 * @param sizeInBytes
368                 */
369                public void setSessionSize(long sizeInBytes)
370                {
371                        totalSessionSize = sizeInBytes;
372                }
373
374                /**
375                 * @param id
376                 */
377                public void setSessionId(String id)
378                {
379                        sessionId = id;
380                }
381
382                /**
383                 * @return The time taken for this request
384                 */
385                public Date getStartDate()
386                {
387                        return new Date(startDate);
388                }
389
390                /**
391                 * @return The event target
392                 */
393                public IRequestHandler getEventTarget()
394                {
395                        return eventTarget;
396                }
397
398                /**
399                 * @return The class of the event target
400                 */
401                public Class<? extends IRequestHandler> getEventTargetClass()
402                {
403                        return eventTarget == null ? null : eventTarget.getClass();
404                }
405
406                /**
407                 * @return The log data for the eventTarget, or {@link NoLogData} if the request handler is
408                 *         not loggable
409                 */
410                public ILogData getEventTargetLog()
411                {
412                        if (eventTarget instanceof ILoggableRequestHandler)
413                                return ((ILoggableRequestHandler)eventTarget).getLogData();
414                        return new NoLogData();
415                }
416
417                /**
418                 * @return The response target
419                 */
420                public IRequestHandler getResponseTarget()
421                {
422                        return responseTarget;
423                }
424
425                /**
426                 * @return The class of the response target
427                 */
428                public Class<? extends IRequestHandler> getResponseTargetClass()
429                {
430                        return responseTarget == null ? null : responseTarget.getClass();
431                }
432
433                /**
434                 * @return The log data for the responseTarget, or {@link NoLogData} if the request handler
435                 *         is not loggable
436                 */
437                public ILogData getResponseTargetLog()
438                {
439                        if (responseTarget instanceof ILoggableRequestHandler)
440                                return ((ILoggableRequestHandler)responseTarget).getLogData();
441                        return new NoLogData();
442                }
443
444                /**
445                 * @return the requested URL by the browser
446                 */
447                public String getRequestedUrl()
448                {
449                        return requestedUrl;
450                }
451
452                /**
453                 * @param requestedUrl
454                 */
455                public void setRequestedUrl(String requestedUrl)
456                {
457                        this.requestedUrl = requestedUrl;
458                }
459
460                /**
461                 * @param target
462                 */
463                public void setResponseTarget(IRequestHandler target)
464                {
465                        responseTarget = target;
466                }
467
468                /**
469                 * @param target
470                 */
471                public void setEventTarget(IRequestHandler target)
472                {
473                        eventTarget = target;
474                }
475
476                /**
477                 * @param timeTaken
478                 */
479                public void setTimeTaken(long timeTaken)
480                {
481                        this.timeTaken = timeTaken;
482                        startDate = System.currentTimeMillis() - timeTaken;
483                }
484
485                /**
486                 * @param string
487                 */
488                public void addEntry(String string)
489                {
490                        entries.add(string);
491                }
492
493                /**
494                 * @param key
495                 * @param value
496                 */
497                public void addUserData(String key, Object value)
498                {
499                        getUserData().put(key, value);
500                }
501
502                /**
503                 * @param key
504                 * @return
505                 */
506                public Object getUserData(String key)
507                {
508                        return getUserData().get(key);
509                }
510
511                /**
512                 * @return the userData Map
513                 */
514                public Map<String, Object> getUserData()
515                {
516                        if (userData == null) {
517                                userData = new HashMap<>();
518                        }
519
520                        return userData;
521                }
522
523                /**
524                 * @return All entries of the objects that are created/updated or removed in this request
525                 */
526                public String getAlteredObjects()
527                {
528                        return Strings.join(", ", entries);
529                }
530
531                /**
532                 * @return The session id for this request
533                 */
534                public String getSessionId()
535                {
536                        return sessionId;
537                }
538
539                /**
540                 * @return The total session size.
541                 */
542                public Long getSessionSize()
543                {
544                        return totalSessionSize;
545                }
546
547                @Override
548                public String toString()
549                {
550                        return "Request[timetaken=" + getTimeTaken() + ",sessioninfo=" + sessionInfo +
551                                ",sessionid=" + sessionId + ",sessionsize=" + totalSessionSize + ",request=" +
552                                eventTarget + ",response=" + responseTarget + ",alteredobjects=" +
553                                getAlteredObjects() + ",activerequest=" + activeRequest + "]";
554                }
555        }
556
557        /**
558         * This interface can be implemented in a custom session object. to give an object that has more
559         * information for the current session (state of session).
560         * 
561         * @author jcompagner
562         */
563        interface ISessionLogInfo
564        {
565                /**
566                 * If you use the request logger log functionality then this object should have a nice
567                 * String representation. So make sure that the toString() is implemented for the returned
568                 * object.
569                 * 
570                 * @return The custom object stored in the request loggers current request.
571                 */
572                Object getSessionInfo();
573        }
574}