<div dir="ltr">Hi everybody,<div>I&#39;m trying to migrate my webapp from Jetty to Undertow.</div><div><br></div><div>The stack is composed by Undertow Guice and Struts2.</div><div><br></div><div>I developed the following class to configure undertow:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><pre style="color:rgb(0,0,0);word-wrap:break-word;white-space:pre-wrap">package com.billdrawer.website.server;

import io.undertow.Undertow;
import io.undertow.predicate.Predicates;
import io.undertow.server.HandlerWrapper;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.PathHandler;
import io.undertow.server.handlers.PredicateHandler;
import io.undertow.server.handlers.resource.ResourceHandler;
import io.undertow.servlet.api.ConfidentialPortManager;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager;
import io.undertow.servlet.api.FilterInfo;
import io.undertow.servlet.api.ListenerInfo;
import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.SecurityConstraint;
import io.undertow.servlet.api.ServletContainer;
import io.undertow.servlet.api.WebResourceCollection;

import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.EnumSet;

import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.undertow.KeycloakServletExtension;

import com.billdrawer.website.common.Config;
import com.billdrawer.website.listener.WebsiteServletContextListener;
import com.google.inject.servlet.GuiceFilter;

public class UndertowServer implements Server {
    private Logger _logger = Logger.getLogger(UndertowServer.class);
    private Undertow _server;
    private DeploymentManager _manager;
    private int _port;
    private String _host;

    @Inject
    public UndertowServer(@Named(Config.STAGE) String stage, @Named(Config.SERVER_HOST) String host, @Named(Config.SERVER_PORT) int port,
            @Named(Config.SERVER_TIMEOUT) int timeout) {
        _port = port;
        _host = host;

        DeploymentInfo deploymentInfo = getDeploymentInfo(stage);

        ServletContainer _container = ServletContainer.Factory.newInstance();
        _manager = _container.addDeployment(deploymentInfo);
        _manager.deploy();

        Deployment deployment = _manager.getDeployment();
        
        KeycloakServletExtension keycloak = new KeycloakServletExtension();
        deploymentInfo.addServletExtension(keycloak);
        deploymentInfo.addInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME, getKeyloakJson());
        keycloak.handleDeployment(deploymentInfo, _manager.getDeployment().getServletContext());

        final ServletContext servletContext = deployment.getServletContext();
        _logger.debug(&quot;Context initialized:&quot;+servletContext.getContextPath());
    }

    protected String getKeyloakJson() {
        String keycloak = &quot;&quot;;
        URL url = getClassLoader().getResource(&quot;keycloak.json&quot;);
        if (url != null) {
            try {
                byte[] encoded = Files.readAllBytes(Paths.get(url.toURI()));
                keycloak = new String(encoded, &quot;utf-8&quot;);
            } catch (Exception e) {
                _logger.error(&quot;Can&#39;t read keycloak.json&quot;, e);
            }
        }
        return keycloak;
    }

    protected DeploymentInfo getDeploymentInfo(String stage) {
        final DeploymentInfo deploymentInfo = new DeploymentInfo();
        deploymentInfo.setClassLoader(getClassLoader());
        deploymentInfo.setContextPath(&quot;/&quot;);
        deploymentInfo.setDefaultEncoding(&quot;UTF-8&quot;);
        deploymentInfo.setDeploymentName(&quot;website.war&quot;);
        deploymentInfo.setDisplayName(&quot;WebsiteServer&quot;);
        deploymentInfo.setUrlEncoding(&quot;UTF-8&quot;);

        deploymentInfo.addListener(new ListenerInfo(WebsiteServletContextListener.class));

        FilterInfo guiceFilter = new FilterInfo(&quot;GuiceFilter&quot;, GuiceFilter.class);
        deploymentInfo.addFilter(guiceFilter);
        for (DispatcherType dispatcher : EnumSet.allOf(DispatcherType.class)) {
            deploymentInfo.addFilterUrlMapping(guiceFilter.getName(), &quot;/*&quot;, dispatcher);
        }

        FilterInfo strutsPrepareAndExecuteFilter = new FilterInfo(&quot;StrutsFilter&quot;, StrutsPrepareAndExecuteFilter.class);
        deploymentInfo.addFilter(strutsPrepareAndExecuteFilter);
        for (DispatcherType dispatcher : EnumSet.allOf(DispatcherType.class)) {
            deploymentInfo.addFilterUrlMapping(strutsPrepareAndExecuteFilter.getName(), &quot;/*&quot;, dispatcher);
        }

        deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
            @Override
            public HttpHandler wrap(final HttpHandler handler) {
                final ResourceHandler resourceHandler = new ResourceHandler(deploymentInfo.getResourceManager());
                PredicateHandler predicateHandler = new PredicateHandler(Predicates.suffixes(&quot;.css&quot;,&quot;.html&quot;,&quot;.js&quot;),resourceHandler, handler);
                return predicateHandler;
            }
        });

        configureSecurity(deploymentInfo);

        return deploymentInfo;
    }

    protected void configureSecurity(DeploymentInfo deploymentInfo) {
        deploymentInfo.setLoginConfig(new LoginConfig(&quot;KEYCLOAK&quot;, &quot;billdrawer&quot;));
        deploymentInfo.setConfidentialPortManager(new ConfidentialPortManager() {
            @Override
            public int getConfidentialPort(HttpServerExchange exchange) {
                return _port;
            }
        });
        SecurityConstraint securityConstraint = new SecurityConstraint();
        WebResourceCollection webResourceCollection = new WebResourceCollection();
        webResourceCollection.addUrlPattern(&quot;/dashboard/*&quot;);
        securityConstraint.addWebResourceCollection(webResourceCollection);
        securityConstraint.addRoleAllowed(&quot;user&quot;);
        deploymentInfo.addSecurityConstraint(securityConstraint);
    }

    protected ClassLoader getClassLoader() {
        return getClass().getClassLoader();
    }

    public void start() {
        _logger.debug(&quot;starting...&quot;);
        try {
            Undertow.Builder builder = Undertow.builder();
            builder.addHttpListener(_port, _host);

            final PathHandler rootHandler = new PathHandler();
            rootHandler.addPrefixPath(_manager.getDeployment().getDeploymentInfo().getContextPath(), _manager.start());

            builder.setHandler(rootHandler);
            _server = builder.build();
            _server.start();
        } catch (ServletException e) {
            _logger.error(&quot;Unexpected exception&quot;, e);
        }
        _<a href="http://logger.info">logger.info</a>(&quot;###START###&quot;);
    }

    public void stop() {
        _logger.debug(&quot;stopping...&quot;);
        try {
            _manager.stop();
            _server.stop();
        } catch (ServletException e) {
            _logger.error(&quot;Unexpected exception&quot;, e);
        }
        _<a href="http://logger.info">logger.info</a>(&quot;###STOP###&quot;);
    }
}</pre></blockquote><div>Everything is working until I do not try to load resources from context.</div><div>I need some help before rollback to Jetty :(</div><div><br clear="all"><div><div class="gmail_signature"><div>--</div>Davide</div></div>
</div></div>