nz.co.senanque.vaadinsupport.application.MaduraSessionManager.java Source code

Java tutorial

Introduction

Here is the source code for nz.co.senanque.vaadinsupport.application.MaduraSessionManager.java

Source

/*******************************************************************************
 * Copyright (c)2014 Prometheus Consulting
 *
 * 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 nz.co.senanque.vaadinsupport.application;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.PreDestroy;

import nz.co.senanque.localemanagement.LocaleAwareRuntimeException;
import nz.co.senanque.vaadinsupport.ButtonPainter;
import nz.co.senanque.vaadinsupport.ButtonProperty;
import nz.co.senanque.vaadinsupport.CommandExt;
import nz.co.senanque.vaadinsupport.FieldFactory;
import nz.co.senanque.vaadinsupport.Hints;
import nz.co.senanque.vaadinsupport.LabelProperty;
import nz.co.senanque.vaadinsupport.MaduraForm;
import nz.co.senanque.vaadinsupport.MaduraPropertyWrapper;
import nz.co.senanque.vaadinsupport.MenuItemPainter;
import nz.co.senanque.vaadinsupport.permissionmanager.PermissionManager;
import nz.co.senanque.validationengine.FieldMetadata;
import nz.co.senanque.validationengine.ObjectMetadata;
import nz.co.senanque.validationengine.ProxyField;
import nz.co.senanque.validationengine.ValidationEngine;
import nz.co.senanque.validationengine.ValidationObject;
import nz.co.senanque.validationengine.ValidationSession;
import nz.co.senanque.validationengine.choicelists.ChoiceBase;
import nz.co.senanque.validationengine.metadata.PropertyMetadata;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.i18n.LocaleContextHolder;

import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.terminal.UserError;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Field;
import com.vaadin.ui.Label;
import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;

/**
 * 
 * All of the Madura session management is done here. You register fields (or whole forms) with the manager.
 * Then you bind specific instances of the object graph to these fields.
 * There is one of these per Madura Session
 * 
 * @author Roger Parkinson
 * @version $Revision:$
 */
public class MaduraSessionManager implements Serializable, MessageSourceAware, InitializingBean {
    private static final long serialVersionUID = 1415805577188960471L;
    private static Logger logger = LoggerFactory.getLogger(MaduraSessionManager.class);
    private Map<Integer, AbstractField> m_fields = new HashMap<>();
    private Map<Integer, Label> m_labels = new HashMap<>();
    @Autowired(required = false)
    private transient ValidationEngine m_validationEngine;
    private transient ValidationSession m_validationSession;
    @Autowired
    private transient FieldFactory m_formFieldFactory;
    @Autowired
    transient PermissionManager m_permissionManager;
    @Autowired
    private transient Hints m_hints;
    private transient MessageSource m_messageSource;

    private class MenuItemWrapper extends AbstractField {

        private static final long serialVersionUID = 418011465566857902L;
        private final MenuItemPainter m_menuItemPainter;

        public Class<?> getType() {
            return null;
        }

        private MenuItemWrapper(MenuItem menuItem, MenuItemPainter menuItemPainter) {
            m_menuItemPainter = menuItemPainter;
            setData(menuItem);
        }

        public MenuItemPainter getMenuItemPainter() {
            return m_menuItemPainter;
        }
    }

    private void registerWidget(AbstractField field) {
        int key = System.identityHashCode(field);
        if (m_fields.get(key) == null) {
            m_fields.put(key, field);
            //         logger.debug("MaduraSessionManager {} Registering field {} {}",getValidationEngine().getIdentifier(),key,field.getCaption());
        }
    }

    private void registerWidget(MenuItem field, MenuItemPainter bp) {
        Collection<AbstractField> fields = getFields();
        for (AbstractField foundField : fields) {
            if (foundField instanceof MenuItemWrapper) {
                MenuItemWrapper menuItemWrapper = (MenuItemWrapper) foundField;
                if (menuItemWrapper.getMenuItemPainter() == bp) {
                    // we found this item already in the list so reuse it
                    // rather than create a new entry. This saves us having to deregister and
                    // recreate whenever the menu reconfigures.
                    menuItemWrapper.setData(field);
                    return;
                }
            }
        }
        registerWidget(new MenuItemWrapper(field, bp));
    }

    public void register(Label field) {
        int key = System.identityHashCode(field);
        if (m_labels.get(key) == null) {
            m_labels.put(key, field);
        }
    }

    public void deregister(AbstractComponent field) {
        m_fields.remove(System.identityHashCode(field));
        m_labels.remove(System.identityHashCode(field));
    }

    /**
     * Check all the other fields to ensure they are still valid
     * this includes any buttons that were registered because they
     * get disabled if there are errors on the relevant form or
     * if the requiredness is incomplete.
     * 
     * @param field
     */
    public void updateOtherFields(AbstractField field) {
        PermissionManager permissionmanager = getPermissionManager();
        Collection<AbstractField> fields = getFields();
        Collection<Label> labels = getLabels();
        for (Label fieldx : labels) {
            com.vaadin.data.Property p = fieldx.getPropertyDataSource();
            if (p != null && p instanceof LabelProperty) {
                fieldx.requestRepaint();
            }
        }
        for (AbstractField fieldx : fields) {
            if (fieldx.equals(field))
                continue;
            if ((fieldx instanceof Button) && !(fieldx instanceof CheckBox)) {
                com.vaadin.data.Property p = fieldx.getPropertyDataSource();
                if (p != null && p instanceof ButtonProperty) {
                    ((ButtonProperty) p).getPainter().paint((Button) fieldx);
                    fieldx.requestRepaint();
                }
                continue;
            }
            if (fieldx instanceof MenuItemWrapper) {
                MenuItemPainter menuItemPainter = ((MenuItemWrapper) fieldx).getMenuItemPainter();
                MenuItem menuItem = (MenuItem) fieldx.getData();
                if (menuItemPainter != null) {
                    menuItemPainter.paint(menuItem);
                    fieldx.requestRepaint();
                }
                continue;
            }
            MaduraPropertyWrapper property = null;
            try {
                property = (MaduraPropertyWrapper) fieldx.getPropertyDataSource();
            } catch (Exception e) {
                // ignore
                property = null;
            }
            if (property != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("evaluating field: {}", property.getName());
                    if (fieldx.isEnabled() != property.isEnabled()) {
                        logger.debug("Enabled: {} {}", fieldx.isEnabled(), property.isEnabled());
                    }
                    if (fieldx.isReadOnly() != property.isReadOnly()) {
                        logger.debug("ReadOnly: {} {}", fieldx.isReadOnly(), property.isReadOnly());
                    }
                    if (fieldx.isRequired() != property.isRequired()) {
                        logger.debug("Required: {} {}", fieldx.isRequired(), property.isRequired());
                    }
                    if (fieldx.isVisible() != property.isVisible()) {
                        logger.debug("Visible: {} {}", fieldx.isVisible(), property.isVisible());
                    }
                }
                fieldx.setEnabled(property.isEnabled());
                fieldx.setReadOnly(property.isReadOnly());
                fieldx.setRequired(property.isRequired());
                fieldx.setVisible(property.isVisible());
                // Permissions trump rules
                if (!permissionmanager.hasPermission(property.getReadPermission())) {
                    fieldx.setVisible(false);
                }
                if (!permissionmanager.hasPermission(property.getWritePermission())) {
                    fieldx.setEnabled(false);
                }
                if (fieldx instanceof AbstractSelect) {
                    AbstractSelect select = (AbstractSelect) fieldx;
                    List<ChoiceBase> availableList = new ArrayList<ChoiceBase>();
                    for (ChoiceBase v : property.getAvailableValues()) {
                        availableList.add(v);
                    }
                    logger.debug("{} availableList {}", property.getName(), availableList);
                    Collection<?> itemIds = select.getItemIds();
                    List<Object> killList = new ArrayList<Object>();
                    for (Object itemId : itemIds) {
                        if (availableList.contains(itemId))
                            continue;
                        killList.add(itemId);
                    }
                    for (Object kill : killList) {
                        select.removeItem(kill);
                    }
                    for (ChoiceBase cb : availableList) {
                        select.addItem(cb);
                    }
                    logger.debug("Select {} value \"{}\", updated to {}",
                            new Object[] { property.getName(), select.getValue(), select.getItemIds() });
                }
            }
            fieldx.requestRepaint();
        }
    }

    public Collection<AbstractField> getFields() {
        if (logger.isDebugEnabled()) {
            logger.debug("fetching registered fields for MaduraSessionManager {}",
                    getValidationEngine().getIdentifier());
            for (Entry<Integer, AbstractField> entry : m_fields.entrySet()) {
                logger.debug("{}={}", entry.getKey(), entry.getValue().getCaption());
            }
            logger.debug("--------");
        }
        return Collections.unmodifiableCollection(m_fields.values());
    }

    private Collection<Label> getLabels() {
        return Collections.unmodifiableCollection(m_labels.values());
    }

    public Hints getHints() {
        return m_hints;
    }

    public void setHints(Hints hints) {
        m_hints = hints;
    }

    /////////////////////////////////////////////////
    public List<MaduraPropertyWrapper> getFieldList(ValidationObject validationObject) {
        List<MaduraPropertyWrapper> ret = new ArrayList<MaduraPropertyWrapper>();
        //       Class<?> clazz = validationObject.getClass();
        ObjectMetadata objectMetadata = validationObject.getMetadata();
        Collection<PropertyMetadata> propertyMetadata = objectMetadata.getAllPropertyMetadata();
        for (PropertyMetadata property : propertyMetadata) {
            Method getter = property.getGetMethod();
            Method setter = property.getSetMethod();
            FieldMetadata fieldMetadata = objectMetadata.getFieldMetadata(property.getName());
            ret.add(new MaduraPropertyWrapper(fieldMetadata, validationObject, setter, getter, getHints(),
                    m_messageSource));
        }
        return ret;
    }

    public List<String> getFieldList(ValidationObject validationObject, Item dataSource) {
        List<String> ret = new ArrayList<String>();
        ObjectMetadata objectMetadata = validationObject.getMetadata();
        //       Class<?> clazz = validationObject.getClass();
        Collection<PropertyMetadata> propertyMetadata = objectMetadata.getAllPropertyMetadata();
        for (PropertyMetadata property : propertyMetadata) {
            String fieldName = property.getName();
            Method getter = property.getGetMethod();
            Method setter = property.getSetMethod();
            FieldMetadata fieldMetadata;
            try {
                fieldMetadata = objectMetadata.getFieldMetadata(property.getName());
                dataSource.removeItemProperty(fieldName);
                dataSource.addItemProperty(fieldName, new MaduraPropertyWrapper(fieldMetadata, validationObject,
                        setter, getter, getHints(), m_messageSource));
            } catch (NullPointerException e) {
                logger.info("property {} not bound to Madura Objects", fieldName);
            }
            ret.add(fieldName);
        }
        return ret;
    }

    public MaduraPropertyWrapper getMaduraPropertyWrapper(FieldMetadata fieldMetadata) {
        ProxyField pf = fieldMetadata.getValidationSession().getProxyField(fieldMetadata);
        return getMaduraPropertyWrapper((ValidationObject) pf.getProxyObject().getObject(), pf.getFieldName());
    }

    public MaduraPropertyWrapper getMaduraPropertyWrapper(ValidationObject validationObject, String propertyName) {
        Hints hints = getHints();
        //        Class<?> clazz = validationObject.getClass();
        ObjectMetadata objectMetadata = validationObject.getMetadata();

        Collection<PropertyMetadata> propertyMetadata = objectMetadata.getAllPropertyMetadata();
        for (PropertyMetadata property : propertyMetadata) {
            String fieldName = property.getName();
            if (!fieldName.equals(propertyName)) {
                continue;
            }
            Method getter = property.getGetMethod();
            Method setter = property.getSetMethod();
            FieldMetadata fieldMetadata;
            try {
                fieldMetadata = objectMetadata.getFieldMetadata(fieldName);
                return new MaduraPropertyWrapper(fieldMetadata, validationObject, setter, getter, hints,
                        m_messageSource);
            } catch (NullPointerException e) {
                return new MaduraPropertyWrapper(propertyName, validationObject, setter, getter, hints,
                        m_messageSource);
            }
        }
        return null;
    }

    public void bind(final MaduraForm form, final AbstractField field, ValidationObject validationObject,
            String propertyName) {
        MaduraPropertyWrapper property = getMaduraPropertyWrapper(validationObject, propertyName);
        if (property == null) {
            throw new LocaleAwareRuntimeException("property.not.found",
                    new Object[] { validationObject.getClass().getName(), propertyName }, m_messageSource);
        }
        bind(form, field, property);
    }

    public void bind(final MaduraForm form, final AbstractField field, MaduraPropertyWrapper property) {
        field.setPropertyDataSource(property);
        Hints hints = getHints();

        hints.setCommonProperties(field, property, m_messageSource);
        setPermissions(property, field);
        registerWidget(field);
        field.addListener(new MaduraPropertyWrapper.ValueChangeListener() {

            private static final long serialVersionUID = -3295559168401789196L;

            public void valueChange(ValueChangeEvent event) {
                com.vaadin.data.Property p = field.getPropertyDataSource();
                if (p instanceof MaduraPropertyWrapper) {
                    MaduraPropertyWrapper property = (MaduraPropertyWrapper) p;
                    if (property.getErrorText() != null) {
                        field.setComponentError(new UserError(property.getErrorText()));
                    } else {
                        field.setComponentError(null);
                    }
                }
                List<String> errors = new ArrayList<String>();
                if (form != null) {
                    for (Object propertyId : form.getItemPropertyIds()) {
                        Field f = form.getField(propertyId);
                        if (f instanceof AbstractField) {
                            AbstractField fieldy = (AbstractField) f;
                            if (fieldy.getComponentError() != null) {
                                errors.add(fieldy.getComponentError().toString());
                            }
                        }
                    }
                    form.setErrors(errors);
                }
                updateOtherFields(field);
            }
        });
    }

    public void register(final AbstractField field) {
        if (field instanceof Button) {
            throw new RuntimeException("Attempted to register a button without a Button Painter");
        }
        registerWidget(field);
        field.addListener(new MaduraPropertyWrapper.ValueChangeListener() {

            private static final long serialVersionUID = 5542293169155226281L;

            public void valueChange(ValueChangeEvent event) {
                com.vaadin.data.Property p = field.getPropertyDataSource();
                if (p instanceof MaduraPropertyWrapper) {
                    MaduraPropertyWrapper property = (MaduraPropertyWrapper) p;
                    if (property.getErrorText() != null) {
                        field.setComponentError(new UserError(property.getErrorText()));
                    } else {
                        field.setComponentError(null);
                    }
                }
                //                List<String> errors = new ArrayList<String>();
                //                if (form != null)
                //                {
                //                    for (Object propertyId : form.getItemPropertyIds())
                //                    {
                //                        Field f = form.getField(propertyId);
                //                        if (f instanceof AbstractField)
                //                        {
                //                            AbstractField fieldy = (AbstractField) f;
                //                            if (fieldy.getComponentError() != null)
                //                            {
                //                                errors.add(fieldy.getComponentError()
                //                                        .toString());
                //                            }
                //                        }
                //                    }
                //                    form.setErrors(errors);
                //                }
                updateOtherFields(field);
            }
        });
    }

    public void register(final Button field, ButtonPainter painter) {
        MaduraPropertyWrapper property = painter.getProperty();
        ButtonProperty bp = new ButtonProperty(painter, field.getCaption(), m_messageSource);
        field.setPropertyDataSource(bp);
        if (property != null) {
            Hints hints = getHints();
            hints.setCommonProperties(field, property, m_messageSource);
            setPermissions(property, field);
        }
        registerWidget(field);
    }

    public void register(final MenuItem field, MenuItemPainter painter) {
        MaduraPropertyWrapper property = painter.getProperty();
        if (property != null) {
            Hints hints = getHints();
            hints.setCommonProperties(field, property, m_messageSource);
            setPermissions(property, field);
        }
        registerWidget(field, painter);
    }

    public void register(final MenuItem menuItem) {
        Command command = menuItem.getCommand();
        if (command instanceof CommandExt) {
            CommandExt commandExt = (CommandExt) command;
            MenuItemPainter painter = commandExt.getPainter();
            MaduraPropertyWrapper property = painter.getProperty();
            if (property != null) {
                Hints hints = getHints();
                hints.setCommonProperties(menuItem, property, m_messageSource);
                setPermissions(property, menuItem);
            }
            registerWidget(menuItem, painter);
        }
    }

    public void bind(final Button button, List<MaduraPropertyWrapper> properties) {
        ButtonProperty buttonProperty = (ButtonProperty) button.getPropertyDataSource();
        buttonProperty.getPainter().setProperties(properties);
        button.setCaption(buttonProperty.getCaption());
        buttonProperty.getPainter().paint(button);
    }

    public void bind(final MenuItem menuItem, List<MaduraPropertyWrapper> properties) {
        Command command = menuItem.getCommand();
        if (command instanceof CommandExt) {
            CommandExt commandExt = (CommandExt) command;
            MenuItemPainter painter = commandExt.getPainter();
            painter.setProperties(properties);
            painter.paint(menuItem);
        }
    }

    private void setPermissions(MaduraPropertyWrapper property, AbstractComponent field) {
        PermissionManager permissionmanager = getPermissionManager();
        if (!permissionmanager.hasPermission(property.getWritePermission())) {
            field.setReadOnly(true);
        }
        if (!permissionmanager.hasPermission(property.getReadPermission())) {
            field.setVisible(false);
        }
    }

    private void setPermissions(MaduraPropertyWrapper property, MenuItem field) {
        PermissionManager permissionmanager = getPermissionManager();
        if (!permissionmanager.hasPermission(property.getWritePermission())) {
            field.setEnabled(false);
        }
        if (!permissionmanager.hasPermission(property.getReadPermission())) {
            field.setVisible(false);
        }
    }

    public void bind(AbstractField field, String propertyName, List<MaduraPropertyWrapper> properties) {
        MaduraPropertyWrapper property = findProperty(propertyName, properties);
        bind(field, property);
    }

    public void bind(final AbstractField field, MaduraPropertyWrapper property) {
        field.setPropertyDataSource(property);
        Hints hints = getHints();

        hints.setCommonProperties(field, property, getMessageSource());
        setPermissions(property, field);
    }

    public MaduraPropertyWrapper findProperty(String propertyName, List<MaduraPropertyWrapper> properties) {
        for (MaduraPropertyWrapper property : properties) {
            if (property.getName().equals(propertyName)) {
                return property;
            }
        }
        throw new LocaleAwareRuntimeException("Property named {0} not found in list", new Object[] { propertyName },
                m_messageSource);
    }

    public void bind(Label field, LabelProperty property) {
        field.setPropertyDataSource(property);
        setPermissions(property.getProperty(), field);
    }

    @PreDestroy
    public void close() {
        if (m_validationSession == null) {
            return;
        }
        m_validationSession.close();
        m_validationSession = null;
        m_labels.clear();
        m_fields.clear();
    }

    public ValidationEngine getValidationEngine() {
        return m_validationEngine;
    }

    public void setValidationEngine(ValidationEngine validationEngine) {
        m_validationEngine = validationEngine;
    }

    public ValidationSession getValidationSession() {
        if (m_validationSession == null) {
            m_validationSession = getValidationEngine().createSession(LocaleContextHolder.getLocale());
        }
        return m_validationSession;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getFieldFactory()
     */
    public FieldFactory getFieldFactory() {
        return m_formFieldFactory;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getFormFieldFactory()
     */
    public FieldFactory getFormFieldFactory() {
        return m_formFieldFactory;
    }

    public void setFormFieldFactory(FieldFactory formFieldFactory) {
        m_formFieldFactory = formFieldFactory;
    }

    public void setMessageSource(MessageSource messageSource) {
        m_messageSource = messageSource;
    }

    public PermissionManager getPermissionManager() {
        return m_permissionManager;
    }

    public void setPermissionManager(PermissionManager permissionManager) {
        m_permissionManager = permissionManager;
    }

    public MessageSource getMessageSource() {
        return m_messageSource;
    }

    public void afterPropertiesSet() throws Exception {
        m_formFieldFactory.setMaduraSessionManager(this);
    }
}