Skip to content

Commit

Permalink
Merge pull request #2749 from michalszynkiewicz/ws-encoders-registration
Browse files Browse the repository at this point in the history
register websocket encoders and decoders for reflection
  • Loading branch information
stuartwdouglas authored Jun 11, 2019
2 parents 4ae06ce + 0be3024 commit 4a17215
Show file tree
Hide file tree
Showing 10 changed files with 426 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@
import java.util.Set;

import javax.websocket.ClientEndpoint;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.ContainerProvider;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpoint;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Type;

import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
Expand All @@ -41,11 +45,13 @@
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.ServiceStartBuildItem;
import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.substrate.ServiceProviderBuildItem;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.quarkus.undertow.deployment.ServletContextAttributeBuildItem;
import io.quarkus.undertow.deployment.UndertowBuildItem;
import io.quarkus.undertow.websockets.runtime.UndertowWebsocketTemplate;
import io.undertow.websockets.jsr.JsrWebSocketFilter;
import io.undertow.websockets.jsr.UndertowContainerProvider;
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;

public class UndertowWebsocketProcessor {
Expand Down Expand Up @@ -124,17 +130,50 @@ public ServletContextAttributeBuildItem deploy(final CombinedIndexBuildItem inde
new ReflectiveClassBuildItem(true, false, annotated.toArray(new String[annotated.size()])));
reflection.produce(new ReflectiveClassBuildItem(false, false, JsrWebSocketFilter.class.getName()));

registerCodersForReflection(reflection, index.getAnnotations(SERVER_ENDPOINT));
registerCodersForReflection(reflection, index.getAnnotations(CLIENT_ENDPOINT));

reflection.produce(
new ReflectiveClassBuildItem(true, true, ClientEndpointConfig.Configurator.class.getName()));

return new ServletContextAttributeBuildItem(WebSocketDeploymentInfo.ATTRIBUTE_NAME,
template.createDeploymentInfo(annotated, endpoints, config));
}

private void registerCodersForReflection(BuildProducer<ReflectiveClassBuildItem> reflection,
Collection<AnnotationInstance> endpoints) {
for (AnnotationInstance endpoint : endpoints) {
if (endpoint.target() instanceof ClassInfo) {
ClassInfo clazz = (ClassInfo) endpoint.target();
if (!Modifier.isAbstract(clazz.flags())) {
registerForReflection(reflection, endpoint.value("encoders"));
registerForReflection(reflection, endpoint.value("decoders"));
}
}
}
}

private void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflection, AnnotationValue types) {
if (types != null && types.asClassArray() != null) {
for (Type type : types.asClassArray()) {
reflection.produce(new ReflectiveClassBuildItem(true, false, type.name().toString()));
}
}
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
ServiceStartBuildItem setupWorker(UndertowWebsocketTemplate template, UndertowBuildItem undertow) {
template.setupWorker(undertow.getUndertow());
return new ServiceStartBuildItem("Websockets");
}

@BuildStep
ServiceProviderBuildItem registerContainerProviderService() {
return new ServiceProviderBuildItem(ContainerProvider.class.getName(),
UndertowContainerProvider.class.getName());
}

@BuildStep
void beanDefiningAnnotations(BuildProducer<BeanDefiningAnnotationBuildItem> annotations) {
annotations.produce(new BeanDefiningAnnotationBuildItem(SERVER_ENDPOINT));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;

import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

@Path("/ws-client-coding-test")
public class ClientCodingResource {

@GET
public String codeBothWays(@QueryParam("echoServerUri") String echoServerUri) throws IOException, DeploymentException {
ContainerProvider.getWebSocketContainer()
.connectToServer(CodingClient.class, URI.create(echoServerUri));

try {
Dto response = CodingClient.messageQueue.poll(20, TimeUnit.SECONDS);
return response.getContent();
} catch (InterruptedException e) {
CodingClient.close();
return "Failed to get response in time";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;

import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

public class ClientDtoDecoder implements Decoder.TextStream<Dto> {
@Override
public Dto decode(Reader reader) throws IOException {
try (BufferedReader bufferedReader = new BufferedReader(reader)) {
String input = bufferedReader.readLine(); // expecting one line input
Dto result = new Dto();
result.setContent("[decoded]" + input);
return result;
}
}

@Override
public void init(EndpointConfig config) {
}

@Override
public void destroy() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

import java.io.IOException;
import java.io.Writer;

import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;

public class ClientDtoEncoder implements Encoder.TextStream<Dto> {
@Override
public void encode(Dto object, Writer writer) throws IOException {
writer.append("[encoded]" + object.getContent());
}

@Override
public void init(EndpointConfig config) {

}

@Override
public void destroy() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;

import javax.websocket.ClientEndpoint;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

@ClientEndpoint(decoders = ClientDtoDecoder.class, encoders = ClientDtoEncoder.class)
public class CodingClient {
private static List<Session> sessions = Collections.synchronizedList(new ArrayList<>());

static LinkedBlockingDeque<Dto> messageQueue = new LinkedBlockingDeque<>();

@OnOpen
public void onOpen(Session session) {
sessions.add(session);

Dto data = new Dto();
data.setContent("initial data");
session.getAsyncRemote().sendObject(data);
}

@OnMessage
public void onMessage(Dto message) {
messageQueue.add(message);
close();
}

static void close() {
for (Session session : sessions) {
try {
session.close();
} catch (IOException ignored) {
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

public class Dto {
private String content;

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

@Override
public String toString() {
return "Dto{" +
"content='" + content + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/recoder", encoders = ServerDtoEncoder.class, decoders = ServerDtoDecoder.class)
public class RecodingSocket {
@OnMessage
public Dto recode(Dto input) {
Dto result = new Dto();
result.setContent("[recoded]" + input.getContent());
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.quarkus.it.websocket;

import java.io.Reader;

import javax.json.Json;
import javax.json.JsonObject;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;

public class ServerDtoDecoder implements Decoder.TextStream<Dto> {
@Override
public Dto decode(Reader reader) {
JsonObject jsonObject = Json.createReader(reader).readObject();
Dto result = new Dto();
result.setContent(jsonObject.getString("content"));
return result;
}

@Override
public void init(EndpointConfig config) {
}

@Override
public void destroy() {
}
}
Loading

0 comments on commit 4a17215

Please sign in to comment.