/** * 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.systest.http; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import javax.xml.namespace.QName; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.bus.spring.SpringBusFactory; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; import org.apache.hello_world.Greeter; import org.apache.hello_world.services.SOAPService; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; /** * This class tests several issues and Conduit policies based * on a set up of redirecting servers. * <pre> * * Http Redirection: * * Rethwel(http:9004) ----> Mortimer (http:9000) * * Redirect Loop: * * Hurlon (http:9006) ----> Abost(http:9007) ----\ * ^ | * |-------------------------------------------/ */ public class HTTPConduitTest extends AbstractBusClientServerTestBase { private static final boolean IN_PROCESS = true; private static List<String> servers = new ArrayList<>(); private static Map<String, String> addrMap = new TreeMap<String, String>(); private final QName serviceName = new QName("http://apache.org/hello_world", "SOAPService"); private final QName rethwelQ = new QName("http://apache.org/hello_world", "Rethwel"); private final QName mortimerQ = new QName("http://apache.org/hello_world", "Mortimer"); private final QName hurlonQ = new QName("http://apache.org/hello_world", "Hurlon"); public HTTPConduitTest() { } public static String getPort(String s) { return BusServer.PORTMAP.get(s); } @BeforeClass public static void allocatePorts() { BusServer.resetPortMap(); addrMap.clear(); addrMap.put("Mortimer", "http://localhost:" + getPort("PORT0") + "/"); addrMap.put("Rethwel", "http://localhost:" + getPort("PORT1") + "/"); addrMap.put("Abost", "http://localhost:" + getPort("PORT2") + "/"); addrMap.put("Hurlon", "http://localhost:" + getPort("PORT3") + "/"); servers.clear(); } /** * This function is used to start up a server. It only "starts" a * server if it hasn't been started before, hence its static nature. * <p> * This approach is used to start the needed servers for a particular test * instead of starting them all in "startServers". This single needed * server approach allieviates the pain in starting them all just to run * a particular test in the debugger. */ public synchronized boolean startServer(String name) { if (servers.contains(name)) { return true; } Bus bus = BusFactory.getThreadDefaultBus(false); URL serverC = Server.class.getResource(name + ".cxf"); BusFactory.setDefaultBus(null); BusFactory.setThreadDefaultBus(null); boolean server = launchServer(Server.class, null, new String[] { name, addrMap.get(name), serverC.toString() }, IN_PROCESS); if (server) { servers.add(name); } BusFactory.setDefaultBus(null); BusFactory.setThreadDefaultBus(bus); return server; } @AfterClass public static void cleanUp() { Bus b = BusFactory.getDefaultBus(false); if (b != null) { b.shutdown(true); } b = BusFactory.getThreadDefaultBus(false); if (b != null) { b.shutdown(true); } } //methods that a subclass can override to inject a Proxy into the flow //and assert the proxy was appropriately called public void configureProxy(Client c) { } public void resetProxyCount() { } public void assertProxyRequestCount(int i) { } private Greeter getMortimerGreeter() throws MalformedURLException { URL wsdl = getClass().getResource("greeting.wsdl"); assertNotNull("WSDL is null", wsdl); SOAPService service = new SOAPService(wsdl, serviceName); assertNotNull("Service is null", service); Greeter mortimer = service.getPort(mortimerQ, Greeter.class); assertNotNull("Port is null", mortimer); updateAddressPort(mortimer, getPort("PORT0")); configureProxy(ClientProxy.getClient(mortimer)); return mortimer; } @Test public void testBasicConnection() throws Exception { startServer("Mortimer"); Greeter mortimer = getMortimerGreeter(); String answer = mortimer.sayHi(); answer = mortimer.sayHi(); answer = mortimer.sayHi(); assertTrue("Unexpected answer: " + answer, "Bonjour from Mortimer".equals(answer)); assertProxyRequestCount(3); } @Test public void testLogLevelIssueCXF3466() throws Exception { startServer("Mortimer"); Greeter mortimer = getMortimerGreeter(); Logger rootLogger = LogManager.getLogManager().getLogger(""); Level oldLevel = rootLogger.getLevel(); rootLogger.setLevel(Level.FINE); try { // Will throw exception Stream is closed if bug is present mortimer.sayHi(); } finally { rootLogger.setLevel(oldLevel); } assertProxyRequestCount(1); } /** * This methods tests that a conduit that is not configured * to follow redirects will not. The default is not to * follow redirects. * Rethwel redirects to Mortimer. * * Note: Unfortunately, the invocation will * "fail" for any number of other reasons. */ @Test public void testHttp2HttpRedirectFail() throws Exception { startServer("Mortimer"); startServer("Rethwel"); URL wsdl = getClass().getResource("greeting.wsdl"); assertNotNull("WSDL is null", wsdl); SOAPService service = new SOAPService(wsdl, serviceName); assertNotNull("Service is null", service); Greeter rethwel = service.getPort(rethwelQ, Greeter.class); assertNotNull("Port is null", rethwel); updateAddressPort(rethwel, getPort("PORT1")); configureProxy(ClientProxy.getClient(rethwel)); String answer = null; try { answer = rethwel.sayHi(); fail("Redirect didn't fail. Got answer: " + answer); } catch (Exception e) { //e.printStackTrace(); } assertProxyRequestCount(1); } /** * We use this class to reset the default bus. * Note: This may not always work in the future. * I was lucky in that "defaultBus" is actually a * protected static. */ class DefaultBusFactory extends SpringBusFactory { public Bus createBus(URL config) { Bus bus = super.createBus(config, true); BusFactory.setDefaultBus(bus); BusFactory.setThreadDefaultBus(bus); return bus; } } /** * This method tests if http to http redirects work. * Rethwel redirects to Mortimer. */ @Test public void testHttp2HttpRedirect() throws Exception { startServer("Mortimer"); startServer("Rethwel"); URL config = getClass().getResource("Http2HttpRedirect.cxf"); // We go through the back door, setting the default bus. new DefaultBusFactory().createBus(config); URL wsdl = getClass().getResource("greeting.wsdl"); assertNotNull("WSDL is null", wsdl); SOAPService service = new SOAPService(wsdl, serviceName); assertNotNull("Service is null", service); Greeter rethwel = service.getPort(rethwelQ, Greeter.class); updateAddressPort(rethwel, getPort("PORT1")); assertNotNull("Port is null", rethwel); configureProxy(ClientProxy.getClient(rethwel)); String answer = rethwel.sayHi(); assertTrue("Unexpected answer: " + answer, "Bonjour from Mortimer".equals(answer)); assertProxyRequestCount(2); } /** * This methods tests that a redirection loop will fail. * Hurlon redirects to Abost, which redirects to Hurlon. * * Note: Unfortunately, the invocation may "fail" for any * number of reasons. */ @Test public void testHttp2HttpLoopRedirectFail() throws Exception { startServer("Abost"); startServer("Hurlon"); URL config = getClass().getResource("Http2HttpLoopRedirectFail.cxf"); // We go through the back door, setting the default bus. new DefaultBusFactory().createBus(config); URL wsdl = getClass().getResource("greeting.wsdl"); assertNotNull("WSDL is null", wsdl); SOAPService service = new SOAPService(wsdl, serviceName); assertNotNull("Service is null", service); Greeter hurlon = service.getPort(hurlonQ, Greeter.class); assertNotNull("Port is null", hurlon); updateAddressPort(hurlon, getPort("PORT3")); configureProxy(ClientProxy.getClient(hurlon)); String answer = null; try { answer = hurlon.sayHi(); fail("Redirect didn't fail. Got answer: " + answer); } catch (Exception e) { // This exception will be one of not being able to // read from the StreamReader //e.printStackTrace(); } assertProxyRequestCount(2); } }