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 }