/*
* Copyright (c) 2008-2017 the original author or authors.
*
* 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 org.cometd.annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.client.ClientSession;
import org.cometd.client.BayeuxClient;
import org.cometd.client.transport.ClientTransport;
import org.cometd.client.transport.LongPollingTransport;
import org.cometd.common.JettyJSONContextClient;
import org.cometd.server.JettyJSONContextServer;
import org.eclipse.jetty.util.ajax.JSON;
import org.junit.Assert;
import org.junit.Test;
public class BayeuxClientRemoteCallTest extends AbstractClientServerTest {
@Test
public void testRemoteCallWithResult() throws Exception {
ServerAnnotationProcessor processor = new ServerAnnotationProcessor(bayeux);
final String response = "response";
Assert.assertTrue(processor.process(new RemoteCallWithResultService(response)));
BayeuxClient client = newBayeuxClient();
client.handshake();
Assert.assertTrue(client.waitFor(5000, BayeuxClient.State.CONNECTED));
final CountDownLatch latch = new CountDownLatch(1);
client.remoteCall(RemoteCallWithResultService.TARGET, "request", new ClientSession.MessageListener() {
@Override
public void onMessage(Message message) {
Assert.assertTrue(message.isSuccessful());
Assert.assertEquals(response, message.getData());
latch.countDown();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
disconnectBayeuxClient(client);
}
@Service
public static class RemoteCallWithResultService {
public static final String TARGET = "/result";
private final String response;
public RemoteCallWithResultService(String response) {
this.response = response;
}
@RemoteCall(TARGET)
public void service(RemoteCall.Caller caller, Object data) {
caller.result(response);
}
}
@Test
public void testRemoteCallTimeout() throws Exception {
long timeout = 1000;
ServerAnnotationProcessor processor = new ServerAnnotationProcessor(bayeux);
Assert.assertTrue(processor.process(new RemoteCallWithTimeoutService(2 * timeout)));
BayeuxClient client = newBayeuxClient();
client.setOption(ClientTransport.MAX_NETWORK_DELAY_OPTION, timeout);
client.handshake();
Assert.assertTrue(client.waitFor(5000, BayeuxClient.State.CONNECTED));
final CountDownLatch latch = new CountDownLatch(1);
client.remoteCall(RemoteCallWithTimeoutService.TARGET, "", new ClientSession.MessageListener() {
@Override
public void onMessage(Message message) {
Assert.assertFalse(message.isSuccessful());
latch.countDown();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
disconnectBayeuxClient(client);
}
@Service
public static class RemoteCallWithTimeoutService {
public static final String TARGET = "/timeout";
private final long timeout;
public RemoteCallWithTimeoutService(long timeout) {
this.timeout = timeout;
}
@RemoteCall(TARGET)
public void service(RemoteCall.Caller caller, Object data) {
try {
Thread.sleep(timeout);
caller.result("ok");
} catch (Exception x) {
caller.failure(x.toString());
}
}
}
@Test
public void testRemoteCallWithFailure() throws Exception {
ServerAnnotationProcessor processor = new ServerAnnotationProcessor(bayeux);
final String failure = "failure";
Assert.assertTrue(processor.process(new RemoteCallWithFailureService(failure)));
BayeuxClient client = newBayeuxClient();
client.handshake();
Assert.assertTrue(client.waitFor(5000, BayeuxClient.State.CONNECTED));
final CountDownLatch latch = new CountDownLatch(1);
client.remoteCall(RemoteCallWithFailureService.TARGET, "request", new ClientSession.MessageListener() {
@Override
public void onMessage(Message message) {
Assert.assertFalse(message.isSuccessful());
Assert.assertEquals(failure, message.getData());
latch.countDown();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
disconnectBayeuxClient(client);
}
@Service
public static class RemoteCallWithFailureService {
public static final String TARGET = "/failure";
private final String failure;
public RemoteCallWithFailureService(String failure) {
this.failure = failure;
}
@RemoteCall(TARGET)
public void service(RemoteCall.Caller caller, Object data) {
caller.failure(failure);
}
}
@Test
public void testRemoteCallWithCustomData() throws Exception {
JettyJSONContextServer jsonContextServer = (JettyJSONContextServer)bayeux.getJSONContext();
jsonContextServer.getJSON().addConvertor(Custom.class, new CustomConvertor());
final String request = "request";
final String response = "response";
ServerAnnotationProcessor processor = new ServerAnnotationProcessor(bayeux);
boolean processed = processor.process(new RemoteCallWithCustomDataService(request, response));
Assert.assertTrue(processed);
Map<String, Object> options = new HashMap<>();
JettyJSONContextClient jsonContextClient = new JettyJSONContextClient();
jsonContextClient.getJSON().addConvertor(Custom.class, new CustomConvertor());
options.put(ClientTransport.JSON_CONTEXT_OPTION, jsonContextClient);
BayeuxClient client = new BayeuxClient(cometdURL, new LongPollingTransport(options, httpClient));
client.handshake();
Assert.assertTrue(client.waitFor(5000, BayeuxClient.State.CONNECTED));
final CountDownLatch latch = new CountDownLatch(1);
client.remoteCall(RemoteCallWithCustomDataService.TARGET, new Custom(request), new ClientSession.MessageListener() {
@Override
public void onMessage(Message message) {
Assert.assertTrue(message.isSuccessful());
Custom data = (Custom)message.getData();
Assert.assertEquals(response, data.payload);
latch.countDown();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
disconnectBayeuxClient(client);
}
@Service
public static class RemoteCallWithCustomDataService {
public static final String TARGET = "/custom_data";
private String request;
private String response;
public RemoteCallWithCustomDataService(String request, String response) {
this.request = request;
this.response = response;
}
@RemoteCall(TARGET)
public void service(RemoteCall.Caller caller, Custom custom) {
if (request.equals(custom.payload)) {
caller.result(new Custom(response));
} else {
caller.failure("failed");
}
}
}
public static class Custom {
public final String payload;
public Custom(String payload) {
this.payload = payload;
}
}
private class CustomConvertor implements JSON.Convertor {
@Override
public void toJSON(Object obj, JSON.Output out) {
Custom custom = (Custom)obj;
out.addClass(custom.getClass());
out.add("payload", custom.payload);
}
@Override
public Object fromJSON(Map object) {
return new Custom((String)object.get("payload"));
}
}
}