View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package com.silvermindsoftware.hitch;
18  
19  import java.awt.Container;
20  import java.lang.reflect.Field;
21  import java.util.Arrays;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.Set;
25  
26  import javax.swing.JComponent;
27  
28  import org.jdesktop.beansbinding.AutoBinding;
29  import org.jdesktop.beansbinding.AutoBinding.UpdateStrategy;
30  import org.jdesktop.beansbinding.Binding;
31  import org.jdesktop.beansbinding.BindingGroup;
32  import org.jdesktop.beansbinding.Property;
33  
34  
35  import com.silvermindsoftware.hitch.binding.BindingCreator;
36  import com.silvermindsoftware.hitch.binding.BindingFactory;
37  import com.silvermindsoftware.hitch.binding.PropertyUtil;
38  import com.silvermindsoftware.hitch.meta.ComponentMeta;
39  import com.silvermindsoftware.hitch.meta.FormMeta;
40  import com.silvermindsoftware.hitch.meta.ModelMeta;
41  import com.silvermindsoftware.hitch.validation.ValidatingBindingListener;
42  import com.silvermindsoftware.hitch.validation.response.ValidationResponder;
43  
44  import ch.elca.el4j.services.gui.swing.GUIApplication;
45  import ch.elca.el4j.util.config.GenericConfig;
46  
47  /**
48   * This class is the default implementation of the binder.
49   *
50   * @svnLink $Revision: 4010 $;$Date: 2009-12-01 10:59:54 +0100 (Di, 01. Dez 2009) $;$Author: jonasha $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/swing/src/main/java/com/silvermindsoftware/hitch/BinderImpl.java $
51   *
52   * @author Stefan Wismer (SWI), based on Hitch by Brandon Goodin
53   */
54  public class BinderImpl implements Binder {
55  	
56  	/**
57  	 * The managed bindings.
58  	 */
59  	protected Set<BindingGroup> m_bindings = new HashSet<BindingGroup>();
60  
61  	/**
62  	 * Use {@link BinderManager}.
63  	 */
64  	BinderImpl() { }
65  	
66  	/** {@inheritDoc} */
67  	public BindingGroup addAutoBinding(Container container, String... modelId) {
68  		return addAutoBinding(container, true, modelId);
69  	}
70  
71  	/** {@inheritDoc} */
72  	@SuppressWarnings("unchecked")
73  	public BindingGroup addAutoBinding(Container container,
74  		boolean performValidate, String... modelId) {
75  		
76  		FormMeta formMeta = BinderManager.getFormMetaData(container.getClass());
77  		
78  		BindingGroup bindings = new BindingGroup();
79  
80  		for (Iterator<ComponentMeta> it = formMeta.getComponentMetaIterator();
81  			it.hasNext();) {
82  			
83  			ComponentMeta componentMeta = it.next();
84  
85  			// check to see if update should occur for particular model objects
86  			if (skipModel(componentMeta.getModelId(), modelId)) {
87  				break;
88  			}
89  
90  			// get container field
91  			Field componentField = componentMeta.getComponentField();
92  
93  			// get model values
94  			ModelMeta modelMeta = formMeta.getModelMeta(componentMeta
95  					.getModelId());
96  			Field modelField = modelMeta.getModelField();
97  			Object modelObject = null;
98  			try {
99  				modelObject = modelField.get(container);
100 			} catch (IllegalAccessException e) {
101 				throw new RuntimeException(e.getMessage(), e);
102 			}
103 
104 			JComponent formComponent = null;
105 
106 			try {
107 				// check if formComponent will be of type JComponent
108 				Object tmpComponent = componentField.get(container);
109 				if (!JComponent.class.isAssignableFrom(
110 					tmpComponent.getClass())) {
111 					break;
112 				}
113 				formComponent = (JComponent) tmpComponent;
114 			} catch (IllegalAccessException e) {
115 				throw new IllegalStateException(e.getMessage(), e);
116 			}
117 
118 			if (formComponent == null) {
119 				throw new IllegalStateException("Form container named "
120 						+ componentField.getName() + " was not found");
121 			}
122 			
123 			AutoBinding binding = addManualBinding(UpdateStrategy.READ_WRITE,
124 				modelObject, componentMeta.getModelPropertyName(),
125 				formComponent, performValidate);
126 			
127 			// collect inserted bindings
128 			if (binding != null) {
129 				bindings.addBinding(binding);
130 			}
131 		}
132 		return bindings;
133 	}
134 	
135 	/** {@inheritDoc} */
136 	@SuppressWarnings("unchecked")
137 	public AutoBinding addAutoBinding(Container container,
138 		JComponent component, BindingCreator creator, boolean performValidate) {
139 		
140 		FormMeta formMeta = BinderManager.getFormMetaData(container.getClass());
141 
142 		for (Iterator<ComponentMeta> it = formMeta.getComponentMetaIterator();
143 			it.hasNext();) {
144 			
145 			ComponentMeta componentMeta = it.next();
146 			try {
147 				if (componentMeta.getComponentField().get(container)
148 					.equals(component)) {
149 					
150 					// get model values
151 					ModelMeta modelMeta = formMeta.getModelMeta(componentMeta
152 							.getModelId());
153 					Field modelField = modelMeta.getModelField();
154 					Object modelObject = null;
155 					try {
156 						modelObject = modelField.get(container);
157 					} catch (IllegalAccessException e) {
158 						throw new RuntimeException(e.getMessage(), e);
159 					}
160 					
161 					return addManualBinding(modelObject,
162 						componentMeta.getModelPropertyName(),
163 						component, creator, performValidate);
164 				}
165 			} catch (IllegalArgumentException e) {
166 				return null;
167 			} catch (IllegalAccessException e) {
168 				return null;
169 			}
170 			
171 		}
172 
173 		return null;
174 	}
175 
176 	/** {@inheritDoc} */
177 	@SuppressWarnings("unchecked")
178 	public AutoBinding addManualBinding(UpdateStrategy strategy, Object model,
179 		String property, JComponent component, boolean performValidate) {
180 		
181 		// create a default binding
182 		AutoBinding b = BindingFactory.getInstance()
183 			.createBinding(strategy, model, property, component);
184 		
185 		if (b != null) {
186 			return addManualBinding(b, performValidate);
187 		} else {
188 			return null;
189 		}
190 	}
191 
192 	/** {@inheritDoc} */
193 	@SuppressWarnings("unchecked")
194 	public AutoBinding addManualBinding(Object model, String property,
195 		JComponent component, BindingCreator creator, boolean performValidate) {
196 		
197 		Property modelPropertyName = PropertyUtil.create(property);
198 		
199 		AutoBinding b = creator.createBinding(
200 			modelPropertyName.getValue(model), component);
201 		addManualBinding(b);
202 		
203 		if (performValidate) {
204 			creator.addValidation(component);
205 		}
206 		
207 		return b;
208 	}
209 	
210 	/** {@inheritDoc} */
211 	@SuppressWarnings("unchecked")
212 	public AutoBinding addManualBinding(AutoBinding binding,
213 		boolean performValidate) {
214 		
215 		addManualBinding(binding);
216 		
217 		if (performValidate) {
218 			GenericConfig config = GUIApplication.getInstance().getConfig();
219 			addValidationResponder(binding, (ValidationResponder)
220 				config.get("validationResponder"));
221 		}
222 		return binding;
223 	}
224 
225 	/** {@inheritDoc} */
226 	@SuppressWarnings("unchecked")
227 	public AutoBinding addManualBinding(AutoBinding binding) {
228 		BindingGroup g = new BindingGroup();
229 		g.addBinding(binding);
230 		m_bindings.add(g);
231 		
232 		return binding;
233 	}
234 	
235 	/** {@inheritDoc} */
236 	public void addValidationResponder(BindingGroup group,
237 		ValidationResponder responder) {
238 		
239 		group.addBindingListener(new ValidatingBindingListener(responder));
240 	}
241 	
242 	/** {@inheritDoc} */
243 	@SuppressWarnings("unchecked")
244 	public void addValidationResponder(AutoBinding binding,
245 		ValidationResponder responder) {
246 		
247 		binding.addBindingListener(new ValidatingBindingListener(responder));
248 	}
249 
250 	/** {@inheritDoc} */
251 	public void bindAll() {
252 		for (BindingGroup group : m_bindings) {
253 			group.bind();
254 		}
255 	}
256 	
257 	/** {@inheritDoc} */
258 	public void unbindAll() {
259 		for (BindingGroup group : m_bindings) {
260 			group.unbind();
261 		}
262 	}
263 
264 	/** {@inheritDoc} */
265 	public void removeAll() {
266 		unbindAll();
267 		m_bindings.clear();
268 	}
269 
270 	/** {@inheritDoc} */
271 	@SuppressWarnings("unchecked")
272 	public BindingGroup find(Object model, String property,
273 		JComponent component) {
274 		
275 		BindingGroup result = new BindingGroup();
276 		
277 		Property modelPropertyName = null;
278 		if (property != null) {
279 			modelPropertyName = PropertyUtil.create(property);
280 		}
281 		for (BindingGroup group : m_bindings) {
282 			for (Binding binding : group.getBindings()) {
283 				if ((model != null && model == binding.getSourceObject())
284 					|| (modelPropertyName != null
285 						&& binding.getSourceProperty().equals(modelPropertyName))
286 					|| (component != null
287 						&& binding.getTargetObject() == component)) {
288 					result.addBinding(binding);
289 				}
290 			}
291 		}
292 		return result;
293 	}
294 
295 	/** {@inheritDoc} */
296 	public void remove(BindingGroup binding) {
297 		m_bindings.remove(binding);
298 	}
299 
300 	/** {@inheritDoc} */
301 	@SuppressWarnings("unchecked")
302 	public void remove(AutoBinding binding) {
303 		for (BindingGroup group : m_bindings) {
304 			for (Binding bindingInGroup : group.getBindings()) {
305 				if (bindingInGroup == binding) {
306 					group.removeBinding(binding);
307 					return;
308 				}
309 			}
310 		}
311 	}
312 
313 	
314 	/**
315 	 * Check if update should occur for particular model objects.
316 	 *
317 	 * @param modelId        the model id given by the annotation
318 	 * @param modelIdList    list of available models
319 	 * @return               true if model should be skipped
320 	 */
321 	protected boolean skipModel(String modelId, String[] modelIdList) {
322 		if (modelIdList != null && modelIdList.length > 0) {
323 			Arrays.sort(modelIdList);
324 
325 			if (Arrays.binarySearch(modelIdList, modelId) < 0) {
326 				return true;
327 			}
328 		}
329 		return false;
330 	}
331 
332 }