001 /*
002 * Copyright 2002-2004 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 package org.springframework.richclient.form.binding.support;
017
018 import java.util.Arrays;
019 import java.util.Collections;
020 import java.util.HashSet;
021 import java.util.Iterator;
022 import java.util.Map;
023 import java.util.Set;
024
025 import javax.swing.JComponent;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029 import org.springframework.binding.form.FormModel;
030 import org.springframework.richclient.application.support.ApplicationServicesAccessor;
031 import org.springframework.richclient.form.binding.Binder;
032 import org.springframework.richclient.form.binding.Binding;
033 import org.springframework.util.Assert;
034
035 /**
036 * @author Oliver Hutchison
037 */
038 public abstract class AbstractBinder extends ApplicationServicesAccessor implements Binder {
039
040 /**
041 * The client property key that is used to save a copy of a binding in its bound
042 * component's client property set. This can be used to locate the binding
043 * that has bound a given component.
044 * @see JComponent#getClientProperty(java.lang.Object)
045 */
046 public static final String BINDING_CLIENT_PROPERTY_KEY = "binding";
047
048 protected final Log log = LogFactory.getLog(getClass());
049
050 private final Class requiredSourceClass;
051
052 private final Set supportedContextKeys;
053
054 protected AbstractBinder(Class requiredSourceClass) {
055 this.requiredSourceClass = requiredSourceClass;
056 this.supportedContextKeys = Collections.EMPTY_SET;
057 }
058
059 protected AbstractBinder(Class requiredSourceClass, String[] supportedContextKeys) {
060 this.requiredSourceClass = requiredSourceClass;
061 this.supportedContextKeys = new HashSet(Arrays.asList(supportedContextKeys));
062 }
063
064 protected void validateContextKeys(Map context) {
065 Set unkownKeys = new HashSet(context.keySet());
066 unkownKeys.removeAll(supportedContextKeys);
067 for (Iterator i = unkownKeys.iterator(); i.hasNext();) {
068 final Object key = i.next();
069 context.remove(key);
070 if (log.isWarnEnabled()) {
071 log.warn("Context key '" + key + "' not supported.");
072 }
073 }
074 }
075
076 public Class getRequiredSourceClass() {
077 return requiredSourceClass;
078 }
079
080 public Binding bind(FormModel formModel, String formPropertyPath, Map context) {
081 JComponent control = createControl(context);
082 Assert.notNull(control, "This binder does not support creating a default control.");
083 return bind(control, formModel, formPropertyPath, context);
084 }
085
086 protected abstract JComponent createControl(Map context);
087
088 public Binding bind(JComponent control, FormModel formModel, String formPropertyPath, Map context) {
089 // Ensure that this component has not already been bound
090 Binding binding = (Binding)control.getClientProperty(BINDING_CLIENT_PROPERTY_KEY);
091 if( binding != null ) {
092 throw new IllegalStateException( "Component is already bound to property: " + binding.getProperty());
093 }
094 validateContextKeys(context);
095 binding = doBind(control, formModel, formPropertyPath, context);
096 control.putClientProperty(BINDING_CLIENT_PROPERTY_KEY, binding);
097 return binding;
098 }
099
100 protected abstract Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context);
101
102 protected Class getPropertyType(FormModel formModel, String formPropertyPath) {
103 return formModel.getFieldMetadata(formPropertyPath).getPropertyType();
104 }
105 }