TransWikia.com

Getting and saving application scope variable in Tomcat

Stack Overflow Asked by Woodsman on December 13, 2021

This is a Java 1.8 and Tomcat 9 based application, with no Spring.

I want to be able to save an object in an application scope and have it fetchable by any other session. There is only one Tomcat server, it’s not federated in anyway. In this case, we have application authorization that happens based on a verified AUTH_USER and ROLE_ID header. The code runs, but every time it saves the object to the application scope, it gets forgotten or somehow not accessible to any future request. As a result, no caching happens.

My question is how do I save an object creating in one request and have it available via application scope for the next request. Please see comments in code to see where I thought it should work.

Requests come in via a web JAX-RS type function. What I have below isn’t exactly how it’s coded, but simplified to avoid unnecessary details. An example of one is:

    @POST
    @Path("getDashboardTotalHubs")
    @Produces({ MediaType.APPLICATION_JSON + AppConstants.COMMA + MediaType.CHARSET_PARAMETER + AppConstants.UTF_8 })
    @Consumes(MediaType.APPLICATION_JSON)
    public Response getDashboardTotalHubs(@Context HttpServletRequest httpServletRequest,
            HubRequestFilter hubRequestFilter) {
        // I want to get check authorization based on the value of the HTTP request headers here.  
        this.httpServletRequest = httpServletRequest;
        AuthorizedHubRequest = getCachedAuthorizedHubRequestMap();
        
    }


    private Map<String,AuthorizedHubRequest> getCachedAuthorizedHubRequestMap() {
        // I thought getSevletContext gave me the global application scope, but I'm somehow
        // wrong.  
        ServletContext context = this.getHttpServletRequest().getServletContext();
        Map<String,AuthorizedHubRequest> result = (Map<String, AuthorizedHubRequest>) context.getAttribute(AuthorizedHubRequest.class.getName());
        if(result == null) {
            result = new HashMap<String,AuthorizedHubRequest>();
            context.setAttribute(AuthorizedHubRequest.class.getName(),result);
        }
        return result;
    }

    private String getAuthorizedHubRequestCacheKey() {
        return this.authUser + "-"+ this.httpServletRequest.getHeader("Authorization") + "-"+ this.roleId;
    }
        
    private AuthorizedHubRequest getAuthorizedHubRequestFromCache() {
        String key = getAuthorizedHubRequestCacheKey();
        return getCachedAuthorizedHubRequestMap().get(key);  // This always returns null
    }

    private void saveAuthorizedHubRequestToCache(AuthorizedHubRequest authorizedHubRequest) {
        String key = getAuthorizedHubRequestCacheKey();
        getCachedAuthorizedHubRequestMap().put(key,authorizedHubRequest);
    }

    public AuthorizedHubRequest getAuthorizedHubRequest() throws SCExceptions {
        AuthorizedHubRequest result = getAuthorizedHubRequestFromCache();
        if(result != null) {
            logger.info("SC_TRACE_ID: "+this.traceId+" Retrieved authorization from cache");
        } else {
            logger.info("SC_TRACE_ID: "+this.traceId+" Authorization not in cache.  Creating.");
            authorizedHubRequest = new AuthorizedHubRequest().withHubRequestFilter(hubRequestFilter).withTraceId(traceId);
            if (this.pageNumber != null && this.pageSize != null) {
                authorizedHubRequest.setPageNumberRequested(pageNumber);
                authorizedHubRequest.setPageSize(pageSize);
            }

            if(this.maximumCacheDuration!=null) {
                authorizedHubRequest.setMaximumCacheDuration(maximumCacheDuration);
            }

            SCHubAuthorizationServiceHandler authHandler = new SCHubAuthorizationServiceHandler();
            authorizedHubRequest.setHubAuthorizations(authHandler.getHubAuthorization(traceId, authUser, roleId));
            saveAuthorizedHubRequestToCache(result);
        }

        return this.authorizedHubRequest;
    }

My server.xml is

<Server port="8015" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
  <Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
  <GlobalNamingResources>
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector connectionTimeout="20000" port="8090" protocol="HTTP/1.1" redirectPort="8443"/>
    <Engine defaultHost="localhost" name="Catalina">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </Realm>
      <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/>
      </Host>
    </Engine>
  </Service>
</Server>

3 Answers

Carlos, have you realized that in the method getAuthorizedHubRequest you are actually caching the variable result, which following your code must be null, and not the new variable authorizedHubRequest? I think that is the problem.

Answered by jccampanero on December 13, 2021

Maybe you need session, not application scope. Session store attributes in HttpSession, so saved information will be available only for requests from same user.

Answered by rell on December 13, 2021

This is a Java 1.8 and Tomcat 9 based application, with no Spring.

The Java Servlet attributes can be used to pass data between requests. There are three different scopes: request scope, session scope and application scope.

My question is how do I save an object creating in one request and have it available via application scope for the next request. Please see comments in code to see where I thought it should work.

The Application Scope is associated with your web application. This scope lives as long as the web application is deployed. You can set the application scoped value attributes in your servlet context attribute. For example

@WebServlet("/set-application-scope-attributes")
public class SetAttributesServlet extends HttpServlet{

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // set application scoped attribute
        req.getServletContext().setAttribute("name", "application scoped attribute");
// ...

}

The application level scoped stored attribute can be retrieved calling another particular type of request. For example:

@WebServlet("/get-application-scoped-attribute")
public class GetAttributesServlet extends HttpServlet{

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // get application scoped attribute
        String applicationScope = (String)req.getServletContext().getAttribute("name");

// ...

}

Answered by fabfas on December 13, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP