| /* |
| * Copyright (c) 2010-2012, 2015 Eike Stepper (Berlin, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * David Bonneau - initial API and implementation |
| * Andre Dietisheim - maintenance |
| */ |
| package org.eclipse.net4j.tests.bugzilla; |
| |
| import org.eclipse.net4j.Net4jUtil; |
| import org.eclipse.net4j.connector.IConnector; |
| import org.eclipse.net4j.jvm.JVMUtil; |
| import org.eclipse.net4j.signal.IndicationWithResponse; |
| import org.eclipse.net4j.signal.RequestWithConfirmation; |
| import org.eclipse.net4j.signal.SignalProtocol; |
| import org.eclipse.net4j.signal.SignalReactor; |
| import org.eclipse.net4j.util.IErrorHandler; |
| import org.eclipse.net4j.util.concurrent.Worker; |
| import org.eclipse.net4j.util.container.ContainerUtil; |
| import org.eclipse.net4j.util.container.IManagedContainer; |
| import org.eclipse.net4j.util.factory.ProductCreationException; |
| import org.eclipse.net4j.util.io.ExtendedDataInputStream; |
| import org.eclipse.net4j.util.io.ExtendedDataOutputStream; |
| import org.eclipse.net4j.util.tests.AbstractOMTest; |
| |
| import org.eclipse.spi.net4j.ServerProtocolFactory; |
| |
| import java.nio.BufferUnderflowException; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| /** |
| * @author David Bonneau |
| */ |
| public class Bugzilla_262875_Test extends AbstractOMTest |
| { |
| /** the length of the metadata sent in a buffer: channelID, correlationID */ |
| private static final short BUFFER_METADATA_LENTGH = 10; |
| |
| private IManagedContainer container; |
| |
| private IConnector connector; |
| |
| @Override |
| protected void doSetUp() throws Exception |
| { |
| super.doSetUp(); |
| container = ContainerUtil.createContainer(); |
| Net4jUtil.prepareContainer(container); |
| JVMUtil.prepareContainer(container); |
| container.registerFactory(new TestProtocol.Factory()); |
| container.activate(); |
| |
| JVMUtil.getAcceptor(container, "default"); |
| connector = JVMUtil.getConnector(container, "default"); |
| } |
| |
| @Override |
| protected void doTearDown() throws Exception |
| { |
| connector.close(); |
| container.deactivate(); |
| super.doTearDown(); |
| } |
| |
| /** |
| * Tests if a buffer underflow exception occurs if the data sent in a request exactly matches the capacity of a |
| * buffer. |
| * |
| * @throws Exception |
| * the exception |
| */ |
| public void testGivenDataMatchesBufferLengthThenBufferUnderflowException() throws Exception |
| { |
| final AtomicBoolean failed = new AtomicBoolean(false); |
| final CountDownLatch latch = new CountDownLatch(1); |
| IErrorHandler oldErrorHandler = Worker.setGlobalErrorHandler(new IErrorHandler() |
| { |
| public void handleError(Throwable t) |
| { |
| t.printStackTrace(); |
| if (t instanceof BufferUnderflowException) |
| { |
| failed.set(true); |
| } |
| |
| latch.countDown(); |
| } |
| }); |
| |
| try |
| { |
| TestProtocol protocol = new TestProtocol(); |
| protocol.open(connector); |
| |
| short bufferCapacity = protocol.getBufferProvider().getBufferCapacity(); |
| new TestProtocol.Request(protocol, bufferCapacity - BUFFER_METADATA_LENTGH).send(); |
| |
| latch.await(DEFAULT_TIMEOUT_EXPECTED, TimeUnit.MILLISECONDS); |
| assertEquals(false, failed.get()); |
| } |
| finally |
| { |
| Worker.setGlobalErrorHandler(oldErrorHandler); |
| } |
| } |
| |
| /** |
| * @author David Bonneau |
| */ |
| private static final class TestProtocol extends SignalProtocol<Object> |
| { |
| private static final String NAME = "TEST_PROTOCOL"; |
| |
| private static final short SIGNAL_ID = 10; |
| |
| public TestProtocol() |
| { |
| super(NAME); |
| } |
| |
| @Override |
| protected SignalReactor createSignalReactor(short signalID) |
| { |
| switch (signalID) |
| { |
| case SIGNAL_ID: |
| return new Indication(this); |
| } |
| |
| return super.createSignalReactor(signalID); |
| } |
| |
| /** |
| * @author David Bonneau |
| */ |
| private static final class Request extends RequestWithConfirmation<Boolean> |
| { |
| private int requestNumOfBytes; |
| |
| public Request(SignalProtocol<?> protocol, int requestNumOfBytes) |
| { |
| super(protocol, SIGNAL_ID); |
| this.requestNumOfBytes = requestNumOfBytes; |
| } |
| |
| @Override |
| protected void requesting(ExtendedDataOutputStream out) throws Exception |
| { |
| for (int i = 0; i < requestNumOfBytes; ++i) |
| { |
| out.writeByte(i); |
| } |
| |
| // delay completion |
| Thread.sleep(100); |
| } |
| |
| @Override |
| protected Boolean confirming(ExtendedDataInputStream in) throws Exception |
| { |
| return in.readBoolean(); |
| } |
| } |
| |
| /** |
| * @author David Bonneau |
| */ |
| private static final class Indication extends IndicationWithResponse |
| { |
| public Indication(SignalProtocol<?> protocol) |
| { |
| super(protocol, SIGNAL_ID); |
| } |
| |
| @Override |
| protected void indicating(ExtendedDataInputStream in) throws Exception |
| { |
| System.out.println("indicating"); |
| } |
| |
| @Override |
| protected void responding(ExtendedDataOutputStream out) throws Exception |
| { |
| out.writeBoolean(true); |
| } |
| } |
| |
| /** |
| * @author David Bonneau |
| */ |
| private static final class Factory extends ServerProtocolFactory |
| { |
| public Factory() |
| { |
| super(NAME); |
| } |
| |
| public Object create(String description) throws ProductCreationException |
| { |
| return new TestProtocol(); |
| } |
| } |
| } |
| } |