Skip to content

Commit

Permalink
#24990 include in 23.01.7
Browse files Browse the repository at this point in the history
  • Loading branch information
erickgonzalez committed Sep 8, 2023
1 parent b9b2516 commit 700491b
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 94 deletions.
6 changes: 5 additions & 1 deletion docker/dotcms/ROOT/srv/00-config-defaults.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export DOT_SAMESITE_COOKIES=${DOT_SAMESITE_COOKIES:-"lax"}

#Tomcat Redis
if [[ "${TOMCAT_REDIS_SESSION_ENABLED}" == 'true' ]]; then
export TOMCAT_REDIS_SESSION_CONFIG=${TOMCAT_REDIS_SESSION_CONFIG:-'<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" /><Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" />'}
export TOMCAT_REDIS_SESSION_CONFIG=${TOMCAT_REDIS_SESSION_CONFIG:-'<Valve className="com.dotcms.tomcat.redissessions.RedisSessionHandlerValve" /><Manager className="com.dotcms.tomcat.redissessions.RedisSessionManager" />'}
export TOMCAT_REDIS_SESSION_HOST=${TOMCAT_REDIS_SESSION_HOST:-"redis"}
export TOMCAT_REDIS_SESSION_PORT=${TOMCAT_REDIS_SESSION_PORT:-"6379"}
export TOMCAT_REDIS_SESSION_PASSWORD=${TOMCAT_REDIS_SESSION_PASSWORD:-""}
Expand All @@ -43,6 +43,10 @@ if [[ "${TOMCAT_REDIS_SESSION_ENABLED}" == 'true' ]]; then
export TOMCAT_REDIS_SESSION_DATABASE=${TOMCAT_REDIS_SESSION_DATABASE:-"0"}
export TOMCAT_REDIS_SESSION_TIMEOUT=${TOMCAT_REDIS_SESSION_TIMEOUT:-"2000"}
export TOMCAT_REDIS_SESSION_PERSISTENT_POLICIES=${TOMCAT_REDIS_SESSION_PERSISTENT_POLICIES}
export TOMCAT_REDIS_MAX_CONNECTIONS=${TOMCAT_REDIS_MAX_CONNECTIONS:-"128"}
export TOMCAT_REDIS_MAX_IDLE_CONNECTIONS=${TOMCAT_REDIS_MAX_IDLE_CONNECTIONS:-"100"}
export TOMCAT_REDIS_MIN_IDLE_CONNECTIONS=${TOMCAT_REDIS_MIN_IDLE_CONNECTIONS:-"32"}
export TOMCAT_REDIS_ENABLED_FOR_ANON_TRAFFIC=${TOMCAT_REDIS_ENABLED_FOR_ANON_TRAFFIC:-"false"}
fi


Expand Down

Large diffs are not rendered by default.

55 changes: 24 additions & 31 deletions dotCMS/src/main/java/com/dotcms/listeners/SessionMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import com.dotcms.api.system.event.*;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.UserAPI;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.dotmarketing.util.WebKeys;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -27,7 +29,7 @@
public class SessionMonitor implements ServletRequestListener,
HttpSessionAttributeListener, HttpSessionListener {


public static final String DOT_CLUSTER_SESSION = "DOT_CLUSTER_SESSION";
private final SystemEventsAPI systemEventsAPI;

public SessionMonitor() {
Expand All @@ -42,9 +44,9 @@ public SessionMonitor(final SystemEventsAPI systemEventsAPI) {


// this will hold all logged in users
private Map<String, String> sysUsers = new ConcurrentHashMap<String, String>();
private Map<String, HttpSession> userSessions = new ConcurrentHashMap<String, HttpSession>();
private Map<String, String> sysUsersAddress = new ConcurrentHashMap<String, String>();
private final Map<String, String> sysUsers = new ConcurrentHashMap<>();
private final Map<String, HttpSession> userSessions = new ConcurrentHashMap<>();
private final Map<String, String> sysUsersAddress = new ConcurrentHashMap<>();

public Map<String, String> getSysUsers() {
return sysUsers;
Expand All @@ -59,17 +61,17 @@ public Map<String, String> getSysUsersAddress() {
}

public void attributeAdded(HttpSessionBindingEvent event) {
//Not Implemented
}

/**
* Checks if the attribute removed is "USER_ID". If so, remove the logout
* user
*
*/
public void attributeRemoved(HttpSessionBindingEvent event) {
String currentAttributeName = event.getName().toString();

if (currentAttributeName.equals("USER_ID")) {
public void attributeRemoved(final HttpSessionBindingEvent event) {
final String currentAttributeName = event.getName();
if (currentAttributeName.equals(com.liferay.portal.util.WebKeys.USER_ID)) {

String id = event.getSession().getId();

Expand All @@ -83,28 +85,16 @@ public void attributeRemoved(HttpSessionBindingEvent event) {
* Do nothing here.
*/
public void attributeReplaced(HttpSessionBindingEvent event) {
//Not Implemented
}

public void sessionCreated(final HttpSessionEvent event) {

/*final String userId = (String) event.getSession().getAttribute("USER_ID");
if (userId != null) {
try {
Logger.debug(this, "Triggering a session created event");
this.systemEventsAPI.push(new SystemEvent
(SystemEventType.SESSION_CREATED, new Payload(new Date())));
} catch (DotDataException e) {
Logger.debug(this, "Could not sent the session created event" + e.getMessage(), e);
}
}*/
//Not Implemented
}

public void sessionDestroyed(final HttpSessionEvent event) {

final String userId = (String) event.getSession().getAttribute("USER_ID");
final String userId = (String) event.getSession().getAttribute(com.liferay.portal.util.WebKeys.USER_ID);
if (userId != null) {

final String sessionId = event.getSession().getId();
Expand All @@ -117,9 +107,8 @@ public void sessionDestroyed(final HttpSessionEvent event) {

Logger.debug(this, "Triggering a session destroyed event");

final Boolean isLogout = event.getSession().getAttribute(LOG_OUT_ATTRIBUTE) != null ?
Boolean.parseBoolean(event.getSession().getAttribute(LOG_OUT_ATTRIBUTE).toString()) :
false;
final boolean isLogout =
event.getSession().getAttribute(LOG_OUT_ATTRIBUTE) != null && Boolean.parseBoolean(event.getSession().getAttribute(LOG_OUT_ATTRIBUTE).toString());

if (!isLogout) {
this.systemEventsAPI.push(new SystemEvent
Expand All @@ -134,15 +123,16 @@ public void sessionDestroyed(final HttpSessionEvent event) {

@Override
public void requestDestroyed(ServletRequestEvent arg0) {
//Not Implemented
}

@Override
public void requestInitialized(ServletRequestEvent event) {
HttpSession session = ((HttpServletRequest) event.getServletRequest())
public void requestInitialized(final ServletRequestEvent event) {
final HttpSession session = ((HttpServletRequest) event.getServletRequest())
.getSession(false);
if (session != null && session.getAttribute("USER_ID") != null) {
String userId = (String) session.getAttribute("USER_ID");
String id = session.getId();
if (session != null && session.getAttribute(com.liferay.portal.util.WebKeys.USER_ID) != null) {
final String userId = (String) session.getAttribute(com.liferay.portal.util.WebKeys.USER_ID);
final String id = session.getId();
synchronized (sysUsers) {
if (!sysUsers.containsKey(id)) {
sysUsers.put(id, userId);
Expand All @@ -159,6 +149,9 @@ public void requestInitialized(ServletRequestEvent event) {
.getRemoteAddr());
}
}
if (UtilMethods.isSet(userId) && !UserAPI.CMS_ANON_USER_ID.equalsIgnoreCase(userId)) {
session.setAttribute(DOT_CLUSTER_SESSION, true);
}
}
event.getServletContext().setAttribute(WebKeys.USER_SESSIONS, this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.dotcms.rest.annotation.NoCache;
import com.dotcms.rest.exception.mapper.ExceptionMapperUtil;
import com.dotcms.system.AppContext;
import com.dotcms.system.CompositeAppContext;
import com.dotcms.system.SimpleMapAppContext;
import com.dotcms.util.LongPollingService;
import com.dotcms.util.marshal.MarshalFactory;
import com.dotcms.util.marshal.MarshalUtils;
Expand Down Expand Up @@ -143,8 +145,8 @@ public final void getEvents(@Context final HttpServletRequest httpServletRequest
.requestAndResponse(httpServletRequest, httpServletResponse)
.rejectWhenNoUser(true).init();

//final AppContext appContext = new SimpleMapAppContext();
final AppContext appContext = WebSessionContext.getInstance(httpServletRequest);
final AppContext simpleAppContext = new SimpleMapAppContext();
final AppContext webAppContext = WebSessionContext.getInstance(httpServletRequest);

try {

Expand All @@ -155,14 +157,15 @@ public final void getEvents(@Context final HttpServletRequest httpServletRequest
asyncResponse.setTimeout(this.timeoutSeconds, TimeUnit.SECONDS);

Logger.debug(this, "Getting syncr system events with a lastcallback as: " + lastCallback);
appContext.setAttribute(SystemEventsDelegate.LAST_CALLBACK, lastCallback != null ? lastCallback :
webAppContext.setAttribute(SystemEventsDelegate.LAST_CALLBACK, lastCallback != null ? lastCallback :
System.currentTimeMillis());

appContext.setAttribute(SystemEventsDelegate.LAST_CALLBACK, (null != lastCallback)?lastCallback:System.currentTimeMillis());
appContext.setAttribute(SystemEventsDelegate.RESPONSE, asyncResponse);
appContext.setAttribute(SystemEventsDelegate.USER, initData.getUser());

this.longPollingService.executeAsync(appContext);
webAppContext.setAttribute(SystemEventsDelegate.LAST_CALLBACK, (null != lastCallback)?lastCallback:System.currentTimeMillis());
webAppContext.setAttribute(SystemEventsDelegate.USER, initData.getUser());
// The AsyncResponse is not serializable. So, it can't be stored in the Session because it causes
// problems with Long Polling when using the Redis Session Manager feature
simpleAppContext.setAttribute(SystemEventsDelegate.RESPONSE, asyncResponse);
this.longPollingService.executeAsync(new CompositeAppContext(webAppContext, webAppContext, simpleAppContext));
}
} catch (Exception e) { // this is an unknown error, so we report as a 500.

Expand Down
39 changes: 39 additions & 0 deletions dotCMS/src/main/java/com/dotcms/system/CompositeAppContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.dotcms.system;

import java.util.stream.Stream;

/**
* This class is a composite of one or more {@link AppContext} objects. When a specific attribute is requested, it will
* try to get it from the first context that has it.
*
* @author jsanca
* @since Jun 7th, 2023
*/
public class CompositeAppContext implements AppContext {

private final AppContext writeContext;
private final AppContext[] readContexts;

public CompositeAppContext(final AppContext writeContext, final AppContext... readContexts) {
this.writeContext = writeContext;
this.readContexts = null == readContexts? new AppContext[0] : readContexts;
}

@Override
public <T> T getAttribute(final String attributeName) {
return (T)Stream.of(this.readContexts).filter(context -> context.getAttribute(attributeName) != null)
.map(c -> c.getAttribute(attributeName)).findFirst().orElse(null);
}

@Override
public <T> void setAttribute(String attributeName, T attributeValue) {
if (null != this.writeContext) {
this.writeContext.setAttribute(attributeName, attributeValue);
}
}

@Override
public String getId() {
return AppContext.super.getId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
import java.util.function.Function;

/**
* Simple Implementation based on a map.
* This is a simple implementation of the {@link AppContext}. It uses a Map to store the attributes instead of using,
* for instance, the current HTTP Session.
* <p>This can be particularly useful in case you need to interact with objects that are not serializable and the Redis
* Session Manager is enabled. Trying to persist non-serializable objects to Redis will cause errors in the system.</p>.
*
* @author jsanca
* @since Jun 7th, 2023
*/
public class SimpleMapAppContext implements AppContext {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dotmarketing.portlets.workflows.model;

import java.io.Serializable;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
Expand All @@ -10,7 +11,8 @@
import com.dotmarketing.util.UtilMethods;
import com.liferay.portal.model.User;

public class WorkflowSearcher {

public class WorkflowSearcher implements Serializable {

String schemeId;
String assignedTo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.dotmarketing.util;

import com.google.common.annotations.VisibleForTesting;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
* This services encapsulates the environment variables and allows
* for a better testing to override, add environment variables.
* @author jsanca
*/
public class EnvironmentVariablesService {

private static class SingletonHolder {
private static final EnvironmentVariablesService INSTANCE = new EnvironmentVariablesService();
}
/**
* Get the instance.
* @return EnvironmentVariablesService
*/
public static EnvironmentVariablesService getInstance() {

return EnvironmentVariablesService.SingletonHolder.INSTANCE;
} // getInstance.

private final Map<String, String> envMap = new ConcurrentHashMap<>();
private EnvironmentVariablesService() {

System.getenv().entrySet().stream()
.forEach(e -> envMap.put(e.getKey(), e.getValue()));
}

@VisibleForTesting
public EnvironmentVariablesService put (final String envKey, final String envValue) {

// todo: add condition if profile is test, allows
Optional.ofNullable(envValue).ifPresent(v -> this.envMap.put(envKey, envValue));
return this;
}

/**
* Returns the environment map
* @return Map
*/
public Map<String, String> getenv() {

return this.envMap;
}


}
1 change: 1 addition & 0 deletions hotfix_tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,4 @@ This maintenance release includes the following code fixes:
**Release-23.01.7**

97. https://github.com/dotCMS/core/issues/24294 : Implement Redisson Session sharing #24294
98. https://github.com/dotCMS/core/issues/24990 : Punch List : Redis Session Manager #24990

0 comments on commit 700491b

Please sign in to comment.