PluginDispatchServlet implements Servlet { @VisibleForTesting protected void configurePluginWebsockets( Map.Entry<String, ListableBeanFactory> pluginBeanFactoryEntry ) { Map<String, IWebsocketEndpointConfig> wsBeans = getWebsocketEndpointConfigBeans( pluginBeanFactoryEntry.getValue() ); if ( logger.isDebugEnabled() ) { logger.debug( "Found " + wsBeans.size() + " websocket endpoints in " + pluginBeanFactoryEntry.getKey() ); } ServletContext servletContext = getServletConfig().getServletContext(); String servletContextPath = servletContext.getContextPath(); String pluginId = pluginBeanFactoryEntry.getKey(); for ( Map.Entry<String, IWebsocketEndpointConfig> beanEntry : wsBeans.entrySet() ) { IWebsocketEndpointConfig websocketEndpointConfig = beanEntry.getValue(); Predicate<String> isOriginAllowedPredicate = websocketEndpointConfig.getIsOriginAllowedPredicate(); Class<?> pluginEndpointClass = websocketEndpointConfig.getEndpointImpl(); List<String> subProtocols = websocketEndpointConfig.getSubProtocolAccepted(); String endpointConfigPath = websocketEndpointConfig.getUrlSufix(); String context = "/" + pluginId + "/" + WEBSOCKET_PLUGIN_PATH_PREFIX + "/" + endpointConfigPath; try { ServerEndpointConfig serverConfig = ServerEndpointConfig.Builder.create( pluginEndpointClass, context ). configurator( getServerWebsocketEndpointConfigurator( servletContextPath, isOriginAllowedPredicate ) ).subprotocols( subProtocols ) .build(); serverConfig.getUserProperties().put( websocketEndpointConfig.getServletContextPathPropertyName(), servletContextPath ); serverConfig.getUserProperties().put( websocketEndpointConfig.getMaxMessagePropertyName(), websocketEndpointConfig.getMaxMessageBytesLength() ); ServerContainer serverContainer = (ServerContainer) servletContext.getAttribute( ServerContainer.class.getName() ); if ( serverContainer != null ) { serverContainer.addEndpoint( serverConfig ); if ( logger.isInfoEnabled() ) { logger.info( pluginId + " plugin Websocket available in path " + context ); } } else { logger.warn( pluginId + " plugin Websocket could not be configured because ServerContainer is missing" ); } } catch ( DeploymentException ex ) { logger.error( "Failed to register endpoint for " + beanEntry.getClass() + " on " + context + ": " + ex.getMessage(), ex ); } } } PluginDispatchServlet(); void destroy(); void service( final ServletRequest req, final ServletResponse res ); String getDispatchKey( HttpServletRequest request ); void init( final ServletConfig config ); ServletConfig getServletConfig(); String getServletInfo();  }
@Test public void testConfigurePluginWebsockets() throws DeploymentException { String pluginId = "pluginId"; String contextPath = "/pentaho"; String websocketKey = "websocketEndpoint"; ListableBeanFactory listableBeanFactory = mock( ListableBeanFactory.class ); Map.Entry<String, ListableBeanFactory> pluginBeanFactoryEntry = new AbstractMap.SimpleEntry<String, ListableBeanFactory>( pluginId, listableBeanFactory ); Map<String, IWebsocketEndpointConfig> wsBeans = new TreeMap<>( ); List<String> subProtocolAccepted = Arrays.asList( new String[]{ "subProtocol1", "subProtocol2" } ); Predicate<String> isOriginAllowedPredicate = s -> "http: int maxMessageBytesLength = 5000; ServletConfig servletConfig = mock( ServletConfig.class ); ServletContext servletContext = mock( ServletContext.class ); when( pluginDispatchServlet.getServletConfig() ).thenReturn( servletConfig ); when( servletConfig.getServletContext() ).thenReturn( servletContext ); when( servletContext.getContextPath() ).thenReturn( contextPath ); ServerContainer serverContainer = mock( ServerContainer.class ); when( servletContext.getAttribute( ServerContainer.class.getName() ) ).thenReturn( serverContainer ); IWebsocketEndpointConfig websocketEndpointConfig = new WebsocketEndpointConfig( "urlSufix", Object.class, subProtocolAccepted, isOriginAllowedPredicate, maxMessageBytesLength ); wsBeans.put( websocketKey, websocketEndpointConfig); when( pluginDispatchServlet.getWebsocketEndpointConfigBeans( listableBeanFactory ) ).thenReturn( wsBeans ); ServerEndpointConfig.Configurator endpointConfigurator = mock ( ServerEndpointConfig.Configurator.class ); when( pluginDispatchServlet.getServerWebsocketEndpointConfigurator( contextPath, isOriginAllowedPredicate ) ).thenReturn( endpointConfigurator ); pluginDispatchServlet.configurePluginWebsockets( pluginBeanFactoryEntry ); verify( serverContainer, times( 1 ) ).addEndpoint( any( ServerEndpointConfig.class ) ); }