KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > riotfamily > forms > factory > xml > XmlFormRepositoryDigester


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1
3  * The contents of this file are subject to the Mozilla Public License Version
4  * 1.1 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  * http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the
11  * License.
12  *
13  * The Original Code is Riot.
14  *
15  * The Initial Developer of the Original Code is
16  * Neteye GmbH.
17  * Portions created by the Initial Developer are Copyright (C) 2006
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  * Felix Gnass [fgnass at neteye dot de]
22  *
23  * ***** END LICENSE BLOCK ***** */

24 package org.riotfamily.forms.factory.xml;
25
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.riotfamily.common.beans.PropertyUtils;
35 import org.riotfamily.common.util.FormatUtils;
36 import org.riotfamily.common.web.file.FileStore;
37 import org.riotfamily.common.xml.DocumentDigester;
38 import org.riotfamily.common.xml.XmlUtils;
39 import org.riotfamily.forms.ContainerElement;
40 import org.riotfamily.forms.ElementFactory;
41 import org.riotfamily.forms.FormInitializer;
42 import org.riotfamily.forms.element.Calendar;
43 import org.riotfamily.forms.element.Checkbox;
44 import org.riotfamily.forms.element.ColorPicker;
45 import org.riotfamily.forms.element.EditableIfNew;
46 import org.riotfamily.forms.element.ElementGroup;
47 import org.riotfamily.forms.element.ImageCheckbox;
48 import org.riotfamily.forms.element.NestedForm;
49 import org.riotfamily.forms.element.NumberField;
50 import org.riotfamily.forms.element.PasswordField;
51 import org.riotfamily.forms.element.TextField;
52 import org.riotfamily.forms.element.Textarea;
53 import org.riotfamily.forms.element.TinyMCE;
54 import org.riotfamily.forms.element.XmlElement;
55 import org.riotfamily.forms.element.collection.ListEditor;
56 import org.riotfamily.forms.element.collection.MapEditor;
57 import org.riotfamily.forms.element.collection.XmlSequence;
58 import org.riotfamily.forms.element.select.CheckboxGroup;
59 import org.riotfamily.forms.element.select.ImageCheckboxGroup;
60 import org.riotfamily.forms.element.select.MultiSelectBox;
61 import org.riotfamily.forms.element.select.OptionsModel;
62 import org.riotfamily.forms.element.select.RadioButtonGroup;
63 import org.riotfamily.forms.element.select.SelectBox;
64 import org.riotfamily.forms.element.select.SelectElement;
65 import org.riotfamily.forms.element.select.StaticOptionsModel;
66 import org.riotfamily.forms.element.suggest.AutocompleteTextField;
67 import org.riotfamily.forms.element.upload.FileUpload;
68 import org.riotfamily.forms.element.upload.FlashUpload;
69 import org.riotfamily.forms.element.upload.ImageUpload;
70 import org.riotfamily.forms.factory.ConfigurableElementFactory;
71 import org.riotfamily.forms.factory.ContainerElementFactory;
72 import org.riotfamily.forms.factory.DefaultFormFactory;
73 import org.riotfamily.forms.factory.FormFactory;
74 import org.riotfamily.forms.factory.FormRepositoryException;
75 import org.springframework.beans.BeansException;
76 import org.springframework.beans.MutablePropertyValues;
77 import org.springframework.beans.factory.BeanFactory;
78 import org.springframework.core.io.Resource;
79 import org.springframework.util.Assert;
80 import org.springframework.util.xml.DomUtils;
81 import org.springframework.validation.Validator;
82 import org.w3c.dom.Attr JavaDoc;
83 import org.w3c.dom.Document JavaDoc;
84 import org.w3c.dom.Element JavaDoc;
85 import org.w3c.dom.NamedNodeMap JavaDoc;
86
87
88 /**
89  * Strategy for parsing a DOM that follows the form-config schema.
90  */

91 public class XmlFormRepositoryDigester implements DocumentDigester {
92
93     public static final String JavaDoc NAMESPACE = "http://www.riotfamily.org/schema/forms/form-config";
94
95     private Log log = LogFactory.getLog(XmlFormRepositoryDigester.class);
96
97     private BeanFactory beanFactory;
98
99     private XmlFormRepository formRepository;
100
101     private HashMap JavaDoc elementClasses = new HashMap JavaDoc();
102
103     private DefaultFormFactory formFactory;
104
105     private String JavaDoc formId;
106
107     private ArrayList JavaDoc imports;
108
109     private String JavaDoc currentPackage;
110
111     private Resource resource;
112
113     public XmlFormRepositoryDigester(XmlFormRepository formRepository,
114             BeanFactory beanFactory) {
115
116         this.formRepository = formRepository;
117         this.beanFactory = beanFactory;
118
119         elementClasses.put("group", ElementGroup.class);
120         elementClasses.put("textfield", TextField.class);
121         elementClasses.put("passwordfield", PasswordField.class);
122         elementClasses.put("numberfield", NumberField.class);
123         elementClasses.put("textarea", Textarea.class);
124         elementClasses.put("richtext", TinyMCE.class);
125         elementClasses.put("calendar", Calendar.class);
126         elementClasses.put("color-picker", ColorPicker.class);
127         elementClasses.put("checkbox", Checkbox.class);
128         elementClasses.put("imagecheckbox", ImageCheckbox.class);
129         elementClasses.put("nested-form", NestedForm.class);
130         elementClasses.put("list", ListEditor.class);
131         elementClasses.put("map", MapEditor.class);
132         elementClasses.put("multi-selectbox", MultiSelectBox.class);
133         elementClasses.put("selectbox", SelectBox.class);
134         elementClasses.put("radio-group", RadioButtonGroup.class);
135         elementClasses.put("checkbox-group", CheckboxGroup.class);
136         elementClasses.put("imagecheckbox-group", ImageCheckboxGroup.class);
137         elementClasses.put("file-upload", FileUpload.class);
138         elementClasses.put("image-upload", ImageUpload.class);
139         elementClasses.put("flash-upload", FlashUpload.class);
140         elementClasses.put("editable-if-new", EditableIfNew.class);
141         elementClasses.put("xml-element", XmlElement.class);
142         elementClasses.put("xml-sequence", XmlSequence.class);
143         elementClasses.put("autocomplete", AutocompleteTextField.class);
144     }
145
146     public void digest(Document JavaDoc doc, Resource resource) {
147         this.resource = resource;
148         formId = null;
149         imports = new ArrayList JavaDoc();
150         currentPackage = null;
151
152         Element root = doc.getDocumentElement();
153         Iterator JavaDoc it = XmlUtils.getChildElements(root).iterator();
154         while (it.hasNext()) {
155             Element ele = (Element) it.next();
156             String JavaDoc namespace = ele.getNamespaceURI();
157             if (namespace == null || namespace.equals(NAMESPACE)) {
158                 if (DomUtils.nodeNameEquals(ele, "form")) {
159                     parseFormDefinition(ele);
160                 }
161                 else if (DomUtils.nodeNameEquals(ele, "package")) {
162                     parsePackageDefinition(ele);
163                 }
164             }
165         }
166
167         it = imports.iterator();
168         while (it.hasNext()) {
169             ((Import) it.next()).apply();
170         }
171     }
172
173     protected void parseFormDefinition(Element formElement) {
174         formFactory = new DefaultFormFactory();
175         formId = formElement.getAttribute("id");
176
177         String JavaDoc beanClassName = XmlUtils.getAttribute(
178                 formElement, "bean-class");
179
180         formFactory.setBeanClass(getBeanClass(beanClassName));
181
182         formFactory.setInitializer((FormInitializer) getOrCreate(formElement,
183                 "initializer", "initializer-class",
184                 FormInitializer.class));
185
186         formFactory.setValidator((Validator) getOrCreate(formElement,
187                 "validator", "validator-class",
188                 Validator.class));
189
190
191         Iterator JavaDoc it = XmlUtils.getChildElements(formElement).iterator();
192         while (it.hasNext()) {
193             parseElementDefinition((Element) it.next(), formFactory);
194         }
195         formRepository.registerFormFactory(formId, formFactory);
196     }
197
198     
199     private Object JavaDoc getOrCreate(Element element, String JavaDoc refAttribute,
200             String JavaDoc classNameAttribute, Class JavaDoc requiredClass) {
201
202         String JavaDoc ref = XmlUtils.getAttribute(
203                 element, refAttribute);
204
205         if (ref != null) {
206             return beanFactory.getBean(ref, requiredClass);
207         }
208         else {
209             String JavaDoc className = XmlUtils.getAttribute(
210                 element, classNameAttribute);
211
212             if (className != null) {
213                 Object JavaDoc obj = PropertyUtils.newInstance(className);
214                 Assert.isInstanceOf(requiredClass, obj);
215                 return obj;
216             }
217         }
218         return null;
219     }
220
221     
222     protected void parsePackageDefinition(Element ele) {
223         currentPackage = XmlUtils.getAttribute(ele, "name");
224         Iterator JavaDoc it = DomUtils.getChildElementsByTagName(
225                 ele, "form").iterator();
226
227         while (it.hasNext()) {
228             parseFormDefinition((Element) it.next());
229         }
230     }
231
232     
233     protected void parseElementDefinition(Element ele,
234             ContainerElementFactory parentFactory) {
235
236         if (DomUtils.nodeNameEquals(ele, "import")) {
237             String JavaDoc formId = ele.getAttribute("form");
238             imports.add(new Import(formId, parentFactory));
239         }
240         else {
241             ConfigurableElementFactory factory = createFactory(ele);
242             parentFactory.addChildFactory(factory);
243         }
244     }
245
246     
247     protected ConfigurableElementFactory createFactory(Element ele) {
248         Class JavaDoc elementClass = getElementClass(ele);
249         ConfigurableElementFactory factory =
250                 new ConfigurableElementFactory(elementClass);
251
252         factory.setBeanFactory(beanFactory);
253         String JavaDoc beanClassName = XmlUtils.getAttribute(ele, "bean-class");
254         if (beanClassName != null) {
255             factory.setBeanClass(getBeanClass(beanClassName));
256         }
257         factory.setBind(XmlUtils.getAttribute(ele, "bind"));
258
259         MutablePropertyValues pvs = getPropertyValues(ele);
260
261         if (SelectElement.class.isAssignableFrom(elementClass)) {
262             initSelectElement(ele, pvs);
263         }
264         else if (Checkbox.class.isAssignableFrom(elementClass)) {
265             initCheckbox(ele, pvs);
266         }
267         else if (ImageUpload.class.isAssignableFrom(elementClass)) {
268             initImageUpload(ele, pvs);
269         }
270         else if (FileUpload.class.isAssignableFrom(elementClass)) {
271             initFileUpload(ele, pvs);
272         }
273         else if (MapEditor.class.isAssignableFrom(elementClass)) {
274             initMapEditor(ele, pvs);
275         }
276         else if (ListEditor.class.isAssignableFrom(elementClass)) {
277             initListEditor(ele, pvs);
278         }
279         else if (AutocompleteTextField.class.isAssignableFrom(elementClass)) {
280             initAutocompleteTextField(ele, pvs);
281         }
282
283         factory.setPropertyValues(pvs);
284
285         if (ContainerElement.class.isAssignableFrom(elementClass)) {
286             Iterator JavaDoc it = XmlUtils.getChildElements(ele).iterator();
287             while (it.hasNext()) {
288                 parseElementDefinition((Element) it.next(), factory);
289             }
290         }
291
292         return factory;
293     }
294
295     private void initSelectElement(Element ele, MutablePropertyValues pvs) {
296         log.debug("Looking for OptionsModel ...");
297         Element modelElement = XmlUtils.getFirstChildByRegex(ele, "model|options");
298         OptionsModel model = getOptionsModel(modelElement);
299         if (model != null) {
300             log.debug("OptionsModel: " + model);
301             pvs.addPropertyValue("optionsModel", model);
302         }
303     }
304     
305     private void initCheckbox(Element ele, MutablePropertyValues pvs) {
306         pvs.removePropertyValue("default");
307         if ("checked".equals(XmlUtils.getAttribute(ele, "default"))) {
308             pvs.addPropertyValue("checkedByDefault", Boolean.TRUE);
309         }
310     }
311     
312     private void initFileUpload(Element ele, MutablePropertyValues pvs) {
313         pvs.removePropertyValue("store");
314         String JavaDoc ref = XmlUtils.getAttribute(ele, "store");
315         if (ref != null) {
316             FileStore fileStore = (FileStore) beanFactory.getBean(
317                     ref, FileStore.class);
318
319             pvs.addPropertyValue("fileStore", fileStore);
320         }
321
322         if (formRepository.getMimetypesMap() != null) {
323             pvs.addPropertyValue("mimetypesMap",
324                     formRepository.getMimetypesMap());
325         }
326     }
327     
328     private void initImageUpload(Element ele, MutablePropertyValues pvs) {
329         initFileUpload(ele, pvs);
330         pvs.addPropertyValue("cropper", formRepository.getImageCropper());
331     }
332     
333     private void initListEditor(Element ele, MutablePropertyValues pvs) {
334         Element itemElement = XmlUtils.getFirstChildElement(ele);
335         ElementFactory itemFactory = createFactory(itemElement);
336         pvs.addPropertyValue("itemElementFactory", itemFactory);
337     }
338     
339     private void initMapEditor(Element ele, MutablePropertyValues pvs) {
340         Element keyElement = XmlUtils.getFirstChildElement(ele);
341         if (DomUtils.nodeNameEquals(keyElement, "key-element")) {
342             ElementFactory factory = createFactory(XmlUtils.getFirstChildElement(keyElement));
343             pvs.addPropertyValue("keyElementFactory", factory);
344         }
345         else {
346             pvs.addPropertyValue("keyOptionsModel", getOptionsModel(keyElement));
347         }
348         Element itemElement = XmlUtils.getNextSiblingElement(keyElement);
349         ElementFactory itemFactory = createFactory(itemElement);
350         pvs.addPropertyValue("itemElementFactory", itemFactory);
351     }
352     
353     private void initAutocompleteTextField(Element ele, MutablePropertyValues pvs) {
354         pvs.addPropertyValue("model", beanFactory.getBean(
355                 XmlUtils.getAttribute(ele, "model")));
356     }
357
358     protected Class JavaDoc getElementClass(Element ele) {
359         String JavaDoc type = null;
360         if (DomUtils.nodeNameEquals(ele, "element")) {
361             type = XmlUtils.getAttribute(ele, "type");
362         }
363         else {
364             String JavaDoc namespace = ele.getNamespaceURI();
365             if (namespace == null || namespace.equals(NAMESPACE)) {
366                 type = XmlUtils.getLocalName(ele);
367             }
368             else {
369                 type = '{' + namespace + '}' + ele.getLocalName();
370             }
371         }
372         return getElementClass(type);
373     }
374
375     protected Class JavaDoc getElementClass(String JavaDoc type) {
376         Class JavaDoc elementClass = (Class JavaDoc) elementClasses.get(type);
377         if (elementClass == null) {
378             elementClass = formRepository.getElementClass(type);
379         }
380         if (elementClass == null) {
381             throw new FormRepositoryException(resource, formId,
382                     "Unknown element type: " + type);
383         }
384         return elementClass;
385     }
386
387     protected Class JavaDoc getBeanClass(String JavaDoc beanClassName) {
388         if (beanClassName == null) {
389             return formRepository.getDefaultBeanClass();
390         }
391         if (beanClassName.indexOf('.') == -1 && currentPackage != null) {
392             beanClassName = currentPackage + '.' + beanClassName;
393         }
394         try {
395             return Class.forName(beanClassName);
396         }
397         catch (ClassNotFoundException JavaDoc e) {
398             throw new FormRepositoryException(resource, formId,
399                     "beanClass not found", e);
400         }
401     }
402
403     protected MutablePropertyValues getPropertyValues(Element element) {
404         MutablePropertyValues pvs = new MutablePropertyValues();
405
406         NamedNodeMap JavaDoc attrs = element.getAttributes();
407         for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
408             Attr JavaDoc attr = (Attr JavaDoc) attrs.item(i);
409             String JavaDoc name = attr.getName();
410             if (!"bind".equals(name)
411                     && !"type".equals(name)
412                     && !"bean-class".equals(name)) {
413
414                 String JavaDoc property = FormatUtils.xmlToCamelCase(attr.getName());
415                 log.debug("Setting property " + property + " to " + attr.getValue());
416                 pvs.addPropertyValue(property, attr.getValue());
417             }
418         }
419
420         Iterator JavaDoc it = XmlUtils.getChildElementsByRegex(
421                 element, "property|set-property").iterator();
422
423         while (it.hasNext()) {
424             Element ele = (Element) it.next();
425             String JavaDoc name = XmlUtils.getAttribute(ele, "name");
426
427             Object JavaDoc value = null;
428
429             String JavaDoc beanName = XmlUtils.getAttribute(ele, "ref");
430             if (beanName != null) {
431                 value = beanFactory.getBean(beanName);
432             }
433             else {
434                 value = XmlUtils.getAttribute(ele, "value");
435             }
436
437             pvs.addPropertyValue(name, value);
438         }
439
440         return pvs;
441     }
442
443     private OptionsModel getOptionsModel(Element ele) {
444         OptionsModel model = null;
445         if (ele != null) {
446             String JavaDoc className = XmlUtils.getAttribute(ele, "class");
447             if (className != null) {
448                 try {
449                     model = (OptionsModel) PropertyUtils.newInstance(className);
450                 }
451                 catch (BeansException e) {
452                     throw new FormRepositoryException(resource, formId,
453                             "Error creating OptionsModel", e);
454                 }
455             }
456             else {
457                 String JavaDoc beanName = XmlUtils.getAttribute(ele, "ref");
458                 if (beanName != null) {
459                     model = getOptionsModel(beanName);
460                 }
461             }
462             if (model != null) {
463                 List JavaDoc setPropElements = XmlUtils.getChildElementsByRegex(
464                         ele, "property|set-property");
465
466                 XmlUtils.populate(model, setPropElements, beanFactory);
467             }
468         }
469         return model;
470     }
471
472     private OptionsModel getOptionsModel(String JavaDoc beanName) {
473         Object JavaDoc bean = beanFactory.getBean(beanName);
474         if (bean instanceof OptionsModel) {
475             return (OptionsModel) bean;
476         }
477         else if (bean instanceof Collection JavaDoc) {
478             return new StaticOptionsModel((Collection JavaDoc) bean);
479         }
480         else {
481             throw new FormRepositoryException(resource, formId,
482                     "Bean [" + beanName + "] is neither an " +
483                     "OptionsModel nor a Collection: " + bean);
484         }
485     }
486
487     private class Import {
488
489         private ContainerElementFactory parent;
490
491         private int insertAt;
492
493         private String JavaDoc formId;
494
495         Import(String JavaDoc formId, ContainerElementFactory parent) {
496             this.formId = formId;
497             this.parent = parent;
498             insertAt = parent.getChildFactories().size();
499         }
500
501         public void apply() {
502             FormFactory formFactory = formRepository.getFormFactory(formId);
503             parent.getChildFactories().addAll(insertAt,
504                     formFactory.getChildFactories());
505         }
506
507     }
508
509 }
510
Popular Tags