View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package com.tapas.evidence.fe.form;
20  
21  import java.lang.reflect.Constructor;
22  import java.lang.reflect.InvocationTargetException;
23  import java.util.Collection;
24  import java.util.Locale;
25  
26  import lombok.extern.slf4j.Slf4j;
27  
28  import org.springframework.validation.BeanPropertyBindingResult;
29  import org.springframework.validation.BindingResult;
30  import org.springframework.validation.FieldError;
31  import org.springframework.validation.Validator;
32  import org.vaadin.mvp.uibinder.IUiMessageSource;
33  
34  import com.vaadin.data.util.BeanItem;
35  import com.vaadin.data.util.NestedMethodProperty;
36  import com.vaadin.terminal.UserError;
37  import com.vaadin.ui.AbstractField;
38  import com.vaadin.ui.Component;
39  import com.vaadin.ui.Field;
40  import com.vaadin.ui.Form;
41  import com.vaadin.ui.FormFieldFactory;
42  
43  /**
44   * @author Michal Bocek
45   * @since 1.0.0
46   */
47  @Slf4j
48  public class EvidenceForm extends Form {
49  
50  	private static final String MISSING_MESSAGE = "{{missing message: ";
51  
52  	private static final long serialVersionUID = 1L;
53  
54  	private static final String NESTED_SEPARATOR = ".";
55  	
56  	public void addFooter(final Component component) {
57  		this.getFooter().addComponent(component);
58  	}
59  
60  	public void setItemDataSource(final Model model, final MetaModel metaModel, final IUiMessageSource messageSource,
61  			final String messagePrefix, final Locale locale) {
62  		final BeanItem<Model> beanItem = new BeanItem<Model>(model);
63  		for (FieldInfo fieldInfo : metaModel.getFieldInfos()) {
64  			if (fieldInfo.isNested()) {
65  				beanItem.addItemProperty(fieldInfo.getFieldNestedName(),
66  						new NestedMethodProperty(model, fieldInfo.getFieldNestedName())); // NOPMD
67  			}
68  		}
69  		this.setItemDataSource(beanItem);
70  		setupFormFieldFactory(model, metaModel, messageSource, locale);
71  		this.setVisibleItemProperties(metaModel.getOrderedFields());
72  		for (String fieldName : metaModel.getCaptionedFields()) {
73  			log.trace("Processing caption for field:{}", fieldName);
74  			final String fieldCaption = messagePrefix + NESTED_SEPARATOR + metaModel.getFieldCaption(fieldName);
75  			final Field field = this.getField(fieldName);
76  			field.setCaption(messageSource.getMessage(fieldCaption, locale));
77  		}
78  		for (String fieldName : metaModel.getRequiredFields()) {
79  			log.trace("Processing required for field:{}", fieldName);
80  			final Boolean fieldRequired = metaModel.getFieldRequired(fieldName);
81  			final Field field = this.getField(fieldName);
82  			log.trace("Field:{} is required:{}", fieldName, fieldRequired);
83  			if (field != null) {
84  				field.setRequired(fieldRequired);
85  				field.setRequiredError(messageSource.getMessage("field.required", locale));
86  			} else {
87  				log.trace("Field: {} doesnt exists and will be skiped!", fieldName);
88  			}
89  		}
90  	}
91  
92  	public boolean validate(final MetaModel metaModel, final Validator validator, final Model model,
93  			final IUiMessageSource messageSource, final Locale locale) {
94  		boolean result = false; 
95  		final BindingResult validationResult = new BeanPropertyBindingResult(model, model.getClass().getName());
96  		clearFields(metaModel);
97  		validator.validate(model, validationResult);
98  		if (validationResult.hasErrors()) {
99  			for (FieldError error : validationResult.getFieldErrors()) {
100 				final String field = error.getField();
101 				final String message = getMessage(error.getCodes(), messageSource, locale);
102 				final Field fieldComponent = this.getField(field);
103 				if (fieldComponent instanceof AbstractField) {
104 					((AbstractField)fieldComponent).setComponentError(new UserError(message));
105 				}
106 			}
107 			result = false;
108 		} else {
109 			result = true;
110 		}
111 		return result;		
112 	}
113 	
114 	private String getMessage(final String[] codes, final IUiMessageSource messageSource, final Locale locale) {
115 		String result = null; 
116 		for (String code : codes) {
117 			result = messageSource.getMessage(code, locale);
118 			if (result != null && !result.startsWith(MISSING_MESSAGE)) {
119 				break;
120 			}
121 		}
122 		return result;
123 	}
124 
125 	private void clearFields(final MetaModel metaModel) {
126 		final Collection<String> validatedFields = metaModel.getValidatedFields();
127 		for (String fieldName : validatedFields) {
128 			final boolean isFieldValidated = metaModel.getFieldValidated(fieldName);
129 			log.trace("Field: {} will be validated: {}", fieldName, isFieldValidated);
130 			if (isFieldValidated) {
131 				final Field fieldComponent = this.getField(fieldName);
132 				if (fieldComponent instanceof AbstractField) {
133 					log.trace("Cleanup error for field:{}", fieldName);
134 					((AbstractField)fieldComponent).setComponentError(null);
135 				}
136 			}
137 		}
138 	}
139 
140 	private void setupFormFieldFactory(final Model model, final MetaModel metaModel, final IUiMessageSource messageSource, final Locale locale) {
141 		final Class<? extends FormFieldFactory> formFieldFactory = metaModel.getFormFieldFactory();
142 		if (formFieldFactory != null) {
143 			try {
144 				final Constructor<? extends FormFieldFactory> constructor = formFieldFactory
145 						.getConstructor(new Class[] { IUiMessageSource.class, Locale.class });
146 				final EvidenceFormFieldFactory instance = (EvidenceFormFieldFactory) constructor
147 						.newInstance(new Object[] { messageSource, locale });
148 				this.setFormFieldFactory(instance);
149 			} catch (InstantiationException e) {
150 				throw new EvidenceFormException("InstantiationException for " + formFieldFactory.getName(), e);
151 			} catch (IllegalAccessException e) {
152 				throw new EvidenceFormException("IllegalAccessException for " + formFieldFactory.getName(), e);
153 			} catch (SecurityException e) {
154 				throw new EvidenceFormException("SecurityException for " + formFieldFactory.getName(), e);
155 			} catch (NoSuchMethodException e) {
156 				throw new EvidenceFormException("NoSuchMethodException for " + formFieldFactory.getName(), e);
157 			} catch (IllegalArgumentException e) {
158 				throw new EvidenceFormException("IllegalArgumentException for " + formFieldFactory.getName(), e);
159 			} catch (InvocationTargetException e) {
160 				throw new EvidenceFormException("InvocationTargetException for " + formFieldFactory.getName(), e);
161 			}
162 		}
163 	}
164 }