UserActivityLoggerImpl implements IUserActivityLogger { @Override public ReturnValue<LoggingObject> log(ILoggingAction loggingAction, Class<?> callingClass, ILoggingResourceable... lriOrNull) { final ActionType actionType = stickyActionType_ != null ? stickyActionType_ : loggingAction.getResourceActionType(); if (isLogAnonymous_ && actionType.equals(ActionType.tracking)) { return ReturnValue.EMPTY; } final CrudAction crudAction = loggingAction.getCrudAction(); final ActionVerb actionVerb = loggingAction.getActionVerb(); final String actionObject = loggingAction.getActionObject(); List<ILoggingResourceable> resourceInfos = getCombinedOrderedLoggingResourceables(lriOrNull); if (loggingAction.getTypeListDefinition() == null) { log.warn("LoggingAction has no ResourceableTypeList defined: action=" + loggingAction + ", fieldId=" + loggingAction.getJavaFieldIdForDebug()); } else { String errorMsg = loggingAction.getTypeListDefinition().executeCheckAndGetErrorMessage(resourceInfos); if (errorMsg != null) { log.warn("LoggingAction reported an inconsistency: " + loggingAction.getActionVerb() + " " + loggingAction.getActionObject() + ", action=" + loggingAction + ", fieldId=" + loggingAction.getJavaFieldIdForDebug() + ", expected: " + loggingAction.getTypeListDefinition().toString() + ", actual: " + convertLoggingResourceableListToString(resourceInfos)); } } if (session_ == null) { log.error("No session available to UserActivityLogger. Cannot write log entry: " + crudAction.name() + ":" + actionVerb.name() + ", " + actionObject + ", " + convertLoggingResourceableListToString(resourceInfos)); return ReturnValue.EMPTY; } if (session_.getSessionInfo() == null || session_.getSessionInfo().getSession() == null || session_.getSessionInfo().getSession().getId() == null || session_.getSessionInfo().getSession().getId().length() == 0) { log.error("No session information available to UserActivityLogger. Cannot write log entry: " + crudAction.name() + ":" + actionVerb.name() + ", " + actionObject + ", " + convertLoggingResourceableListToString(resourceInfos)); return ReturnValue.EMPTY; } final String sessionId = session_.getSessionInfo().getSession().getId(); Identity identity = session_.getIdentity(); if (identity == null) { log.error("No identity available to UserActivityLogger. Cannot write log entry: " + crudAction.name() + ":" + actionVerb.name() + ", " + actionObject + ", " + convertLoggingResourceableListToString(resourceInfos)); return ReturnValue.EMPTY; } Long identityKey = identity.getKey(); if (actionType != ActionType.admin) { final String identityKeyStr = String.valueOf(identityKey); for (Iterator it = resourceInfos.iterator(); it.hasNext();) { ILoggingResourceable lr = (ILoggingResourceable) it.next(); if (lr.getResourceableType() == StringResourceableType.targetIdentity) { if (log.isDebugEnabled() && !lr.getId().equals(identityKeyStr)) { final Writer strackTraceAsStringWriter = new StringWriter(); final PrintWriter printWriter = new PrintWriter(strackTraceAsStringWriter); (new Exception("OLAT-4955 debug stacktrac")).printStackTrace(printWriter); log.debug("OLAT-4955: Not storing targetIdentity for non-admin logging actions. A non-admin logging action wanted to store a user other than the one from the session: action=" + loggingAction + ", fieldId=" + loggingAction.getJavaFieldIdForDebug() + strackTraceAsStringWriter.toString()); } it.remove(); } } } String identityName; if (isLogAnonymous_ && (actionType != ActionType.admin)) { identityName = ""; } else { identityName = identity.getName(); } final LoggingObject logObj = new LoggingObject(sessionId, identityKey, identityName, crudAction.name().substring(0, 1), actionVerb.name(), actionObject, LogModule.isLogAnonymous()); LoggingObject lastLogObj = (LoggingObject) session_.getEntry(USESS_KEY_USER_ACTIVITY_LOGGING_LAST_LOG); if (lastLogObj != null) { Date currentTime = logObj.getCreationDate(); Date lastTime = lastLogObj.getCreationDate(); long duration; if (lastTime == null) { duration = -1; } else if (currentTime == null) { duration = System.currentTimeMillis() - lastTime.getTime(); } else { duration = currentTime.getTime() - lastTime.getTime(); } if (lastLogObj.getKey() != null) { getActivityLoggingDao().updateDuration(lastLogObj, duration); } else { log.error("Trying to update duration of LoggingObject before it had been saved to database [" + lastLogObj + "]"); } } session_.putEntry(USESS_KEY_USER_ACTIVITY_LOGGING_LAST_LOG, logObj); if (resourceInfos != null && resourceInfos.size() != 0) { if (resourceInfos.size() > 4) { log.warn("More than 4 resource infos set on a user activity log. Can only have 4. Having: " + resourceInfos.size()); int diff = resourceInfos.size() - 4; for (int i = 0; i < diff; i++) { resourceInfos.remove(3); } } ILoggingResourceable ri = resourceInfos.get(resourceInfos.size() - 1); logObj.setTargetResourceInfo(ri.getType(), ri.getId(), ri.getName()); if (resourceInfos.size() > 1) { ri = resourceInfos.get(resourceInfos.size() - 2); logObj.setParentResourceInfo(ri.getType(), ri.getId(), ri.getName()); } if (resourceInfos.size() > 2) { ri = resourceInfos.get(resourceInfos.size() - 3); logObj.setGrandParentResourceInfo(ri.getType(), ri.getId(), ri.getName()); } if (resourceInfos.size() > 3) { ri = resourceInfos.get(resourceInfos.size() - 4); logObj.setGreatGrandParentResourceInfo(ri.getType(), ri.getId(), ri.getName()); } } logObj.setBusinessPath(businessPath_); logObj.setSourceClass(callingClass.getCanonicalName()); logObj.setSimpleDuration(-1); logObj.setResourceAdminAction(actionType.equals(ActionType.admin) ? true : false); Locale locale = i18nManager.getLocaleOrDefault(identity.getUser().getPreferences().getLanguage()); List<String> tmpUserProperties = new ArrayList<String>(12); for (Iterator<String> iterator = userProperties_.iterator(); iterator.hasNext();) { String userPropString = getUserService().getPropertyOrIdentityEnvAttribute(identity.getUser(), iterator.next(), locale); boolean shorten = false; try { if (userPropString != null && userPropString.getBytes("UTF-8").length > 254) { shorten = true; } } catch (UnsupportedEncodingException uee) { log.error("error while calculating real string length: unsupported encoding: ", uee); shorten = true; } if (shorten) { log.error("Userproperty was too long for logging-table (shortened automatically). check that nothing valueable is lost! value before cut: " + userPropString); userPropString = userPropString.substring(0, 255); } tmpUserProperties.add(userPropString); } logObj.setUserProperties(tmpUserProperties); getActivityLoggingDao().saveLogObject(logObj); return new ReturnValue(logObj); } UserActivityLoggerImpl(HttpServletRequest hReq);   UserActivityLoggerImpl();   UserActivityLoggerImpl(UserSession userSession, ActivityLoggingDao activityLoggingDao, boolean isLogAnonymous, Set<String> userProperties, I18nManager i18nManager); private  UserActivityLoggerImpl(IUserActivityLogger userActivityLogger, WindowControl wControl, boolean propageToThreadLocal); static UserActivityLoggerImpl setupLoggerForController(WindowControl wControl); static IUserActivityLogger newLoggerForValueUnbound(UserSession session); static UserActivityLoggerImpl newLoggerForEventBus(GenericEventListener listener); @Override void frameworkSetSession(UserSession session); @Override void addLoggingResourceInfo(ILoggingResourceable loggingResourceable); @Override void frameworkSetBusinessPath(String businessPath); @Override void frameworkSetBCContextEntries(List<ContextEntry> bcEntries); @Override void frameworkSetBusinessPathFromWindowControl(WindowControl wControl); @Override void setStickyActionType(ActionType actionType); @Override ActionType getStickyActionType(); @Override ReturnValue<LoggingObject> log(ILoggingAction loggingAction, Class<?> callingClass, ILoggingResourceable... lriOrNull); static final String USESS_KEY_USER_ACTIVITY_LOGGING_LAST_LOG; }
@Test public void testLog_noLoggingWithAnonymusModeActionTypeTracking() { IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, true); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(defaultLoggingActionMock, this.getClass(), null); verify(activityLoggingDaoMock, never()).saveLogObject(returnValue.getValue()); }
@Test public void testLog_noLoggingWhenSessionInfoIsNull() { when(userSessionMock.getSessionInfo()).thenReturn(null); IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, false); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(defaultLoggingActionMock, this.getClass(), null); verify(activityLoggingDaoMock, never()).saveLogObject(returnValue.getValue()); assertNull("should not log when 'SessionInfo is null' ", returnValue.getValue()); }
@Test public void testLog_noLoggingWhenSessionInfoSessionIsNull() { SessionInfo sessionInfo = mock(SessionInfo.class); when(sessionInfo.getSession()).thenReturn(null); when(userSessionMock.getSessionInfo()).thenReturn(sessionInfo); IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, false); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(defaultLoggingActionMock, this.getClass(), null); verify(activityLoggingDaoMock, never()).saveLogObject(returnValue.getValue()); assertNull("should not log when 'SessionInfo.getSession() is null' ", returnValue.getValue()); }
@Test public void testLog_noLoggingWhenSessionInfoSessionIdIsNull() { HttpSession session = mock(HttpSession.class); when(session.getId()).thenReturn(null); SessionInfo sessionInfo = mock(SessionInfo.class); when(sessionInfo.getSession()).thenReturn(session); when(userSessionMock.getSessionInfo()).thenReturn(sessionInfo); IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, false); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(defaultLoggingActionMock, this.getClass(), null); verify(activityLoggingDaoMock, never()).saveLogObject(returnValue.getValue()); assertNull("should not log when 'SessionInfo.getSession().getId() is null' ", returnValue.getValue()); }
@Test public void testLog_noLoggingWhenSessionInfoSessionIdhasLengthZero() { HttpSession session = mock(HttpSession.class); when(session.getId()).thenReturn(""); SessionInfo sessionInfo = mock(SessionInfo.class); when(sessionInfo.getSession()).thenReturn(session); when(userSessionMock.getSessionInfo()).thenReturn(sessionInfo); IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, false); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(defaultLoggingActionMock, this.getClass(), null); verify(activityLoggingDaoMock, never()).saveLogObject(returnValue.getValue()); assertNull("should not log when 'SessionInfo.getSession().getId().length = 0' ", returnValue.getValue()); }
@Test public void testLog_noLoggingWhenSessionIdentityIsNull() { HttpSession session = mock(HttpSession.class); when(session.getId()).thenReturn("session_id"); SessionInfo sessionInfo = mock(SessionInfo.class); when(sessionInfo.getSession()).thenReturn(session); when(userSessionMock.getSessionInfo()).thenReturn(sessionInfo); when(userSessionMock.getIdentity()).thenReturn(null); IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, false); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(defaultLoggingActionMock, this.getClass(), null); verify(activityLoggingDaoMock, never()).saveLogObject(returnValue.getValue()); assertNull("should not log when 'SessionInfo.getIdentity() is null' ", returnValue.getValue()); }
@Test public void testLog_AnonymousLoggingHasNoUsernameForActionTypeStatistic() { IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, true); ILoggingAction loginAction = createLoggingActionMock(ActionType.statistic); when(loginAction.getActionObject()).thenReturn("test"); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(loginAction, this.getClass(), null); verify(activityLoggingDaoMock).saveLogObject(returnValue.getValue()); assertNotNull("Missing logging, no log-object created", returnValue.getValue()); assertEquals("Logging must have empty username '' because it is anonymus and ActionType=statistic", "", returnValue.getValue().getUserName()); }
@Test public void testLog_NoneAnonymousLoggingHasUsernameForActionTypeStatistic() { IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, false); ILoggingAction loginAction = createLoggingActionMock(ActionType.statistic); when(loginAction.getActionObject()).thenReturn("test"); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(loginAction, this.getClass(), null); verify(activityLoggingDaoMock).saveLogObject(returnValue.getValue()); assertNotNull("Missing logging, no log-object created ", returnValue.getValue()); assertEquals("Logging must use username '" + testUserName + "' because it is non-anonymus and ActionType=statistic", testUserName, returnValue.getValue() .getUserName()); }
@Test public void testLog_NoAnonymousLoggingForActionTypeAdmin() { IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, true); ILoggingAction loginAction = createLoggingActionMock(ActionType.admin); when(loginAction.getActionObject()).thenReturn("test"); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(loginAction, this.getClass(), null); verify(activityLoggingDaoMock).saveLogObject(returnValue.getValue()); assertNotNull("Missing logging, no log-object created", returnValue.getValue()); assertEquals("Logging must have username '" + testUserName + "' because it is anonymus but ActionType=admin", testUserName, returnValue.getValue().getUserName()); }
@Test public void testLog_update() { IUserActivityLogger userActivityLogger = createUserActivityLogger(userSessionMock, true); ILoggingAction loginAction = createLoggingActionMock(ActionType.admin); when(loginAction.getActionObject()).thenReturn("test"); ReturnValue<LoggingObject> returnValue = userActivityLogger.log(loginAction, this.getClass()); verify(activityLoggingDaoMock).saveLogObject(returnValue.getValue()); when(userSessionMock.getEntry(UserActivityLoggerImpl.USESS_KEY_USER_ACTIVITY_LOGGING_LAST_LOG)).thenReturn(returnValue.getValue()); ReturnValue<LoggingObject> lastReturnValue = userActivityLogger.log(loginAction, this.getClass()); verify(activityLoggingDaoMock).saveLogObject(lastReturnValue.getValue()); }