name.martingeisse.wicket.autoform.AutoformPanel.java Source code

Java tutorial

Introduction

Here is the source code for name.martingeisse.wicket.autoform.AutoformPanel.java

Source

/**
 * Copyright (c) 2011 Martin Geisse
 *
 * This file is distributed under the terms of the MIT license.
 */

package name.martingeisse.wicket.autoform;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import name.martingeisse.wicket.autoform.annotation.validation.AutoformAssociatedValidator;
import name.martingeisse.wicket.autoform.annotation.validation.AutoformValidator;
import name.martingeisse.wicket.autoform.componentfactory.IAutoformPropertyComponentFactory;
import name.martingeisse.wicket.autoform.describe.IAutoformBeanDescriber;
import name.martingeisse.wicket.autoform.describe.IAutoformBeanDescriptor;
import name.martingeisse.wicket.autoform.describe.IAutoformPropertyDescriptor;
import name.martingeisse.wicket.autoform.validation.IValidationErrorAcceptor;
import name.martingeisse.wicket.panel.MultiComponentFeedbackPanel;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.ComponentFeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.apache.wicket.validation.IValidator;

/**
 * Default autoform panel.
 */
public class AutoformPanel extends Panel {

    /**
     * the beanDescriptor
     */
    private final IAutoformBeanDescriptor beanDescriptor;

    /**
     * the propertyComponentFactory
     */
    private final IAutoformPropertyComponentFactory propertyComponentFactory;

    /**
     * Constructor.
     * @param id the wicket id
     * @param bean the bean to show in the autoform
     * @param beanDescriber the bean describer that extracts meta-data from the bean
     * @param propertyComponentFactory the factory used to create components for the bean properties
     */
    public AutoformPanel(final String id, final Serializable bean, final IAutoformBeanDescriber beanDescriber,
            final IAutoformPropertyComponentFactory propertyComponentFactory) {
        super(id, Model.of(bean));
        this.beanDescriptor = beanDescriber.describe(bean);
        this.propertyComponentFactory = propertyComponentFactory;
        createComponents();
    }

    /**
     * 
     */
    private void createComponents() {

        // create the form component
        final Form<?> form = new Form<Void>("form") {
            @Override
            protected void onSubmit() {
                AutoformPanel.this.onSuccessfulSubmit();
            }
        };
        add(form);

        // create the property repeater
        final ListView<IAutoformPropertyDescriptor> rows = new ListView<IAutoformPropertyDescriptor>("rows",
                beanDescriptor.getPropertyDescriptors()) {

            /* (non-Javadoc)
             * @see org.apache.wicket.markup.html.list.ListView#populateItem(org.apache.wicket.markup.html.list.ListItem)
             */
            @Override
            protected void populateItem(final ListItem<IAutoformPropertyDescriptor> item) {
                final IAutoformPropertyDescriptor propertyDescriptor = item.getModelObject();
                item.add(new Label("keyLabel", propertyDescriptor.getDisplayName()));
                item.add(propertyComponentFactory.createPropertyComponent("valueComponent", propertyDescriptor,
                        createValidators(propertyDescriptor), new ValidationErrorAcceptor(item)));
            }

        };
        rows.setReuseItems(true);
        form.add(rows);

    }

    /**
     *
     */
    private static class ValidationErrorAcceptor implements IValidationErrorAcceptor {

        /**
         * the item
         */
        private final ListItem<IAutoformPropertyDescriptor> item;

        /**
         * Constructor.
         */
        ValidationErrorAcceptor(final ListItem<IAutoformPropertyDescriptor> item) {
            this.item = item;
        }

        /* (non-Javadoc)
         * @see name.martingeisse.wicket.autoform.validation.IValidationErrorAcceptor#acceptValidationErrorsFrom(org.apache.wicket.Component)
         */
        @Override
        public void acceptValidationErrorsFrom(final Component component) {
            item.add(new ComponentFeedbackPanel("errorMessage", component));
        }

        /* (non-Javadoc)
         * @see name.martingeisse.wicket.autoform.validation.IValidationErrorAcceptor#acceptValidationErrorsFromMultiple(org.apache.wicket.Component[])
         */
        @Override
        public void acceptValidationErrorsFromMultiple(Component... components) {
            item.add(new MultiComponentFeedbackPanel("errorMessage", components));
        }

    }

    /**
     * @param property
     * @return
     */
    private IValidator<?>[] createValidators(final IAutoformPropertyDescriptor property) {
        final List<IValidator<?>> validators = new ArrayList<IValidator<?>>();

        // check for AutoformValidator
        final AutoformValidator autoformValidatorAnnotation = property.getAnnotation(AutoformValidator.class);
        if (autoformValidatorAnnotation != null) {
            for (final Class<? extends IValidator<?>> validatorClass : autoformValidatorAnnotation.value()) {
                try {
                    validators.add(validatorClass.newInstance());
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        // check for annotations tagged with AutoformAssociatedValidator
        for (final Annotation annotation : property.getAnnotations()) {
            final Class<? extends Annotation> annotationType = annotation.annotationType();
            final AutoformAssociatedValidator associatedValidatorAnnotation = annotationType
                    .getAnnotation(AutoformAssociatedValidator.class);
            if (associatedValidatorAnnotation != null) {
                try {
                    final Class<? extends IValidator<?>> validatorClass = associatedValidatorAnnotation.value();
                    final Constructor<? extends IValidator<?>> constructor = validatorClass
                            .getConstructor(annotationType);
                    if (constructor == null) {
                        throw new IllegalStateException("associated validator class " + validatorClass
                                + " has no constructor(" + annotationType + ")");
                    }
                    validators.add(constructor.newInstance(annotation));
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        return validators.toArray(new IValidator<?>[validators.size()]);
    }

    /**
     * Getter method for the beanDescriptor.
     * @return the beanDescriptor
     */
    public IAutoformBeanDescriptor getBeanDescriptor() {
        return beanDescriptor;
    }

    /**
     * @return the form used by this autoform panel
     */
    public Form<?> getForm() {
        return (Form<?>) get("form");
    }

    /**
     * This method is invoked when the user successfully submits the form (i.e. without validation errors).
     * The default implementation does nothing.
     */
    protected void onSuccessfulSubmit() {
    }

}