001 /* 002 * Copyright 2002-2005 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * 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, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.binding.form.support; 017 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import org.springframework.binding.form.FieldFace; 022 import org.springframework.binding.form.FieldFaceSource; 023 import org.springframework.util.Assert; 024 import org.springframework.util.CachingMapDecorator; 025 026 /** 027 * A convenience superclass for FieldFaceSource's that require caching to improve the performance of FieldFace lookup. 028 * 029 * <p> 030 * FieldFace retrieval is delegated to subclasses using the {@link #loadFieldFace(String, Object)} method. 031 * 032 * @author Oliver Hutchison 033 * @author Mathias Broekelmann 034 */ 035 public abstract class CachingFieldFaceSource implements FieldFaceSource { 036 037 private static final Object DEFAULT_CONTEXT = new Object(); 038 039 /* 040 * A cache with context keys and Map from field to FieldFace values. The keys are held with week references so this 041 * class will not prevent GC of context instances. 042 */ 043 private final CachingMapDecorator cachedFieldFaceDescriptors = new CachingMapDecorator(true) { 044 public Object create(Object key) { 045 return new HashMap(); 046 } 047 }; 048 049 protected CachingFieldFaceSource() { 050 } 051 052 public FieldFace getFieldFace(String field) { 053 return getFieldFace(field, null); 054 } 055 056 public FieldFace getFieldFace(final String field, final Object context) { 057 Map faceDescriptors = (Map) cachedFieldFaceDescriptors.get(context == null ? DEFAULT_CONTEXT : context); 058 FieldFace fieldFaceDescriptor = (FieldFace) faceDescriptors.get(field); 059 if (fieldFaceDescriptor == null) { 060 fieldFaceDescriptor = loadFieldFace(field, context); 061 Assert.notNull(fieldFaceDescriptor, "FieldFace must not be null."); 062 faceDescriptors.put(field, fieldFaceDescriptor); 063 } 064 return fieldFaceDescriptor; 065 } 066 067 /** 068 * Loads the FieldFace for the given field path and context id. This value will be cached so performance need not be 069 * a concern of this method. 070 * 071 * @param field 072 * the form field path 073 * @param context 074 * optional context for which the FieldFace is being resolved 075 * @return the FieldFace for the given context id (never null). 076 */ 077 protected abstract FieldFace loadFieldFace(String field, Object context); 078 }