/** * Reactive Observe cancellation: Cancel the observe relation by forgetting, * which will trigger a RST. For TCP, {{@link #proactiveCancel()} will be * executed. */ public void reactiveCancel() { Request request = this.request; if (CoAP.isTcpScheme(request.getScheme())) { LOGGER.log(Level.INFO, "Change to cancel the observe {0} proactive over TCP.", request.getTokenString()); proactiveCancel(); } else { // cancel old ongoing request cancel(); } }
@Override public void run() { reregister(); } }, timeout, TimeUnit.MILLISECONDS);
private void prepareReregistration(CoapResponse response, long backoff) { if (!isCanceled()) { long timeout = response.getOptions().getMaxAge() * 1000 + backoff; ScheduledFuture<?> f = scheduler.schedule(new Runnable() { @Override public void run() { reregister(); } }, timeout, TimeUnit.MILLISECONDS); setReregistrationHandle(f); } } }
/** * Proactive Observe cancellation: Cancel the observe relation by sending a * GET with Observe=1. */ public void proactiveCancel() { sendCancelObserve(); // cancel old ongoing request cancel(); }
@Test(expected = IllegalStateException.class) public void testObserveClientReregisterAfterReject() throws Exception { resourceX.setObserveType(Type.NON); resourceX.rejectNextGet(); CoapClient client = new CoapClient(uriX); CountingHandler handler = new CountingHandler(); CoapObserveRelation rel = client.observeAndWait(handler); assertTrue("Not rejected", rel.isCanceled()); rel.reregister(); }
try { Thread.sleep(6*1000); } catch (InterruptedException e) { } System.out.println("---------------\nCancel Observe"); relation1.reactiveCancel(); try { Thread.sleep(6*1000); } catch (InterruptedException e) { } try { Thread.sleep(6*1000); } catch (InterruptedException e) { } System.out.println("---------------\nCancel Observe"); relation2.proactiveCancel(); try { Thread.sleep(2*1000); } catch (InterruptedException e) { } long timeout = relation4.getCurrent().getOptions().getMaxAge(); try { Thread.sleep(6*1000); } catch (InterruptedException e) { } System.out.println("---------------\nReboot Server"); clientStimulus.post("sesame", MediaTypeRegistry.TEXT_PLAIN); try { Thread.sleep((timeout+6)*1000); } catch (InterruptedException e) { } relation4.proactiveCancel(); try { Thread.sleep(2*1000); } catch (InterruptedException e) { } try { Thread.sleep(11*1000); } catch (InterruptedException e) { } System.out.println("---------------\nCancel Observe"); relation13.proactiveCancel(); try { Thread.sleep(6*1000); } catch (InterruptedException e) { } try { Thread.sleep(21*1000); } catch (InterruptedException e) { } System.out.println("---------------\nCancel Observe"); relation14.proactiveCancel(); try { Thread.sleep(6*1000); } catch (InterruptedException e) { }
assertFalse("Response not received", rel.isCanceled()); assertNotNull("Response not received", rel.getCurrent()); assertEquals("\"resX says hi for the 1 time\"", rel.getCurrent().getResponseText()); assertFalse(rel.isCanceled()); assertEquals("\"resX says client for the 2 time\"", rel.getCurrent().getResponseText()); rel.reregister(); assertFalse(rel.isCanceled()); assertFalse(rel.isCanceled()); assertEquals("\"resX says client for the 2 time\"", rel.getCurrent().getResponseText()); assertEquals("\"resX says new client for the 3 time\"", rel.getCurrent().getResponseText()); assertEquals(1, resourceX.getObserverCount());
@Test public void testObserveClient() throws Exception { final AtomicInteger resetCounter = new AtomicInteger(0); server.getEndpoints().get(0).addInterceptor(new ServerMessageInterceptor(resetCounter)); resourceX.setObserveType(Type.NON); int repeat = 3; CoapClient client = new CoapClient(uriX); CountingHandler handler = new CountingHandler(); CoapObserveRelation rel = client.observeAndWait(handler); // onLoad is called asynchronous to returning the response // therefore wait for one onLoad assertTrue(handler.waitForLoadCalls(1, 1000, TimeUnit.MILLISECONDS)); assertFalse("Response not received", rel.isCanceled()); assertNotNull("Response not received", rel.getCurrent()); assertEquals("\"resX says hi for the 1 time\"", rel.getCurrent().getResponseText()); rel.reactiveCancel(); System.out.println(uriX + " reactive canceled"); for (int i = 0; i < repeat; ++i) { resourceX.changed("client"); Thread.sleep(50); } // still only one notification (the response) is received assertFalse(handler.waitForLoadCalls(2, 1000, TimeUnit.MILLISECONDS)); assertEquals(repeat, resetCounter.get()); // repeat RST received // no RST delivered (interceptor) assertEquals(1, resourceX.getObserverCount()); }
if (countDown == 1) { LOGGER.log(Level.FINE, "Client proactively cancels observe relation"); relation.proactiveCancel(); relation.reactiveCancel();
Assert.assertFalse(obs1.isCanceled()); obs1.reactiveCancel(); Thread.sleep(100); resource.changed();
@Override public void onLoad(CoapResponse response) { if (response.getCode() == ResponseCode.NOT_FOUND) { CoapObserveRelation cor; synchronized (relationStorage) { if (!testdump.get()) { testdump.set(true); System.out.println("Used Memory: " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 + "kb (" + relationStorage.size() + " clients)."); } if ((cor = relationStorage.get(new InetSocketAddress(response.advanced().getSource(), response.advanced().getSourcePort()))) != null) { cor.reactiveCancel(); relationStorage.remove(new InetSocketAddress(response.advanced().getSource(), response.advanced().getSourcePort())); cor = null; } if (relationStorage.size() == 0) testdump.set(false); } return; } } @Override public void onError() { }
private CoapObserveRelation observeAndWait(Request request, CoapHandler handler) { if (request.getOptions().hasObserve()) { Endpoint outEndpoint = getEffectiveEndpoint(request); CoapObserveRelation relation = new CoapObserveRelation(request, outEndpoint); request.addMessageObserver(new ObserveMessageObserverImpl(handler, relation)); CoapResponse response = synchronous(request, outEndpoint); if (response == null || !response.advanced().getOptions().hasObserve()) { relation.setCanceled(true); } return relation; } else { throw new IllegalArgumentException("please make sure that the request has observe option set."); } }
throw new IllegalStateException("observe not supported by CoAP server!"); if (isCanceled()) { throw new IllegalStateException("observe already canceled!");
private CoapObserveRelation observe(Request request, CoapHandler handler) { if (request.getOptions().hasObserve()) { Endpoint outEndpoint = getEffectiveEndpoint(request); CoapObserveRelation relation = new CoapObserveRelation(request, outEndpoint); request.addMessageObserver(new ObserveMessageObserverImpl(handler, relation)); send(request, outEndpoint); return relation; } else { throw new IllegalArgumentException("please make sure that the request has observe option set."); } }
/** * Checks if the specified response truly is a new notification and if, * invokes the handler's method or drops the notification otherwise. * Ordering and delivery must be done synchronized here to deal with * race conditions in the stack. */ @Override protected void deliver(CoapResponse response) { synchronized (relation) { if (relation.onResponse(response)) { handler.onLoad(response); } else { LOGGER.finer("Dropping old notification: "+response.advanced()); return; } } }
/** * Sets the current response or notification. * * Use {@link #orderer} to filter deprecated responses. * * @param response the response or notification * @return {@code true}, response is accepted by {@link #orderer}, * {@code false} otherwise. */ protected boolean onResponse(CoapResponse response) { if (null != response && orderer.isNew(response.advanced())) { current = response; prepareReregistration(response, 2000); registrationPending.set(false); return true; } else { return false; } }
/** * Reactive Observe cancellation: Cancel the observe relation by forgetting, * which will trigger a RST. For TCP, {{@link #proactiveCancel()} will be * executed. */ public void reactiveCancel() { // cancel old ongoing request cancel(); }
@Test(expected = IllegalStateException.class) public void testObserveClientReregisterAfterTimeout() throws Exception { resourceX.setObserveType(Type.NON); resourceX.delayNextGet(100); CoapClient client = new CoapClient(uriX); long timeout = client.getTimeout(); client.setTimeout(1); CountingHandler handler = new CountingHandler(); CoapObserveRelation rel = client.observeAndWait(handler); assertTrue("No timeout", rel.isCanceled()); client.setTimeout(timeout); rel.reregister(); }
obs1.reactiveCancel(); resource.changed(); Thread.sleep(50);
/** * Proactive Observe cancellation: Cancel the observe relation by sending a * GET with Observe=1. */ public void proactiveCancel() { sendCancelObserve(); // cancel old ongoing request cancel(); }