001/* 002 * Copyright 2002-2014 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 * https://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.messaging.core; 018 019import java.util.Map; 020import java.util.concurrent.ConcurrentHashMap; 021 022import org.springframework.beans.factory.InitializingBean; 023import org.springframework.util.Assert; 024 025/** 026 * {@link DestinationResolver} implementation that proxies a target DestinationResolver, 027 * caching its {@link #resolveDestination} results. Such caching is particularly useful 028 * if the destination resolving process is expensive (e.g. the destination has to be 029 * resolved through an external system) and the resolution results are stable anyway. 030 * 031 * @author Agim Emruli 032 * @author Juergen Hoeller 033 * @since 4.1 034 * @see DestinationResolver#resolveDestination 035 */ 036public class CachingDestinationResolverProxy<D> implements DestinationResolver<D>, InitializingBean { 037 038 private final Map<String, D> resolvedDestinationCache = new ConcurrentHashMap<String, D>(); 039 040 private DestinationResolver<D> targetDestinationResolver; 041 042 043 /** 044 * Create a new CachingDestinationResolverProxy, setting the target DestinationResolver 045 * through the {@link #setTargetDestinationResolver} bean property. 046 */ 047 public CachingDestinationResolverProxy() { 048 } 049 050 /** 051 * Create a new CachingDestinationResolverProxy using the given target 052 * DestinationResolver to actually resolve destinations. 053 * @param targetDestinationResolver the target DestinationResolver to delegate to 054 */ 055 public CachingDestinationResolverProxy(DestinationResolver<D> targetDestinationResolver) { 056 Assert.notNull(targetDestinationResolver, "Target DestinationResolver must not be null"); 057 this.targetDestinationResolver = targetDestinationResolver; 058 } 059 060 061 /** 062 * Set the target DestinationResolver to delegate to. 063 */ 064 public void setTargetDestinationResolver(DestinationResolver<D> targetDestinationResolver) { 065 this.targetDestinationResolver = targetDestinationResolver; 066 } 067 068 @Override 069 public void afterPropertiesSet() { 070 if (this.targetDestinationResolver == null) { 071 throw new IllegalArgumentException("Property 'targetDestinationResolver' is required"); 072 } 073 } 074 075 076 /** 077 * Resolves and caches destinations if successfully resolved by the target 078 * DestinationResolver implementation. 079 * @param name the destination name to be resolved 080 * @return the currently resolved destination or an already cached destination 081 * @throws DestinationResolutionException if the target DestinationResolver 082 * reports an error during destination resolution 083 */ 084 @Override 085 public D resolveDestination(String name) throws DestinationResolutionException { 086 D destination = this.resolvedDestinationCache.get(name); 087 if (destination == null) { 088 destination = this.targetDestinationResolver.resolveDestination(name); 089 this.resolvedDestinationCache.put(name, destination); 090 } 091 return destination; 092 } 093 094}