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.Component;
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Method;
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import com.silvermindsoftware.hitch.annotations.BoundComponent;
28  import com.silvermindsoftware.hitch.annotations.Form;
29  import com.silvermindsoftware.hitch.annotations.ModelObject;
30  import com.silvermindsoftware.hitch.meta.FormMeta;
31  import com.silvermindsoftware.hitch.reflect.ClassManager;
32  
33  /**
34   * This class manages binder instances.
35   *
36   * @svnLink $Revision: 3873 $;$Date: 2009-08-04 13:59:45 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/swing/src/main/java/com/silvermindsoftware/hitch/BinderManager.java $
37   *
38   * @author Stefan Wismer (SWI), based on Hitch by Brandon Goodin
39   */
40  public class BinderManager {
41  	public static final BinderManager s_manager = new BinderManager();
42  
43  	protected Map<Class<?>, FormMeta> m_formMap
44  		= new HashMap<Class<?>, FormMeta>();
45  	
46  	private BinderManager() { }
47  	
48  	/**
49  	 * Get a binder for a specific window component.
50  	 *
51  	 * @param form    the form containing the components
52  	 * @return        the binder
53  	 */
54  	public static Binder getBinder(Component form) {
55  		s_manager.collectAnnotationMeta(form.getClass());
56  		return new BinderImpl();
57  	}
58  	
59  	public static FormMeta getFormMetaData(Class<?> formClass) {
60  		return s_manager.getFormMeta(formClass);
61  	}
62  	
63  
64  
65  	@SuppressWarnings("unchecked")
66  	private void collectAnnotationMeta(Class formClass) {
67  		ErrorContext.put("- Collecting AnnotationMeta on " + formClass.getName());
68  		// ComponentField Meta for component class
69  		FormMeta formMeta;
70  
71  		if (m_formMap.containsKey(formClass)) {
72  			formMeta = m_formMap.get(formClass);
73  		} else {
74  			formMeta = new FormMeta(formClass);
75  			m_formMap.put(formClass, formMeta);
76  		}
77  
78  		if (!formMeta.isAnnotationMetaCollected()) {
79  
80  			boolean autoBind = false;
81  
82  			if (formClass.isAnnotationPresent(Form.class)) {
83  				Form form = (Form) formClass.getAnnotation(Form.class);
84  				autoBind = form.autoBind();
85  			}
86  
87  			// temporary list to hold fields that have BoundComponent annotations
88  			List<Field> boundComponentFields = new ArrayList<Field>();
89  
90  			// retrieve public component's fields to find annotated fields
91  			Field[] fields = ClassManager.getClassInfo(formClass).getFields();
92  
93  			for (Field field : fields) {
94  				if (field.isAnnotationPresent(BoundComponent.class)) {
95  					boundComponentFields.add(field);
96  				} else if (field.isAnnotationPresent(ModelObject.class)) {
97  					ModelObject modelObject = field.getAnnotation(ModelObject.class);
98  					
99  					// SWI: remove "m_" if necessary
100 					String modelId = field.getName();
101 					if (modelId.startsWith("m_")) {
102 						modelId = modelId.substring(2);
103 					}
104 
105 					ErrorContext.put("- Processing Annotation for model object field " +
106 							field.getName() + " of type " + modelObject.getClass().getName());
107 
108 					if (modelObject.isDefault()) {
109 						ErrorContext.put("- Model Object is default");
110 						formMeta.putModelMeta("[default]", field);
111 					} else {
112 						ErrorContext.put("- Model Object is NOT default");
113 						formMeta.putModelMeta(modelId, field);
114 					}
115 
116 					Class modelObjectType = field.getType();
117 
118 					// autoBind if autoBind enabled. But, do not if ModelObject is a Map because fields do not yet exist
119 					if (autoBind && modelObject.autoBind() && !Map.class.isAssignableFrom(modelObjectType)) {
120 
121 						// iterate modelObject fields
122 
123 						ErrorContext.put("- AutoBind Model Object" + modelObjectType.getName());
124 
125 
126 						for (Method moMethod : ClassManager.getClassInfo(modelObjectType).getSetters()) {
127 
128 							String componentFieldName =
129 									moMethod.getName().substring(3, 4).toLowerCase() +
130 										moMethod.getName().substring(4);
131 
132 							Field formClassField = null;
133 							
134 							// SWI {
135 							// determine if corresponding field starts with m_...
136 							ErrorContext.put("- Attempting to lookup field " + componentFieldName);
137 							try {
138 								formClassField = ClassManager.getClassInfo(formClass).getField(componentFieldName);
139 							} catch (NoSuchFieldException e) {
140 								// ignored
141 							}
142 							try {
143 								formClassField = ClassManager.getClassInfo(formClass).getField("m_" + componentFieldName);
144 							} catch (NoSuchFieldException e) {
145 								// ignored
146 							}
147 							// } SWI
148 
149 							if (formClassField != null) {
150 								if (!formClassField.isAnnotationPresent(BoundComponent.class)) {
151 									ErrorContext.put("- Adding ComponentMeta for " + formClassField.getName() +
152 										" of type " + formClassField.getType().getName());
153 
154 									formMeta.addComponentMeta(
155 										modelObject.isDefault() ? "[default]" : modelId,
156 										componentFieldName, formClassField, void.class,
157 										new String[]{}, true, ReadOnly.DEFAULT,
158 										moMethod.getParameterTypes()[0]);
159 
160 									ErrorContext.removeLast();
161 
162 								}
163 							} else {
164 								ErrorContext.removeLast();
165 							}
166 						}
167 
168 
169 						ErrorContext.removeLast();
170 
171 					}
172 
173 					ErrorContext.removeLast();
174 
175 				}
176 			}
177 
178 			for (Field field : boundComponentFields) {
179 
180 				ErrorContext.put("processing BoundComponent field " + field.getName() + " of type " + field.getType().getName());
181 
182 				BoundComponent boundComponent = field.getAnnotation(BoundComponent.class);
183 				
184 				// SWI: remove "m_" if necessary
185 				String modelId = boundComponent.modelId();
186 				if (modelId.startsWith("m_")) {
187 					modelId = modelId.substring(2);
188 				}
189 
190 				formMeta.addComponentMeta(
191 						modelId,
192 						boundComponent.property().equals("[default]") ?
193 								field.getName() : boundComponent.property(),
194 						field, boundComponent.handler(),
195 						boundComponent.handlerValues(), false,
196 						boundComponent.readOnly(), boundComponent.type());
197 
198 				ErrorContext.removeLast();
199 
200 			}
201 
202 			formMeta.setAnnotationMetaCollected(true);
203 		}
204 
205 		ErrorContext.removeLast();
206 	}
207 
208 	public FormMeta getFormMeta(Class formClass) {
209 		FormMeta formMeta = null;
210 
211 		if (m_formMap.containsKey(formClass)) {
212 
213 			// if key exists retrieve meta for mapping
214 			formMeta = m_formMap.get(formClass);
215 
216 			ErrorContext.put("- FormMeta retrieved for " + formClass.getName());
217 
218 			// if annotaion metadata has not been collected
219 			if (!formMeta.isAnnotationMetaCollected())
220 				collectAnnotationMeta(formClass);
221 
222 		} else {
223 
224 			ErrorContext.put("- New FormMeta created for " + formClass.getName());
225 
226 			collectAnnotationMeta(formClass);
227 			formMeta = m_formMap.get(formClass);
228 
229 		}
230 
231 		return formMeta;
232 	}
233 }