/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cxf.phase;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.cxf.common.util.SortedArraySet;
import org.apache.cxf.continuations.SuspendedInvocationException;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.InterceptorChain;
import org.apache.cxf.logging.FaultListener;
import org.apache.cxf.message.FaultMode;
import org.apache.cxf.message.Message;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class PhaseInterceptorChainTest extends Assert {
private IMocksControl control;
private PhaseInterceptorChain chain;
private Message message;
@Before
public void setUp() {
control = EasyMock.createNiceControl();
message = control.createMock(Message.class);
Phase phase1 = new Phase("phase1", 1);
Phase phase2 = new Phase("phase2", 2);
Phase phase3 = new Phase("phase3", 3);
SortedSet<Phase> phases = new TreeSet<Phase>();
phases.add(phase1);
phases.add(phase2);
phases.add(phase3);
chain = new PhaseInterceptorChain(phases);
}
@After
public void tearDown() {
control.verify();
}
@Test
public void testState() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
control.replay();
chain.add(p);
assertSame("Initial state is State.EXECUTING",
InterceptorChain.State.EXECUTING, chain.getState());
chain.pause();
assertSame("Pausing chain should lead to State.PAUSED",
InterceptorChain.State.PAUSED, chain.getState());
chain.resume();
assertSame("Resuming chain should lead to State.COMPLETE",
InterceptorChain.State.COMPLETE, chain.getState());
chain.abort();
assertSame("Aborting chain should lead to State.ABORTED",
InterceptorChain.State.ABORTED, chain.getState());
}
@Test
public void testSuspendedException() throws Exception {
CountingPhaseInterceptor p1 =
new CountingPhaseInterceptor("phase1", "p1");
SuspendedInvocationInterceptor p2 =
new SuspendedInvocationInterceptor("phase2", "p2");
message.getInterceptorChain();
EasyMock.expectLastCall().andReturn(chain).anyTimes();
control.replay();
chain.add(p1);
chain.add(p2);
try {
chain.doIntercept(message);
fail("Suspended invocation swallowed");
} catch (SuspendedInvocationException ex) {
// ignore
}
assertSame("No previous interceptor selected", p1, chain.iterator().next());
assertSame("Suspended invocation should lead to State.PAUSED",
InterceptorChain.State.PAUSED, chain.getState());
}
@Test
public void testAddOneInterceptor() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
control.replay();
chain.add(p);
Iterator<Interceptor<? extends Message>> it = chain.iterator();
assertSame(p, it.next());
assertTrue(!it.hasNext());
}
@Test
public void testForceAddSameInterceptor() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
control.replay();
chain.add(p, false);
chain.add(p, false);
Iterator<Interceptor<? extends Message>> it = chain.iterator();
assertSame(p, it.next());
assertTrue(!it.hasNext());
chain.add(p, true);
it = chain.iterator();
assertSame(p, it.next());
assertSame(p, it.next());
assertTrue(!it.hasNext());
}
@Test
public void testForceAddSameInterceptorType() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p1");
control.replay();
chain.add(p1, false);
chain.add(p2, false);
Iterator<Interceptor<? extends Message>> it = chain.iterator();
assertSame(p1, it.next());
assertTrue(!it.hasNext());
chain.add(p2, true);
it = chain.iterator();
assertSame(p1, it.next());
assertSame(p2, it.next());
assertTrue(!it.hasNext());
}
@Test
public void testAddTwoInterceptorsSamePhase() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
Set<String> after = new HashSet<String>();
after.add("p1");
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p2", null, after);
control.replay();
chain.add(p1);
chain.add(p2);
Iterator<Interceptor<? extends Message>> it = chain.iterator();
assertSame("Unexpected interceptor at this position.", p1, it.next());
assertSame("Unexpected interceptor at this position.", p2, it.next());
assertTrue(!it.hasNext());
}
@Test
public void testThreeInterceptorSamePhaseWithOrder() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
Set<String> before = new HashSet<String>();
before.add("p1");
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p2", before, null);
Set<String> before1 = new HashSet<String>();
before1.add("p2");
AbstractPhaseInterceptor p3 = setUpPhaseInterceptor("phase1", "p3", before1, null);
control.replay();
chain.add(p3);
chain.add(p1);
chain.add(p2);
Iterator<Interceptor<? extends Message>> it = chain.iterator();
assertSame("Unexpected interceptor at this position.", p3, it.next());
assertSame("Unexpected interceptor at this position.", p2, it.next());
assertSame("Unexpected interceptor at this position.", p1, it.next());
assertTrue(!it.hasNext());
}
@Test
public void testSingleInterceptorPass() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p, false, false);
control.replay();
chain.add(p);
chain.doIntercept(message);
}
@Test
public void testSingleInterceptorFail() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p, true, true);
control.replay();
chain.add(p);
chain.doIntercept(message);
}
@Test
public void testSingleInterceptorFailWithCustomLogger() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p, true, true);
setUpCustomLogger(true, true, false);
control.replay();
chain.add(p);
chain.doIntercept(message);
}
@Test
public void testSingleInterceptorFailWithCustomLoggerAndDefaultLogging() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p, true, true);
setUpCustomLogger(true, true, true);
control.replay();
chain.add(p);
chain.doIntercept(message);
}
@Test
public void testSingleInterceptorFailWithoutCustomLogger() throws Exception {
AbstractPhaseInterceptor p = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p, true, true);
setUpCustomLogger(false, true, false);
control.replay();
chain.add(p);
chain.doIntercept(message);
}
@Test
public void testTwoInterceptorsInSamePhasePass() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p1, false, false);
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p2");
setUpPhaseInterceptorInvocations(p2, false, false);
control.replay();
chain.add(p2);
chain.add(p1);
chain.doIntercept(message);
}
@Test
public void testThreeInterceptorsInSamePhaseSecondFail() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p1, false, true);
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p2");
setUpPhaseInterceptorInvocations(p2, true, true);
AbstractPhaseInterceptor p3 = setUpPhaseInterceptor("phase1", "p3");
control.replay();
chain.add(p1);
chain.add(p2);
chain.add(p3);
chain.doIntercept(message);
}
@Test
public void testTwoInterceptorsInSamePhaseSecondFail() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p1, false, true);
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p2");
setUpPhaseInterceptorInvocations(p2, true, true);
control.replay();
chain.add(p1);
chain.add(p2);
chain.doIntercept(message);
}
@Test
public void testTwoInterceptorsInDifferentPhasesPass() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p1, false, false);
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase2", "p2");
setUpPhaseInterceptorInvocations(p2, false, false);
control.replay();
chain.add(p1);
chain.add(p2);
chain.doIntercept(message);
}
@Test
public void testTwoInterceptorsInDifferentPhasesSecondFail() throws Exception {
AbstractPhaseInterceptor p1 = setUpPhaseInterceptor("phase1", "p1");
setUpPhaseInterceptorInvocations(p1, false, true);
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase2", "p2");
setUpPhaseInterceptorInvocations(p2, true, true);
control.replay();
chain.add(p1);
chain.add(p2);
chain.doIntercept(message);
}
@Test
public void testInsertionInDifferentPhasePass() throws Exception {
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase2", "p2");
setUpPhaseInterceptorInvocations(p2, false, false);
AbstractPhaseInterceptor p3 = setUpPhaseInterceptor("phase3", "p3");
setUpPhaseInterceptorInvocations(p3, false, false);
InsertingPhaseInterceptor p1 = new InsertingPhaseInterceptor(chain, p2,
"phase1", "p1");
control.replay();
chain.add(p3);
chain.add(p1);
chain.doIntercept(message);
assertEquals(1, p1.invoked);
assertEquals(0, p1.faultInvoked);
}
@Test
public void testInsertionInSamePhasePass() throws Exception {
AbstractPhaseInterceptor p2 = setUpPhaseInterceptor("phase1", "p2");
setUpPhaseInterceptorInvocations(p2, false, false);
Set<String> after3 = new HashSet<String>();
after3.add("p2");
AbstractPhaseInterceptor p3 = setUpPhaseInterceptor("phase1", "p3", null, after3);
setUpPhaseInterceptorInvocations(p3, false, false);
InsertingPhaseInterceptor p1 = new InsertingPhaseInterceptor(chain, p3,
"phase1", "p1");
p1.addBefore("p2");
control.replay();
chain.add(p1);
chain.add(p2);
chain.doIntercept(message);
assertEquals(1, p1.invoked);
assertEquals(0, p1.faultInvoked);
}
@Test
public void testWrappedInvocation() throws Exception {
CountingPhaseInterceptor p1 = new CountingPhaseInterceptor("phase1",
"p1");
WrapperingPhaseInterceptor p2 = new WrapperingPhaseInterceptor(
"phase2", "p2");
CountingPhaseInterceptor p3 = new CountingPhaseInterceptor("phase3",
"p3");
message.getInterceptorChain();
EasyMock.expectLastCall().andReturn(chain).anyTimes();
control.replay();
chain.add(p1);
chain.add(p2);
chain.add(p3);
chain.doIntercept(message);
assertEquals(1, p1.invoked);
assertEquals(1, p2.invoked);
assertEquals(1, p3.invoked);
}
@Test
public void testChainInvocationStartFromSpecifiedInterceptor() throws Exception {
CountingPhaseInterceptor p1 = new CountingPhaseInterceptor("phase1",
"p1");
CountingPhaseInterceptor p2 = new CountingPhaseInterceptor(
"phase2", "p2");
CountingPhaseInterceptor p3 = new CountingPhaseInterceptor("phase3",
"p3");
message.getInterceptorChain();
EasyMock.expectLastCall().andReturn(chain).anyTimes();
control.replay();
chain.add(p1);
chain.add(p2);
chain.add(p3);
chain.doInterceptStartingAfter(message, p2.getId());
assertEquals(0, p1.invoked);
assertEquals(0, p2.invoked);
assertEquals(1, p3.invoked);
}
AbstractPhaseInterceptor setUpPhaseInterceptor(String phase, String id) throws Exception {
return setUpPhaseInterceptor(phase, id, null, null);
}
AbstractPhaseInterceptor setUpPhaseInterceptor(final String phase,
final String id,
Set<String> b,
Set<String> a) throws Exception {
AbstractPhaseInterceptor p = control
.createMock(AbstractPhaseInterceptor.class);
if (a == null) {
a = new SortedArraySet<String>();
}
if (b == null) {
b = new SortedArraySet<String>();
}
Field f = AbstractPhaseInterceptor.class.getDeclaredField("before");
f.setAccessible(true);
f.set(p, b);
f = AbstractPhaseInterceptor.class.getDeclaredField("after");
f.setAccessible(true);
f.set(p, a);
f = AbstractPhaseInterceptor.class.getDeclaredField("phase");
f.setAccessible(true);
f.set(p, phase);
f = AbstractPhaseInterceptor.class.getDeclaredField("id");
f.setAccessible(true);
f.set(p, id);
return p;
}
@SuppressWarnings("unchecked")
void setUpPhaseInterceptorInvocations(AbstractPhaseInterceptor p,
boolean fail, boolean expectFault) {
p.handleMessage(message);
if (fail) {
EasyMock.expectLastCall().andThrow(new RuntimeException());
message.setContent(EasyMock.isA(Class.class),
EasyMock.isA(Exception.class));
EasyMock.expectLastCall();
} else {
EasyMock.expectLastCall();
}
if (expectFault) {
p.handleFault(message);
EasyMock.expectLastCall();
}
}
private void setUpCustomLogger(boolean useCustomLogger,
boolean expectFault,
boolean returnFromCustomLogger) {
if (useCustomLogger) {
FaultListener customLogger = control.createMock(FaultListener.class);
message.getContextualProperty(FaultListener.class.getName());
EasyMock.expectLastCall().andReturn(customLogger);
if (expectFault) {
customLogger.faultOccurred(EasyMock.isA(Exception.class),
EasyMock.isA(String.class),
EasyMock.isA(Message.class));
EasyMock.expectLastCall().andReturn(returnFromCustomLogger);
if (returnFromCustomLogger) {
//default logging should also be invoked
//not too beautiful way to verify that defaultLogging was invoked.
message.get(FaultMode.class);
EasyMock.expectLastCall().andReturn(FaultMode.RUNTIME_FAULT);
}
}
} else {
message.getContextualProperty(FaultListener.class.getName());
EasyMock.expectLastCall().andReturn(null);
}
}
public class InsertingPhaseInterceptor extends
AbstractPhaseInterceptor<Message> {
int invoked;
int faultInvoked;
private final PhaseInterceptorChain insertionChain;
private final AbstractPhaseInterceptor insertionInterceptor;
public InsertingPhaseInterceptor(PhaseInterceptorChain c,
AbstractPhaseInterceptor i, String phase, String id) {
super(id, phase);
insertionChain = c;
insertionInterceptor = i;
}
public void handleMessage(Message m) {
insertionChain.add(insertionInterceptor);
invoked++;
}
public void handleFault(Message m) {
faultInvoked++;
}
}
public class CountingPhaseInterceptor extends
AbstractPhaseInterceptor<Message> {
int invoked;
public CountingPhaseInterceptor(String phase, String id) {
super(id, phase);
}
public void handleMessage(Message m) {
invoked++;
}
}
public class WrapperingPhaseInterceptor extends CountingPhaseInterceptor {
public WrapperingPhaseInterceptor(String phase, String id) {
super(phase, id);
}
public void handleMessage(Message m) {
super.handleMessage(m);
m.getInterceptorChain().doIntercept(m);
}
}
public class SuspendedInvocationInterceptor extends AbstractPhaseInterceptor<Message> {
public SuspendedInvocationInterceptor(String phase, String id) {
super(id, phase);
}
public void handleMessage(Message m) {
m.getInterceptorChain().suspend();
}
}
}