Websocket + Vraptor

13 respostas
bglbruno

Olá pessoal, bom dia!

Gostaria de saber se já implementaram algo com websockets + vraptor.

A minha necessidade é fazer um server websocket, que quando um objeto é inserido/alterado/removido na base de dados via hibernate, quero que o server emita uma mensagem broadcast e tal, notificando os usuários.

Alguém já implementou algo assim?
Pode me dar uma ajuda?

Já vi como implementar no Tomcat 7, mas ele usa uma Servet, e pelo que andei lendo aqui no Guj, terei problemas porque o VRaptor usa um Filter.

Forte abraço, valeu!

13 Respostas

Lucas_Cavalcanti

Pois eh… uma tentativa que talvez funcione é pegar o filtro do VRaptor:

e trocar o implements Filter por extends HttpServlet…

o que vai dar pau é a falta do FilterChain… mas tente usar sem por enquanto e ver no que rola.

Daí eu te ajudo a resolver os problemas que aparecerem =)

bglbruno

Certo Lucas, eu vi as dicas que você deu num outro tópico sobre isso
E fiz dessa maneira. Eu não conheço muito sobre servlets

@WebServlet
public class VRaptorServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	
	private ContainerProvider provider;
	private ServletContext servletContext;

	private StaticContentHandler staticHandler;

	private static final Logger logger = LoggerFactory.getLogger(VRaptor.class);

	public void destroy() {
		provider.stop();
		provider = null;
		servletContext = null;
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) {
			throw new ServletException(
					"VRaptor must be run inside a Servlet environment. Portlets and others aren't supported.");
		}

		final HttpServletRequest baseRequest = (HttpServletRequest) req;
		final HttpServletResponse baseResponse = (HttpServletResponse) res;

		if (staticHandler.requestingStaticFile(baseRequest)) {
			staticHandler.deferProcessingToContainer(null, baseRequest, baseResponse);
		} else {
			logger.debug("VRaptor received a new request");
			logger.trace("Request: {}", req);

			VRaptorRequest mutableRequest = new VRaptorRequest(baseRequest);
			VRaptorResponse mutableResponse = new VRaptorResponse(baseResponse);

			final RequestInfo request = new RequestInfo(servletContext, null, mutableRequest, mutableResponse);
			provider.provideForRequest(request, new Execution<Object>() {
				public Object insideRequest(Container container) {
					container.instanceFor(EncodingHandler.class).setEncoding(baseRequest, baseResponse);
					container.instanceFor(RequestExecution.class).execute();
					return null;
				}
			});
			logger.debug("VRaptor ended the request");
		}
		
		super.service(req, res);
	}
	
	@Override
	public void init(ServletConfig cfg) throws ServletException {
		servletContext = cfg.getServletContext();
		BasicConfiguration config = new BasicConfiguration(servletContext);
		init(config.getProvider());
		logger.info("VRaptor 3.4.1-SNAPSHOT successfuly initialized");
	}

	void init(ContainerProvider provider) {
		this.provider = provider;
		this.provider.start(servletContext);
		this.staticHandler = provider.getContainer().instanceFor(StaticContentHandler.class);
	}

}

Eu só não consegui compreender ainda, como essa servlet passaria a requisição via ws pra a classe servidor de websocket.
Pois esse seria o papel dela, correto? ou estou enganado?

Outra dúvida, no método service, preciso chamar super.service(req, res) no final?

Lucas_Cavalcanti

não era só fazer algo como request.getAsyncContext() no controller que vc quiser brincar de fazer WebSocket?

bglbruno

Não sei cara rs sério, não manjo nada de servlet.

Como seria o cenário?
Eu teria um controller que seria meu server websocket e essa servlet faria o mesmo papel do filtro do vraptor.
Ou essa servlet adaptada já seria o meu server?

To com muita vontade de implementar isso e contribuir com o projeto vraptor, mas não sei muito como seria.
Não sei muito bem como prosseguir.
Se puder me passar algo ou me ajudar, seria bom.

Lucas_Cavalcanti

o servlet vai funcionar como se fosse o filter do vraptor e o controller vai ser o servidor do web socket.

Nunca usei isso na prática, então não sei se vou conseguir te ajudar mto… mas procura sobre o request asyncContext

bglbruno

Saquei.

Está dando esse erro quando tento acessar a raiz da aplicação

SEVERE: Servlet.service() for servlet VRaptorServlet threw exception
java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.startAsync(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)Ljavax/servlet/AsyncContext;
	at br.com.nextrans.myone.servlet.VRaptorServlet.service(VRaptorServlet.java:81)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:291)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:722)

Essa é a implementação do método service

@Override
	protected void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) {
			throw new ServletException(
					"VRaptor must be run inside a Servlet environment. Portlets and others aren't supported.");
		}

		final HttpServletRequest baseRequest = (HttpServletRequest) req;
		final HttpServletResponse baseResponse = (HttpServletResponse) res;

		if (!staticHandler.requestingStaticFile(baseRequest)) {
			logger.debug("VRaptor received a new request");
			logger.trace("Request: {}", req);

			
			VRaptorRequest mutableRequest = new VRaptorRequest(baseRequest);
			VRaptorResponse mutableResponse = new VRaptorResponse(baseResponse);

			final RequestInfo request = new RequestInfo(servletContext, null, mutableRequest, mutableResponse);
			provider.provideForRequest(request, new Execution<Object>() {
				public Object insideRequest(Container container) {
					container.instanceFor(EncodingHandler.class).setEncoding(baseRequest, baseResponse);
					container.instanceFor(RequestExecution.class).execute();
					return null;
				}
			});
			AsyncContext aCtx = req.startAsync(req, res); // não sei onde chamar esse método
			logger.debug("VRaptor ended the request");
		}
		
	}

Alguma ideia?

Lucas_Cavalcanti

vc deve estar ou deployando num servidor que não é servlet 3.0 ou vc tá com a api do servlet 2.5 no classpath.

bglbruno

É isso mesmo Lucas. Viajei, tava deployando o projeto no tomcat 6
Só não estou conseguindo subir o tomcat 7 no eclipse.
Fica dando essa mensagem: “[…] bootstrap.jar which is referenced by the classpath, does not exist.” Sendo que o arquivo existe.
Já tentei reinstalar o server no eclipse, mexer no User Entries, e nada.

Já teve esse problema?

Lucas_Cavalcanti

vc tá usando o adapter do tomcat 7? tipo na hora de criar o servidor vc selecionou a versão 7?

bglbruno

Sim, isso mesmo.
new Server -> Selecionei a versão, diretório de instalação, etc.

bglbruno

Lucas, consegui instalar o server corretamente.

Agora quando tento acessar um controller pela url, não é mostrado nada na tela.

Meu método service está da mesma forma:

@Override
	protected void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) {
			throw new ServletException(
					"VRaptor must be run inside a Servlet environment. Portlets and others aren't supported.");
		}

		final HttpServletRequest baseRequest = (HttpServletRequest) req;
		final HttpServletResponse baseResponse = (HttpServletResponse) res;

		if (!staticHandler.requestingStaticFile(baseRequest)) {
			logger.debug("VRaptor received a new request");
			logger.trace("Request: {}", req);

			
			VRaptorRequest mutableRequest = new VRaptorRequest(baseRequest);
			VRaptorResponse mutableResponse = new VRaptorResponse(baseResponse);

			final RequestInfo request = new RequestInfo(servletContext, null, mutableRequest, mutableResponse);
			provider.provideForRequest(request, new Execution<Object>() {
				public Object insideRequest(Container container) {
					container.instanceFor(EncodingHandler.class).setEncoding(baseRequest, baseResponse);
					container.instanceFor(RequestExecution.class).execute();
					return null;
				}
			});
			AsyncContext aCtx = req.startAsync(req, res); // não sei o que fazer com isso
			logger.debug("VRaptor ended the request");
		}
		
	}
bglbruno

Criei esse repositório https://github.com/bglbruno/vraptor-websocket

Lucas_Cavalcanti

o startAsync vc faz só no controller, e só qdo vc quiser que a requisição seja web-socket.

Vc chegou a ligar o log de debug? está logando alguma coisa durante a request?

Criado 9 de maio de 2013
Ultima resposta 13 de mai. de 2013
Respostas 13
Participantes 2