/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.xml.ws.api.pipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceException;
import com.sun.istack.NotNull;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.pipe.EngineTest.InlineExecutor;
import com.sun.xml.ws.api.pipe.EngineTest.SimpleCompletionCallback;
import com.sun.xml.ws.api.pipe.EngineTest.TestTube;
import com.sun.xml.ws.api.pipe.EngineTest.TubeCall;
import com.sun.xml.ws.api.pipe.EngineTest.TubeCallType;
import com.sun.xml.ws.api.pipe.Fiber.CompletionCallback;
import com.sun.xml.ws.api.pipe.Fiber.Listener;
import com.sun.xml.ws.api.pipe.helper.AbstractFilterTubeImpl;
import com.sun.xml.ws.api.server.Container;
import com.sun.xml.ws.api.server.ContainerResolver;
import junit.framework.TestCase;
public class FiberTest extends TestCase {
private Engine engine = null;
private Engine threadPoolEngine = null;
private Container testContainer = null;
private SimpleInlineExecutor executor = null;
public void setUp() {
testContainer = new Container() {};
String id = "engine1";
executor = new SimpleInlineExecutor();
engine = new Engine(id, testContainer, executor);
threadPoolEngine = new Engine(id, testContainer);
}
private static class SimpleInlineExecutor extends InlineExecutor {
private ThreadLocal<Boolean> isInExecutor = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
@Override
public void execute(Runnable command) {
isInExecutor.set(Boolean.TRUE);
try {
super.execute(command);
} finally {
isInExecutor.set(Boolean.FALSE);
}
}
public Boolean isInExecutor() {
return isInExecutor.get();
}
}
@SuppressWarnings("deprecation")
private static class TestListener implements Listener {
@Override
public void fiberSuspended(Fiber fiber) {
}
@Override
public void fiberResumed(Fiber fiber) {
}
}
@SuppressWarnings("deprecation")
public void testAddRemoveListener() {
Fiber fiber = engine.createFiber();
Listener testListener = new TestListener();
List<Listener> listeners = fiber.getCurrentListeners();
assertNotNull(listeners);
assertTrue(listeners.isEmpty());
fiber.addListener(testListener);
listeners = fiber.getCurrentListeners();
assertNotNull(listeners);
assertEquals(1, listeners.size());
assertTrue(listeners.contains(testListener));
Listener testListener2 = new TestListener();
fiber.addListener(testListener2);
listeners = fiber.getCurrentListeners();
assertNotNull(listeners);
assertEquals(2, listeners.size());
assertTrue(listeners.contains(testListener2));
fiber.removeListener(testListener);
listeners = fiber.getCurrentListeners();
assertNotNull(listeners);
assertEquals(1, listeners.size());
assertTrue(listeners.contains(testListener2));
}
public void testStartTubePacketCompletionCallback() {
final Holder<Boolean> isInExecutor = new Holder<Boolean>(Boolean.FALSE);
TestTube testTube = new TestTube() {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
isInExecutor.value = executor.isInExecutor();
return super.processRequest(request);
}
};
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(testTube, request, callback);
assertEquals(request, callback.response);
assertNull(callback.error);
List<TubeCall> calls = testTube.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
assertTrue(isInExecutor.value);
}
public void testStartTubePacketCompletionCallbackBoolean() {
final Holder<Boolean> isInExecutor = new Holder<Boolean>(Boolean.FALSE);
TestTube testTube = new TestTube() {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
isInExecutor.value = executor.isInExecutor();
return super.processRequest(request);
}
};
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(testTube, request, callback, true);
assertEquals(request, callback.response);
assertNull(callback.error);
List<TubeCall> calls = testTube.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
assertFalse(isInExecutor.value);
}
//////////////////////////////
// NextAction / Flow-controlling tests
static class FilterTestTube extends AbstractFilterTubeImpl {
private String tubeName = null;
private List<TubeCall> calls = new ArrayList<TubeCall>();
public FilterTestTube(Tube next) {
super(next);
}
public FilterTestTube(FilterTestTube that, TubeCloner cloner) {
super(that, cloner);
}
public List<TubeCall> getCalls() { return calls; }
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
Container c = ContainerResolver.getDefault().getContainer();
calls.add(new TubeCall(TubeCallType.REQUEST, request, c));
return doInvoke(next, request);
}
@Override
@NotNull
public NextAction processResponse(@NotNull Packet response) {
Container c = ContainerResolver.getDefault().getContainer();
calls.add(new TubeCall(TubeCallType.RESPONSE, response, c));
return doReturnWith(response);
}
@Override
@NotNull
public NextAction processException(@NotNull Throwable t) {
Packet packet = Fiber.current().getPacket();
Container c = ContainerResolver.getDefault().getContainer();
calls.add(new TubeCall(TubeCallType.EXCEPTION, packet, c));
return doThrow(t);
}
@Override
public void preDestroy() {
}
@Override
public FilterTestTube copy(TubeCloner cloner) {
return new FilterTestTube(this, cloner);
}
public void setName(String tubeName) {
this.tubeName = tubeName;
}
//Useful for debugging
public String toString() {
return tubeName;
}
}
public void testNextActionInvoke() {
TestTube tubeC = new TestTube();
FilterTestTube tubeB = new FilterTestTube(tubeC);
FilterTestTube tubeA = new FilterTestTube(tubeB);
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback, true);
assertEquals(request, callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
public void testNextActionInvokeAndForget() {
TestTube tubeC = new TestTube();
FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doInvokeAndForget(next, request);
}
};
FilterTestTube tubeA = new FilterTestTube(tubeB);
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback, true);
assertEquals(request, callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
public void testNextActionReturn() {
TestTube tubeC = new TestTube();
FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doReturnWith(request);
}
};
FilterTestTube tubeA = new FilterTestTube(tubeB);
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback, true);
assertEquals(request, callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
public void testNextActionThrow() {
TestTube tubeC = new TestTube() {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
throw new RuntimeException();
}
};
FilterTestTube tubeB = new FilterTestTube(tubeC);
FilterTestTube tubeA = new FilterTestTube(tubeB);
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback, true);
assertNull(callback.response);
assertTrue(callback.error instanceof RuntimeException);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.EXCEPTION, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.EXCEPTION, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
public void testNextActionAbortResponse() {
TestTube tubeC = new TestTube() {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
NextAction na = new NextAction();
na.abortResponse(request);
return na;
}
};
FilterTestTube tubeB = new FilterTestTube(tubeC);
FilterTestTube tubeA = new FilterTestTube(tubeB);
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback, true);
assertEquals(request, callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
public void testNextActionThrowAbortResponse() {
TestTube tubeC = new TestTube() {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
NextAction na = new NextAction();
na.throwExceptionAbortResponse(new RuntimeException());
return na;
}
};
FilterTestTube tubeB = new FilterTestTube(tubeC);
FilterTestTube tubeA = new FilterTestTube(tubeB);
Packet request = new Packet();
SimpleCompletionCallback callback = new SimpleCompletionCallback();
Fiber fiber = engine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback, true);
assertNull(callback.response);
assertTrue(callback.error instanceof RuntimeException);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
//////////////////////////////
// Suspend / resume tests
public void testSuspendNextRunnableResume() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doSuspend(next, new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
};
final FilterTestTube tubeA = new FilterTestTube(tubeB);
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
fiber.resume(request);
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(request, callback.response);
assertNull(callback.error);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
public void testSuspendRunnableResume() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doSuspend(new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
};
final FilterTestTube tubeA = new FilterTestTube(tubeB);
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
fiber.resume(request);
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(request, callback.response);
assertNull(callback.error);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
public void testSuspendNextRunnableResumeThrowable() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doSuspend(next, new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
};
final FilterTestTube tubeA = new FilterTestTube(tubeB);
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
fiber.resume(new RuntimeException());
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertNull(callback.response);
assertTrue(callback.error instanceof RuntimeException);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.EXCEPTION, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.EXCEPTION, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
public void testSuspendNextRunnableResumeThrowablePacket() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doSuspend(next, new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
};
final FilterTestTube tubeA = new FilterTestTube(tubeB);
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
Packet secondPacket = new Packet();
fiber.resume(new RuntimeException(), secondPacket);
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertNull(callback.response);
assertTrue(callback.error instanceof RuntimeException);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.EXCEPTION, secondCall.callType);
assertEquals(testContainer, secondCall.container);
assertEquals(secondPacket, secondCall.packet);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.EXCEPTION, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
public void testSuspendNextRunnableResumeAndReturn() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doSuspend(next, new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
};
final FilterTestTube tubeA = new FilterTestTube(tubeB);
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
fiber.resumeAndReturn(request, false);
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(request, callback.response);
assertNull(callback.error);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
public void testCancel() throws InterruptedException {
final Semaphore atResponse = new Semaphore(0);
final Semaphore mayProceed = new Semaphore(0);
TestTube tubeC = new TestTube();
FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processResponse(@NotNull Packet response) {
try {
atResponse.release();
mayProceed.acquire();
} catch (InterruptedException e) {
throw new WebServiceException(e);
}
return super.processResponse(response);
}
};
final FilterTestTube tubeA = new FilterTestTube(tubeB);
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback();
final Fiber fiber = engine.createFiber();
assertNotNull(fiber);
Thread testThread = new Thread(new Runnable() {
@Override
public void run() {
fiber.start(tubeA, request, callback, true);
}
});
testThread.start();
if (!atResponse.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
fiber.cancel(false);
mayProceed.release();
testThread.join(3 * 60 * 1000);
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
}
private static class TestFiberContextSwitchInterceptor implements FiberContextSwitchInterceptor {
private String name = null;
public TestFiberContextSwitchInterceptor(String name) {
this.name = name;
}
public String toString() {
return name;
}
private int callCount = 0;
public int getCallCount() { return callCount; }
@Override
public <R, P> R execute(Fiber f, P p, Work<R, P> work) {
callCount++;
return work.execute(p);
}
}
public void testAddInterceptorDuringSuspendResume() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
return doSuspend(new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
};
tubeB.setName("tubeB");
final FilterTestTube tubeA = new FilterTestTube(tubeB);
tubeA.setName("tubeA");
final Packet request = new Packet();
final SimpleCompletionCallback callback = new SimpleCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
TestFiberContextSwitchInterceptor interceptor1 = new TestFiberContextSwitchInterceptor("interceptor1");
fiber.addInterceptor(interceptor1);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertEquals(1, interceptor1.getCallCount());
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
TestFiberContextSwitchInterceptor interceptor2 = new TestFiberContextSwitchInterceptor("interceptor2");
fiber.addInterceptor(interceptor2);
fiber.resume(request);
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(2, interceptor1.getCallCount());
assertEquals(1, interceptor2.getCallCount());
assertEquals(request, callback.response);
assertNull(callback.error);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
private static final Map<String,Integer> fiberNameToThreadLocalValueMap = new ConcurrentHashMap<String,Integer>();
private static final Integer retainMeInteger = new Integer(1001);
private static class MyFiberContextSwitchInterceptor implements FiberContextSwitchInterceptor {
private String name = null;
public MyFiberContextSwitchInterceptor(String name) {
this.name = name;
}
public String toString() {
return name;
}
private int callCount = 0;
public int getCallCount() { return callCount; }
@Override
public <R, P> R execute(Fiber f, P p, Work<R, P> work) {
callCount++;
Integer threadLocalValue = fiberNameToThreadLocalValueMap.get(f.toString());
//Set thread-local on the current thread when Fiber is switching context
//so that it is available on the thread during further processing
ThreadLocalHelper.set(threadLocalValue);
try {
return work.execute(p);
} finally {
//When current thread goes back to the thread pool, clean it of our thread-local
ThreadLocalHelper.unset();
}
}
}
static class MyCompletionCallback implements CompletionCallback {
public Packet response = null;
public Throwable error = null;
private String fiberName = null;
public void setFiberName(String name) {
this.fiberName = name;
}
@Override
public void onCompletion(@NotNull Packet response) {
this.response = response;
}
@Override
public void onCompletion(@NotNull Throwable error) {
this.error = error;
}
}
public void testThreadLocalPropagationWithFiberContextSwitch() throws InterruptedException {
final Semaphore atSuspend = new Semaphore(0);
final Semaphore checkCompleted = new Semaphore(0);
final Semaphore atEnd = new Semaphore(0);
final TestTube tubeC = new TestTube();
final FilterTestTube tubeB = new FilterTestTube(tubeC) {
@Override
@NotNull
public NextAction processRequest(@NotNull Packet request) {
super.processRequest(request);
//Before suspend, make sure thread-local is available thanks to MyFiberContextSwitchInterceptor.execute
Integer threadLocalInteger = ThreadLocalHelper.get();
assertNotNull(threadLocalInteger);
assertEquals(retainMeInteger, threadLocalInteger);
return doSuspend(new Runnable() {
@Override
public void run() {
atSuspend.release();
try {
checkCompleted.acquire();
} catch (InterruptedException e) {
}
}
});
}
@Override
@NotNull
public NextAction processResponse(@NotNull Packet response) {
super.processResponse(response);
//After resume, make sure thread-local is available thanks to MyFiberContextSwitchInterceptor.execute
Integer threadLocalInteger = ThreadLocalHelper.get();
assertNotNull(threadLocalInteger);
assertEquals(retainMeInteger, threadLocalInteger);
return doReturnWith(response);
}
};
tubeB.setName("testThreadLocalPropagationWithFiberContextSwitch.tubeB");
final FilterTestTube tubeA = new FilterTestTube(tubeB);
tubeA.setName("testThreadLocalPropagationWithFiberContextSwitch.tubeA");
final Packet request = new Packet();
final MyCompletionCallback callback = new MyCompletionCallback() {
@Override
public void onCompletion(@NotNull Packet response) {
super.onCompletion(response);
if (super.fiberName != null) fiberNameToThreadLocalValueMap.remove(super.fiberName);
atEnd.release();
}
@Override
public void onCompletion(@NotNull Throwable error) {
super.onCompletion(error);
if (super.fiberName != null) fiberNameToThreadLocalValueMap.remove(super.fiberName);
atEnd.release();
}
};
final Fiber fiber = threadPoolEngine.createFiber();
assertNotNull(fiber);
//Put away some value (say, Transaction context gotten from the thread that is going to invoke fiber.start) before fiber.start
//Post fiber.start, processing thread comes from a thread pool, no guarantee of same thread in force
//This entry will be cleaned up when SimpleCompletionCallback callback method is called at last
fiberNameToThreadLocalValueMap.put(fiber.toString(), retainMeInteger);
//callback has to remember Fiber name so that it can remove the entry from fiberNameToThreadLocalValueMap having Fiber name as the key
callback.setFiberName(fiber.toString());
MyFiberContextSwitchInterceptor interceptor1 =
new MyFiberContextSwitchInterceptor("testThreadLocalPropagationWithFiberContextSwitch.interceptor1");
fiber.addInterceptor(interceptor1);
fiber.start(tubeA, request, callback);
if (!atSuspend.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
assertEquals(0, atEnd.availablePermits()); // ensure test thread really blocked
// thread is suspended
assertEquals(1, interceptor1.getCallCount());
assertNull(callback.response);
assertNull(callback.error);
List<TubeCall> calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
TubeCall firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(1, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
checkCompleted.release();
fiber.resume(request);
if (!atEnd.tryAcquire(3, TimeUnit.MINUTES))
fail("timeout");
//Two context switches, 1) when fiber.start was done and 2) when fiber was suspended
assertEquals(2, interceptor1.getCallCount());
assertEquals(request, callback.response);
assertNull(callback.error);
calls = tubeA.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
TubeCall secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeB.getCalls();
assertNotNull(calls);
assertEquals(2, calls.size());
firstCall = calls.get(0);
assertNotNull(firstCall);
assertEquals(TubeCallType.REQUEST, firstCall.callType);
assertEquals(testContainer, firstCall.container);
secondCall = calls.get(1);
assertNotNull(secondCall);
assertEquals(TubeCallType.RESPONSE, secondCall.callType);
assertEquals(testContainer, secondCall.container);
calls = tubeC.getCalls();
assertNotNull(calls);
assertEquals(0, calls.size());
}
}