/** * Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org> * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.seedstack.seed.web.internal.websocket; import com.google.common.collect.Lists; import io.nuun.kernel.api.plugin.InitState; import io.nuun.kernel.api.plugin.context.InitContext; import io.nuun.kernel.api.plugin.request.ClasspathScanRequest; import org.seedstack.seed.core.SeedRuntime; import org.seedstack.seed.core.internal.AbstractSeedPlugin; import org.seedstack.seed.web.spi.FilterDefinition; import org.seedstack.seed.web.spi.ListenerDefinition; import org.seedstack.seed.web.spi.ServletDefinition; import org.seedstack.seed.web.spi.WebProvider; import org.seedstack.shed.reflect.Classes; import javax.servlet.ServletContext; import javax.websocket.ClientEndpoint; import javax.websocket.ClientEndpointConfig; import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; /** * This plugin scan Endpoint, ClientEndpoint and ServerEndpoint defined in the JSR 356. * All the scanned classes will be passed to the module. */ public class WebSocketPlugin extends AbstractSeedPlugin implements WebProvider { private final boolean webSocketPresent = Classes.optional("javax.websocket.server.ServerEndpoint").isPresent(); private final Set<Class<?>> serverEndpointClasses = new HashSet<>(); private final Set<Class<?>> clientEndpointClasses = new HashSet<>(); private final Set<Class<? extends ServerEndpointConfig.Configurator>> serverConfiguratorClasses = new HashSet<>(); private final HashSet<Class<? extends ClientEndpointConfig.Configurator>> clientConfiguratorClasses = new HashSet<>(); private ServletContext servletContext; @Override public String name() { return "websocket"; } @Override public void setup(SeedRuntime seedRuntime) { servletContext = seedRuntime.contextAs(ServletContext.class); } @Override public Collection<ClasspathScanRequest> classpathScanRequests() { if (isEnabled()) { return classpathScanRequestBuilder().annotationType(ServerEndpoint.class).annotationType(ClientEndpoint.class).build(); } else { return super.classpathScanRequests(); } } @Override public InitState initialize(InitContext initContext) { if (isEnabled()) { for (Class<?> candidate : initContext.scannedClassesByAnnotationClass().get(ServerEndpoint.class)) { serverConfiguratorClasses.add(candidate.getAnnotation(ServerEndpoint.class).configurator()); serverEndpointClasses.add(candidate); } for (Class<?> candidate : initContext.scannedClassesByAnnotationClass().get(ClientEndpoint.class)) { clientConfiguratorClasses.add(candidate.getAnnotation(ClientEndpoint.class).configurator()); clientEndpointClasses.add(candidate); } } return InitState.INITIALIZED; } @Override public Object nativeUnitModule() { if (isEnabled()) { return new WebSocketModule(serverEndpointClasses, serverConfiguratorClasses, clientEndpointClasses, clientConfiguratorClasses); } else { return super.nativeUnitModule(); } } @Override public List<ServletDefinition> servlets() { return null; } @Override public List<FilterDefinition> filters() { return null; } @Override public List<ListenerDefinition> listeners() { if (isEnabled()) { return Lists.newArrayList(new ListenerDefinition(WebSocketServletContextListener.class)); } else { return null; } } private boolean isEnabled() { return webSocketPresent && servletContext != null; } }