/** * Copyright 2013 Tommi S.E. Laukkanen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bubblecloud.ilves.component.grid; import com.vaadin.data.Validator; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.validator.StringLengthValidator; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Field; import com.vaadin.ui.TextField; import org.bubblecloud.ilves.component.field.TimestampField; import org.bubblecloud.ilves.component.formatter.ObjectConverter; import org.bubblecloud.ilves.component.formatter.TimestampConverter; import org.bubblecloud.ilves.util.StringUtil; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; /** * Value object containing set of field descriptors. * * @author Tommi S.E. Laukkanen */ public final class FieldSetDescriptor { /** * The field descriptors. */ private List<FieldDescriptor> fieldDescriptors = new ArrayList<FieldDescriptor>(); private List<FieldDescriptor> visibleFieldDescriptors; /** * Constructs field set descriptor from bean class. * * @param beanClass the bean class */ public FieldSetDescriptor(final Class<?> beanClass) { // Try to introspect, if it fails, we just have an empty Item try { List<PropertyDescriptor> propertyDescriptors = getBeanPropertyDescriptor(beanClass); // Add all the bean properties as MethodProperties to this Item // later entries on the list overwrite earlier ones for (PropertyDescriptor pd : propertyDescriptors) { final Method getMethod = pd.getReadMethod(); if ((getMethod != null) && getMethod.getDeclaringClass() != Object.class) { final String fieldId = pd.getName(); final String labelKey = "field-" + StringUtil.fromCamelCaseToLocalizationKeyConvetion(fieldId); final Class<?> valueType = pd.getPropertyType(); final Class<? extends Field> fieldClass; final Converter<?,?> converter; final int width; final HorizontalAlignment valueAlignment; final Object defaultValue; final boolean readOnly = pd.getWriteMethod() == null; final boolean required; final List<Validator> validators = new ArrayList<Validator>(); if (valueType.equals(String.class)) { fieldClass = TextField.class; converter = null; width = 150; valueAlignment = HorizontalAlignment.LEFT; defaultValue = null; required = true; validators.add(new StringLengthValidator("Invalid length.", 0, 255, true)); } else if (valueType.equals(Integer.class)) { fieldClass = TextField.class; converter = null; width = 80; valueAlignment = HorizontalAlignment.LEFT; defaultValue = null; required = true; } else if (valueType.equals(Long.class)) { fieldClass = TextField.class; converter = null; width = 80; valueAlignment = HorizontalAlignment.LEFT; defaultValue = null; required = true; } else if (valueType.equals(Boolean.class)) { fieldClass = CheckBox.class; converter = null; width = 50; valueAlignment = HorizontalAlignment.LEFT; defaultValue = null; required = true; } else if (valueType.equals(Date.class)) { fieldClass = TimestampField.class; converter = new TimestampConverter(); width = 180; valueAlignment = HorizontalAlignment.LEFT; defaultValue = null; required = true; } else { fieldClass = TextField.class; converter = new ObjectConverter(); width = 100; valueAlignment = HorizontalAlignment.LEFT; defaultValue = null; required = false; } final boolean sortable = true; final FieldDescriptor fieldDescriptor = new FieldDescriptor( fieldId, labelKey, fieldClass, converter, width, valueAlignment, valueType, defaultValue, readOnly, sortable, required ); for (final Validator validator : validators) { fieldDescriptor.addValidator(validator); } fieldDescriptors.add(fieldDescriptor); } } visibleFieldDescriptors = fieldDescriptors; } catch (final java.beans.IntrospectionException ignored) { } } public void setVisibleFieldIds(final String[] visibleFieldIds) { visibleFieldDescriptors = new ArrayList<FieldDescriptor>(); for (final String visibleFieldId : visibleFieldIds) { for (final FieldDescriptor fieldDescriptor : fieldDescriptors) { if (fieldDescriptor.getId().equals(visibleFieldId)) { visibleFieldDescriptors.add(fieldDescriptor); } } } } /** * @return fieldDescriptors */ public List<FieldDescriptor> getFieldDescriptors() { return visibleFieldDescriptors; } /** * Gets field descriptor based on fieldId. * @param fieldId the fieldId * @return the field descriptor. */ public FieldDescriptor getFieldDescriptor(final String fieldId) { for (final FieldDescriptor fieldDescriptor : fieldDescriptors) { if (fieldDescriptor.getId().equals(fieldId)) { return fieldDescriptor; } } throw new IllegalArgumentException("No such field id: " + fieldId); } /** * Returns the property descriptors of a class or an interface. * * For an interface, superinterfaces are also iterated as Introspector does * not take them into account (Oracle Java bug 4275879), but in that case, * both the setter and the getter for a property must be in the same * interface and should not be overridden in subinterfaces for the discovery * to work correctly. * * For interfaces, the iteration is depth first and the properties of * superinterfaces are returned before those of their subinterfaces. * * @param beanClass the bean class * @return list of property descriptors * @throws java.beans.IntrospectionException if exception occurs in introspection */ private static List<PropertyDescriptor> getBeanPropertyDescriptor( final Class<?> beanClass) throws IntrospectionException { if (beanClass.isInterface()) { List<PropertyDescriptor> propertyDescriptors = new ArrayList<PropertyDescriptor>(); for (Class<?> cls : beanClass.getInterfaces()) { propertyDescriptors.addAll(getBeanPropertyDescriptor(cls)); } BeanInfo info = Introspector.getBeanInfo(beanClass); propertyDescriptors.addAll(Arrays.asList(info .getPropertyDescriptors())); return propertyDescriptors; } else { BeanInfo info = Introspector.getBeanInfo(beanClass); return Arrays.asList(info.getPropertyDescriptors()); } } }