1
votes

Obtention et enregistrement de la variable d'étendue d'application dans Tomcat

Il s'agit d'une application basée sur Java 1.8 et Tomcat 9, sans pas de Spring .

Je veux pouvoir enregistrer un objet dans une portée d'application et le récupérer par n'importe quelle autre session. Il n'y a qu'un seul serveur Tomcat, il n'est de toute façon pas fédéré. Dans ce cas, nous avons une autorisation d'application basée sur un en-tête AUTH_USER et ROLE_ID vérifié. Le code s'exécute, mais chaque fois qu'il enregistre l'objet dans la portée de l'application, il est oublié ou d'une manière ou d'une autre inaccessible à une demande future. En conséquence, aucune mise en cache ne se produit.

Ma question est de savoir comment enregistrer un objet en création dans une requête et le mettre à disposition via la portée de l'application pour la requête suivante. Veuillez consulter les commentaires dans le code pour voir où je pensais que cela devrait fonctionner.

Les demandes arrivent via une fonction de type Web JAX-RS. Ce que j'ai ci-dessous n'est pas exactement comment il est codé, mais simplifié pour éviter les détails inutiles. Un exemple est:

<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>
    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;
    }

Mon server.xml est

    @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();
        
    }



4 commentaires

et ... quelle est votre vraie question?


@Stultuske Je vais éditer la question, mais comme mentionné ci-dessus, j'aimerais enregistrer un objet dans la portée de l'application. Le code que j'ai ci-dessus est destiné à enregistrer le travail dans une demande et à le rendre accessible dans la suivante.


où le this.httpServletRequest a-t-il été défini?


@Greg J'ai modifié ma question pour afficher un exemple de requête JAX-RS entrante. Pensez-y comme ceci: il faut du temps au service pour charger toutes les autorisations autorisées qu'un utilisateur peut avoir. Ainsi, sur la base des en-têtes de l'ensemble SAML, il ne récupère les valeurs de la base de données que si le cache ne l'a pas.


3 Réponses :


1
votes

Il s'agit d'une application basée sur Java 1.8 et Tomcat 9, sans Spring.

Les attributs Java Servlet peuvent être utilisés pour transmettre des données entre les requêtes. Il existe trois portées différentes: la portée de la requête, la portée de la session et la portée de l'application.

Ma question est de savoir comment enregistrer un objet créant dans une demande et le mettre à disposition via la portée de l'application pour la demande suivante. Veuillez consulter les commentaires dans le code pour voir où je pensais que cela devrait fonctionner.

La portée de l'application est associée à votre application Web. Cette étendue dure aussi longtemps que l'application Web est déployée. Vous pouvez définir les attributs de valeur de portée de l'application dans l'attribut de contexte de votre servlet. Par exemple

@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");

// ...

}

L'attribut stocké au niveau de l'application peut être récupéré en appelant un autre type particulier de requête. Par exemple:

@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");
// ...

}


0 commentaires

1
votes

Peut-être avez-vous besoin d'une session, pas de la portée de l'application. Attributs de stockage de session dans HttpSession, les informations enregistrées ne seront donc disponibles que pour les demandes du même utilisateur.


0 commentaires

2
votes

Carlos, avez-vous réalisé que dans la méthode getAuthorizedHubRequest, vous mettez en cache la variable result, qui après votre code doit être nulle, et non la nouvelle variable allowedHubRequest? Je pense que c'est le problème.


2 commentaires

Je pensais avoir accepté cette réponse plus tôt. J'espère que cette tentative aboutira et que vous pourrez récupérer votre prime.


Ne vous en faites pas @Woodsman. L'important est que la réponse vous ait aidé. Meilleures salutations.