001/* 002 * Copyright 2012-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.test.web.client; 018 019import java.util.Collections; 020import java.util.Map; 021import java.util.concurrent.ConcurrentHashMap; 022 023import org.springframework.beans.BeanUtils; 024import org.springframework.boot.web.client.RestTemplateBuilder; 025import org.springframework.boot.web.client.RestTemplateCustomizer; 026import org.springframework.test.web.client.MockRestServiceServer; 027import org.springframework.test.web.client.RequestExpectationManager; 028import org.springframework.test.web.client.SimpleRequestExpectationManager; 029import org.springframework.util.Assert; 030import org.springframework.web.client.RestTemplate; 031 032/** 033 * {@link RestTemplateCustomizer} that can be applied to a {@link RestTemplateBuilder} 034 * instances to add {@link MockRestServiceServer} support. 035 * <p> 036 * Typically applied to an existing builder before it is used, for example: 037 * <pre class="code"> 038 * MockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer(); 039 * MyBean bean = new MyBean(new RestTemplateBuilder(customizer)); 040 * customizer.getServer().expect(requestTo("/hello")).andRespond(withSuccess()); 041 * bean.makeRestCall(); 042 * </pre> 043 * <p> 044 * If the customizer is only used once, the {@link #getServer()} method can be used to 045 * obtain the mock server. If the customizer has been used more than once the 046 * {@link #getServer(RestTemplate)} or {@link #getServers()} method must be used to access 047 * the related server. 048 * 049 * @author Phillip Webb 050 * @since 1.4.0 051 * @see #getServer() 052 * @see #getServer(RestTemplate) 053 */ 054public class MockServerRestTemplateCustomizer implements RestTemplateCustomizer { 055 056 private Map<RestTemplate, RequestExpectationManager> expectationManagers = new ConcurrentHashMap<>(); 057 058 private Map<RestTemplate, MockRestServiceServer> servers = new ConcurrentHashMap<>(); 059 060 private final Class<? extends RequestExpectationManager> expectationManager; 061 062 private boolean detectRootUri = true; 063 064 public MockServerRestTemplateCustomizer() { 065 this.expectationManager = SimpleRequestExpectationManager.class; 066 } 067 068 public MockServerRestTemplateCustomizer( 069 Class<? extends RequestExpectationManager> expectationManager) { 070 Assert.notNull(expectationManager, "ExpectationManager must not be null"); 071 this.expectationManager = expectationManager; 072 } 073 074 /** 075 * Set if root URIs from {@link RootUriRequestExpectationManager} should be detected 076 * and applied to the {@link MockRestServiceServer}. 077 * @param detectRootUri if root URIs should be detected 078 */ 079 public void setDetectRootUri(boolean detectRootUri) { 080 this.detectRootUri = detectRootUri; 081 } 082 083 @Override 084 public void customize(RestTemplate restTemplate) { 085 RequestExpectationManager expectationManager = createExpectationManager(); 086 if (this.detectRootUri) { 087 expectationManager = RootUriRequestExpectationManager 088 .forRestTemplate(restTemplate, expectationManager); 089 } 090 MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate) 091 .build(expectationManager); 092 this.expectationManagers.put(restTemplate, expectationManager); 093 this.servers.put(restTemplate, server); 094 } 095 096 protected RequestExpectationManager createExpectationManager() { 097 return BeanUtils.instantiateClass(this.expectationManager); 098 } 099 100 public MockRestServiceServer getServer() { 101 Assert.state(!this.servers.isEmpty(), 102 "Unable to return a single MockRestServiceServer since " 103 + "MockServerRestTemplateCustomizer has not been bound to " 104 + "a RestTemplate"); 105 Assert.state(this.servers.size() == 1, 106 "Unable to return a single MockRestServiceServer since " 107 + "MockServerRestTemplateCustomizer has been bound to " 108 + "more than one RestTemplate"); 109 return this.servers.values().iterator().next(); 110 } 111 112 public Map<RestTemplate, RequestExpectationManager> getExpectationManagers() { 113 return this.expectationManagers; 114 } 115 116 public MockRestServiceServer getServer(RestTemplate restTemplate) { 117 return this.servers.get(restTemplate); 118 } 119 120 public Map<RestTemplate, MockRestServiceServer> getServers() { 121 return Collections.unmodifiableMap(this.servers); 122 } 123 124}