org.apache.openaz.xacml.admin.view.windows.ExpressionBuilderComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.openaz.xacml.admin.view.windows.ExpressionBuilderComponent.java

Source

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.apache.openaz.xacml.admin.view.windows;

import java.util.Map;

import javax.xml.bind.JAXBElement;

import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeSelectorType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.FunctionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinitionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableReferenceType;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.openaz.xacml.admin.jpa.Attribute;
import org.apache.openaz.xacml.admin.jpa.Datatype;
import org.apache.openaz.xacml.admin.jpa.FunctionArgument;
import org.apache.openaz.xacml.admin.jpa.FunctionDefinition;
import org.apache.openaz.xacml.admin.model.ExpressionContainer;
import org.apache.openaz.xacml.admin.util.AdminNotification;
import org.apache.openaz.xacml.admin.util.JPAUtils;
import org.apache.openaz.xacml.admin.util.XACMLFunctionValidator;
import org.apache.openaz.xacml.admin.view.events.ApplyParametersChangedListener;
import org.apache.openaz.xacml.util.XACMLObjectCopy;
import com.vaadin.annotations.AutoGenerated;
import com.vaadin.data.Container.ItemSetChangeEvent;
import com.vaadin.data.Container.ItemSetChangeListener;
import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
import com.vaadin.ui.AbstractSelect.ItemDescriptionGenerator;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

public class ExpressionBuilderComponent extends Window implements ApplyParametersChangedListener {
    /*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

    @AutoGenerated
    private VerticalLayout mainLayout;
    @AutoGenerated
    private Button buttonSave;
    @AutoGenerated
    private TreeTable treeExpressions;
    @AutoGenerated
    private HorizontalLayout horizontalLayout_1;
    @AutoGenerated
    private CheckBox checkBoxShortName;
    @AutoGenerated
    private Button buttonClearAll;
    @AutoGenerated
    private Button buttonDeleteExpression;
    @AutoGenerated
    private Button buttonAddExpression;
    /*
     * 
     * 
     * 
     */
    private static final long serialVersionUID = 1L;
    private static Log logger = LogFactory.getLog(ExpressionBuilderComponent.class);

    private static final Action ADD_EXPRESSION = new Action("Add Expression");
    private static final Action EDIT_EXPRESSION = new Action("Edit Expression");
    private static final Action DELETE_EXPRESSION = new Action("Delete Expression");
    private static final Action ADD_ARGUMENT = new Action("Add Argument");
    private static final Action EDIT_ARGUMENT = new Action("Edit Argument");
    private static final Action DELETE_ARGUMENT = new Action("Delete Argument");

    private final Object[] visibleColumns = new Object[] { ExpressionContainer.PROPERTY_NAME,
            ExpressionContainer.PROPERTY_ID, ExpressionContainer.PROPERTY_ID_SHORT,
            ExpressionContainer.PROPERTY_DATATYPE, ExpressionContainer.PROPERTY_DATATYPE_SHORT };
    private final String[] columnHeaders = new String[] { "Name", "XCAML ID or Value", "XCAML ID or Value",
            "Data Type ID", "Data Type ID" };

    private final ExpressionBuilderComponent self = this;
    private final Object parent;
    private final Map<VariableDefinitionType, PolicyType> variables;
    private final ExpressionContainer container;
    private boolean isSaved = false;

    /**
     * The constructor should first build the main layout, set the
     * composition root and then do any custom initialization.
     *
     * The constructor will not be automatically regenerated by the
     * visual editor.
     */
    public ExpressionBuilderComponent(Object parent, Object root, FunctionArgument argument,
            Map<VariableDefinitionType, PolicyType> variables) {
        buildMainLayout();
        //      setCompositionRoot(mainLayout);
        setContent(mainLayout);
        //
        // Save our data
        //
        this.parent = parent;
        this.variables = variables;
        this.container = new ExpressionContainer(parent, root, argument);
        //
        // Make sure we support the parent object
        //
        if (this.isSupported() == false) {
            throw new IllegalArgumentException("Unsupported object type");
        }
        //
        // Set our shortcuts
        //
        this.setCloseShortcut(KeyCode.ESCAPE);
        //
        // Finish our GUI initialization
        //
        this.initializeTree();
        this.initializeButtons();
        this.initializeCheckbox();
        //
        // Setup the buttons
        //
        this.setupButtons();
    }

    private boolean isSupported() {
        return this.isParentACondition() || this.isParentAVariable() || this.isParentAAssignment();
    }

    private boolean isParentACondition() {
        return this.parent instanceof ConditionType;
    }

    private boolean isParentAVariable() {
        return this.parent instanceof VariableDefinitionType;
    }

    private boolean isParentAAssignment() {
        return this.parent instanceof AttributeAssignmentExpressionType;
    }

    private void initializeTree() {
        //
        // Initialize GUI properties
        //
        this.treeExpressions.setImmediate(true);
        this.treeExpressions.setSelectable(true);
        //
        // Initialize the data source
        //
        this.treeExpressions.setContainerDataSource(this.container);
        this.treeExpressions.setItemCaptionMode(ItemCaptionMode.PROPERTY);
        this.treeExpressions.setVisibleColumns(this.visibleColumns);
        this.treeExpressions.setColumnHeaders(this.columnHeaders);
        this.treeExpressions.setColumnCollapsingAllowed(true);
        this.treeExpressions.setColumnCollapsed(ExpressionContainer.PROPERTY_ID, true);
        this.treeExpressions.setColumnCollapsed(ExpressionContainer.PROPERTY_DATATYPE, true);
        //
        // Add our action handler
        //
        this.treeExpressions.addActionHandler(new Handler() {
            private static final long serialVersionUID = 1L;

            @Override
            public Action[] getActions(Object target, Object sender) {
                if (target == null) {
                    if (self.container.size() == 0) {
                        return new Action[] { ADD_EXPRESSION };
                    }
                    return null;
                }
                if (target instanceof ApplyType
                        && XACMLFunctionValidator.canHaveMoreArguments((ApplyType) target)) {
                    return new Action[] { ADD_ARGUMENT, EDIT_EXPRESSION, DELETE_EXPRESSION };
                }
                return new Action[] { EDIT_ARGUMENT, DELETE_ARGUMENT };
            }

            @Override
            public void handleAction(Action action, Object sender, Object target) {
                if (action == ADD_EXPRESSION && target == null) {
                    self.addExpression(null, null);
                }
                if (action == EDIT_EXPRESSION && target != null) {
                    self.editExpression(target, (ApplyType) self.container.getParent(target),
                            (FunctionArgument) self.container.getArgument(target));
                }
                if (action == DELETE_EXPRESSION && target != null) {
                    self.deleteExpression(target);
                }
                if (action == ADD_ARGUMENT && target != null && target instanceof ApplyType) {
                    self.addArgument((ApplyType) target);
                }
                if (action == EDIT_ARGUMENT && target != null) {
                    self.editExpression(target, (ApplyType) self.container.getParent(target),
                            (FunctionArgument) self.container.getArgument(target));
                }
                if (action == DELETE_ARGUMENT && target != null) {
                    self.deleteExpression(target);
                }
            }
        });
        //
        // Listen to double-click item selections
        //
        this.treeExpressions.addItemClickListener(new ItemClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void itemClick(ItemClickEvent event) {
                if (event.isDoubleClick()) {
                    Object target = event.getItemId();//self.treeExpressions.getValue();
                    if (target == null) {
                        return;
                    }
                    self.editExpression(target, (ApplyType) self.container.getParent(target),
                            (FunctionArgument) self.container.getArgument(target));
                }
            }
        });
        //
        // Listen when the user selects a row
        //
        this.treeExpressions.addValueChangeListener(new ValueChangeListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void valueChange(ValueChangeEvent event) {
                self.setupButtons();
            }
        });
        //
        // Listen to when the table contents change
        //
        this.treeExpressions.addItemSetChangeListener(new ItemSetChangeListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void containerItemSetChange(ItemSetChangeEvent event) {
                self.validateExpression();
            }
        });
        //
        // Expand columns automatically
        //
        this.treeExpressions.setColumnExpandRatio(ExpressionContainer.PROPERTY_NAME, 1.0f);
        this.treeExpressions.setColumnExpandRatio(ExpressionContainer.PROPERTY_ID, 1.0f);
        this.treeExpressions.setColumnExpandRatio(ExpressionContainer.PROPERTY_DATATYPE, 1.0f);
        //
        // Expand all the children
        //
        for (Object id : this.treeExpressions.getItemIds()) {
            this.treeExpressions.setCollapsed(id, false);
        }
        //
        // Have a description generator
        //
        this.treeExpressions.setItemDescriptionGenerator(new ItemDescriptionGenerator() {
            private static final long serialVersionUID = 1L;

            @Override
            public String generateDescription(Component source, Object itemId, Object propertyId) {
                if (propertyId != null && propertyId.equals(ExpressionContainer.PROPERTY_NAME)
                        && itemId instanceof ApplyType) {
                    return ((ApplyType) itemId).getDescription();
                }
                return null;
            }
        });
    }

    private void initializeButtons() {
        this.buttonClearAll.setImmediate(true);
        this.buttonClearAll.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(ClickEvent event) {
                self.clearAllExpressions();
            }

        });

        this.buttonAddExpression.setImmediate(true);
        this.buttonAddExpression.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(ClickEvent event) {
                Object selected = self.treeExpressions.getValue();
                if (selected == null) {
                    //
                    // Adding a root expression
                    //
                    self.addExpression(null, null);
                } else {
                    //
                    // Adding an argument
                    //
                    if (selected instanceof ApplyType) {
                        //
                        // Get the function
                        //
                        self.addArgument((ApplyType) selected);
                    }
                }
            }
        });

        this.buttonDeleteExpression.setImmediate(true);
        this.buttonDeleteExpression.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(ClickEvent event) {
                Object id = self.treeExpressions.getValue();
                if (id == null) {
                    logger.error("Delete button clicked on null selection");
                    return;
                }
                self.deleteExpression(id);
            }

        });

        this.buttonSave.setImmediate(true);
        this.buttonSave.setClickShortcut(KeyCode.ENTER);
        this.buttonSave.setEnabled(false);
        this.buttonSave.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(ClickEvent event) {
                //
                // TODO validate
                //
                //
                // Mark that we are saved
                //
                self.isSaved = true;
                //
                // Close the window
                //
                self.close();
            }
        });
    }

    protected void initializeCheckbox() {
        this.checkBoxShortName.setValue(true);
        this.checkBoxShortName.setImmediate(true);
        this.checkBoxShortName.addValueChangeListener(new ValueChangeListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void valueChange(ValueChangeEvent event) {
                self.treeExpressions.setColumnCollapsed(ExpressionContainer.PROPERTY_ID,
                        self.checkBoxShortName.getValue());
                self.treeExpressions.setColumnCollapsed(ExpressionContainer.PROPERTY_DATATYPE,
                        self.checkBoxShortName.getValue());
                self.treeExpressions.setColumnCollapsed(ExpressionContainer.PROPERTY_ID_SHORT,
                        !self.checkBoxShortName.getValue());
                self.treeExpressions.setColumnCollapsed(ExpressionContainer.PROPERTY_DATATYPE_SHORT,
                        !self.checkBoxShortName.getValue());
            }
        });
    }

    protected void setupButtons() {
        if (this.treeExpressions.size() == 0) {
            this.buttonAddExpression.setEnabled(true);
            this.buttonClearAll.setEnabled(false);
            this.buttonSave.setEnabled(false);
        } else {
            this.validateExpression();
            this.buttonAddExpression.setEnabled(false);
            this.buttonClearAll.setEnabled(true);
        }
        Object value = this.treeExpressions.getValue();
        if (value == null) {
            this.buttonDeleteExpression.setEnabled(false);
        } else {
            this.buttonDeleteExpression.setEnabled(true);
        }
    }

    protected void validateExpression() {
        boolean valid = false;
        boolean canHaveMore = false;
        if (this.isParentACondition()) {
            valid = XACMLFunctionValidator.validateCondition((ConditionType) this.parent);
            canHaveMore = XACMLFunctionValidator.canHaveMoreArguments((ConditionType) this.parent);
        } else if (this.isParentAVariable()) {
            valid = XACMLFunctionValidator.validateVariable((VariableDefinitionType) this.parent);
            canHaveMore = XACMLFunctionValidator.canHaveMoreArguments((VariableDefinitionType) this.parent);
        } else if (this.isParentAAssignment()) {
            valid = XACMLFunctionValidator.validateAssignment((AttributeAssignmentExpressionType) this.parent);
            canHaveMore = XACMLFunctionValidator
                    .canHaveMoreArguments((AttributeAssignmentExpressionType) this.parent);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("valid: " + valid + " canHaveMore: " + canHaveMore);
        }
        //      this.buttonAddExpression.setEnabled(canHaveMore);
        this.buttonSave.setEnabled(valid);
    }

    protected void addArgument(final ApplyType parentApply) {
        //
        // Get the function
        //
        FunctionDefinition function = JPAUtils.findFunction(parentApply.getFunctionId());
        if (function != null) {
            FunctionArgument argument = XACMLFunctionValidator
                    .getFunctionArgument(parentApply.getExpression().size() + 1, function);
            if (logger.isDebugEnabled()) {
                logger.debug("Add Argument: " + argument);
            }
            assert argument != null;
            //
            // Is this a high order bag function? And it's data type not defined? (most likely)
            //
            if (function.isHigherOrder() && argument.getDatatypeBean() == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("isHighOrder and a null datatype bean");
                }
                //
                // Get what the data type restriction should be
                //
                try {
                    assert parentApply.getExpression().size() > 0;
                    JAXBElement<?> element = parentApply.getExpression().get(0);
                    assert element != null && element.getValue() != null;
                    Object declaredFunction = element.getValue();
                    assert declaredFunction instanceof FunctionType;
                    FunctionDefinition declaredFunctionDefinition = JPAUtils
                            .findFunction(((FunctionType) declaredFunction).getFunctionId());
                    assert declaredFunctionDefinition != null;
                    if (logger.isDebugEnabled()) {
                        logger.debug("declaredFunction is: " + declaredFunctionDefinition);
                    }
                    FunctionArgument declaredFunctionArgument = XACMLFunctionValidator
                            .getFunctionArgument(parentApply.getExpression().size(), declaredFunctionDefinition);
                    assert declaredFunctionArgument != null;
                    if (logger.isDebugEnabled()) {
                        logger.debug("declaredFunctionArgument is: " + declaredFunctionArgument);
                    }
                    //
                    // Copy the argument
                    //
                    argument = new FunctionArgument(argument);
                    argument.setDatatypeBean(declaredFunctionArgument.getDatatypeBean());
                } catch (Exception e) {
                    logger.error("Exception while determining parent apply's FunctionType argument datatype.");
                }

            }
            self.addExpression(parentApply, argument);
        } else {
            AdminNotification.error("ApplyType does not have a function defined. Please define that first.");
        }

    }

    protected void addExpression(final ApplyType parentApply, final FunctionArgument argument) {
        if (logger.isDebugEnabled()) {
            logger.debug("Adding Expression: " + parentApply + " arg: " + argument);
        }
        //
        // First we need to select what Expression They want
        //
        final ExpressionSelectionWindow selector = new ExpressionSelectionWindow(parentApply,
                this.isParentAAssignment(), (argument != null ? argument.isBag() : false),
                (argument != null ? !argument.isBag() : false));
        selector.setCaption("Select the Expression Type");
        selector.setModal(true);
        selector.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Was something selected?
                //
                String selection = selector.getSelection();
                if (selection == null) {
                    return;
                }
                //
                // What did the user select?
                //
                if (selection.equals(ExpressionSelectionWindow.OPTION_APPLY)) {
                    //
                    self.editApply(new ApplyType(), parentApply, argument);
                    //
                } else if (selection.equals(ExpressionSelectionWindow.OPTION_DESIGNATOR)) {
                    //
                    self.editAttribute(new AttributeDesignatorType(), parentApply, argument);
                    //
                } else if (selection.equals(ExpressionSelectionWindow.OPTION_SELECTOR)) {
                    //
                    self.editAttribute(new AttributeSelectorType(), parentApply, argument);
                    //
                } else if (selection.equals(ExpressionSelectionWindow.OPTION_VALUE)) {
                    //
                    self.editValue(new AttributeValueType(), parentApply, argument);
                    //
                } else if (selection.equals(ExpressionSelectionWindow.OPTION_VARIABLE)) {
                    //
                    self.editVariable(new VariableReferenceType(), parentApply, argument);
                    //
                }
            }
        });
        selector.center();
        UI.getCurrent().addWindow(selector);
    }

    protected void editApply(final ApplyType apply, final ApplyType parent, final FunctionArgument argument) {
        if (logger.isDebugEnabled()) {
            logger.debug("editApply: " + apply + " parent: " + parent + " :" + argument);
        }
        //
        // Copy the apply and create its window
        //
        final ApplyType copyApply = XACMLObjectCopy.copy(apply);
        final ApplyEditorWindow window = new ApplyEditorWindow(copyApply, parent, argument, self.parent);
        window.setCaption("Edit The Apply Expression");
        window.setModal(true);
        //
        // Set ourselves as an ApplyParametersChanged listener
        //
        window.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Did the user save?
                //
                if (window.isSaved() == false) {
                    return;
                }
                //
                // Copy back the apply
                //
                apply.setDescription(copyApply.getDescription());
                apply.setFunctionId(copyApply.getFunctionId());
                //
                // Get the function information
                //
                FunctionDefinition function = JPAUtils.findFunction(apply.getFunctionId());
                assert function != null;
                //
                // Is this a new Apply?
                //
                if (self.container.containsId(apply)) {
                    //
                    // No - we are updating
                    //
                    self.container.updateItem(apply);
                } else {
                    //
                    // Is this a higher-order bag function?
                    //
                    if (function.isHigherOrder()) {
                        //
                        // Have the user select a function for it
                        //
                        final FunctionSelectionWindow functionSelection = new FunctionSelectionWindow(null);
                        functionSelection.setCaption("Select Function");
                        functionSelection.setModal(true);
                        functionSelection.addCloseListener(new CloseListener() {
                            private static final long serialVersionUID = 1L;

                            @Override
                            public void windowClose(CloseEvent e) {
                                //
                                // Did the user save?
                                //
                                if (functionSelection.isSaved() == false) {
                                    return;
                                }
                                //
                                // Get the function
                                //
                                String function = functionSelection.getSelectedFunction();
                                if (function == null || function.isEmpty()) {
                                    logger.error("Function window said it was saved, but there was no function.");
                                    return;
                                }
                                //
                                // Create the function object
                                //
                                FunctionType hoFunction = new FunctionType();
                                hoFunction.setFunctionId(function);
                                //
                                // Add it into the apply
                                //
                                apply.getExpression().add(new ObjectFactory().createFunction(hoFunction));
                                //
                                // New Item
                                //
                                Item item = self.container.addItem(apply, parent, argument);
                                assert item != null;
                                self.treeExpressions.setCollapsed(apply, false);
                                self.treeExpressions.select(apply);
                            }
                        });
                        functionSelection.center();
                        UI.getCurrent().addWindow(functionSelection);
                    } else {
                        //
                        // New Item
                        //
                        Item item = self.container.addItem(apply, parent, argument);
                        assert item != null;
                        self.treeExpressions.setCollapsed(apply, false);
                        self.treeExpressions.select(apply);
                    }
                }
            }
        });
        window.center();
        UI.getCurrent().addWindow(window);
    }

    protected void editAttribute(final Object target, final ApplyType parent, final FunctionArgument argument) {
        if (logger.isDebugEnabled()) {
            logger.debug("editAttribute: " + target + " parent: " + parent + " :" + argument);
        }
        //
        // Determine what the data type needs to be
        //
        Datatype datatype = null;
        if (parent == null && this.isParentACondition()) {
            datatype = JPAUtils.getBooleanDatatype();
        } else {
            if (argument != null) {
                datatype = argument.getDatatypeBean();
            }
        }
        //
        // Copy the attribute
        //
        final Object copyAttribute = XACMLObjectCopy.deepCopy(target);
        //
        // Create the window
        //
        final AttributeSelectionWindow window = new AttributeSelectionWindow(datatype, copyAttribute);
        if (target instanceof AttributeDesignatorType) {
            window.setCaption("Edit Designator " + (((AttributeDesignatorType) target).getAttributeId() != null
                    ? ((AttributeDesignatorType) target).getAttributeId()
                    : ""));
        } else {
            window.setCaption("Edit Selector " + (((AttributeSelectorType) target).getContextSelectorId() != null
                    ? ((AttributeSelectorType) target).getContextSelectorId()
                    : ""));
        }
        window.setModal(true);
        window.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Did the user hit save?
                //
                if (window.isSaved() == false) {
                    return;
                }
                //
                // Grab the attribute
                //
                Attribute attribute = window.getAttribute();
                if (attribute == null) {
                    return;
                }
                //
                // Save it back into the original
                //
                if (target instanceof AttributeDesignatorType) {
                    ((AttributeDesignatorType) target).setAttributeId(attribute.getXacmlId());
                    ((AttributeDesignatorType) target).setCategory(attribute.getCategoryBean().getXacmlId());
                    ((AttributeDesignatorType) target).setDataType(attribute.getDatatypeBean().getXacmlId());
                    ((AttributeDesignatorType) target).setIssuer(attribute.getIssuer());
                    ((AttributeDesignatorType) target).setMustBePresent(attribute.isMustBePresent());
                } else {
                    ((AttributeSelectorType) target).setContextSelectorId(attribute.getXacmlId());
                    ((AttributeSelectorType) target).setCategory(attribute.getCategoryBean().getXacmlId());
                    ((AttributeSelectorType) target).setDataType(attribute.getDatatypeBean().getXacmlId());
                    ((AttributeSelectorType) target).setPath(attribute.getSelectorPath());
                    ((AttributeSelectorType) target).setMustBePresent(attribute.isMustBePresent());
                }
                //
                // Is this a new item?
                //
                if (self.container.containsId(target)) {
                    //
                    // No, just update the container
                    //
                    self.container.updateItem(target);
                } else {
                    //
                    // Yes a new item, add it in
                    //
                    //assert(self.container.addItem(JPAUtils.createDesignator(attribute), parent, argument) != null);
                    Item item = self.container.addItem(target, parent, argument);
                    assert item != null;
                    self.treeExpressions.select(target);
                }
            }
        });
        window.center();
        UI.getCurrent().addWindow(window);
    }

    protected void editValue(final AttributeValueType value, final ApplyType parent,
            final FunctionArgument argument) {
        if (logger.isDebugEnabled()) {
            logger.debug("editvalue: " + value + " parent: " + parent + " :" + argument);
        }
        //
        // Copy the attribute value
        //
        final AttributeValueType copyValue = XACMLObjectCopy.copy(value);
        //
        // Get what the datatype should be
        //
        Datatype datatypeRestriction = null;
        //
        // Is this a root?
        //
        if (parent == null) {
            //
            // Check if our parent container is a condition
            //
            if (self.isParentACondition()) {
                //
                // We are only allowed to return boolean's
                //
                datatypeRestriction = JPAUtils.getBooleanDatatype();
            }
        } else {
            //
            // Are we an argument?
            //
            if (argument != null) {
                //
                // Yes - we are restricted to that argument's datatype
                //
                datatypeRestriction = argument.getDatatypeBean();
            }
        }
        //
        // Create the window
        //
        final AttributeValueEditorWindow window = new AttributeValueEditorWindow(copyValue, datatypeRestriction);
        window.setCaption("Edit Attribute Value");
        window.setModal(true);
        window.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Did the user click save?
                //
                if (window.isSaved() == false) {
                    return;
                }
                //
                // Yes - get the value
                //
                value.getContent().clear();
                for (Object o : copyValue.getContent()) {
                    value.getContent().add(o);
                }
                value.setDataType(copyValue.getDataType());
                //
                // Was this a new value?
                //
                if (self.container.containsId(value)) {
                    //
                    // No - update it
                    //
                    self.container.updateItem(value);
                } else {
                    //
                    // Yes - add it in
                    //
                    Item item = self.container.addItem(value, parent, argument);
                    assert item != null;
                }
            }
        });
        window.center();
        UI.getCurrent().addWindow(window);
    }

    protected void editVariable(final VariableReferenceType variable, final ApplyType parent,
            final FunctionArgument argument) {
        if (logger.isDebugEnabled()) {
            logger.debug("editVariable: " + variable + " parent: " + parent + " :" + argument);
        }
        //
        // Copy the variable
        //
        final VariableReferenceType copyVariable = XACMLObjectCopy.copy(variable);
        //
        // Create the window
        //
        final VariableReferenceEditorWindow window = new VariableReferenceEditorWindow(copyVariable,
                this.variables);
        window.setCaption("Edit Variable Reference");
        window.setModal(true);
        window.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Did the user click save?
                //
                if (window.isSaved() == false) {
                    return;
                }
                //
                // Copy the variable changes back
                //
                variable.setVariableId(copyVariable.getVariableId());
                //
                // Is this a new one?
                //
                if (self.container.containsId(variable)) {
                    //
                    // No - update it
                    //
                    self.container.updateItem(variable);
                } else {
                    //
                    // Yes - add it
                    //
                    Item item = self.container.addItem(variable, parent, argument);
                    assert item != null;
                }
            }
        });
        window.center();
        UI.getCurrent().addWindow(window);
    }

    protected void editFunction(final FunctionType func, final ApplyType parent, final FunctionArgument argument) {
        if (logger.isDebugEnabled()) {
            logger.debug("editFunction: " + func + " parent: " + parent + " :" + argument);
        }

        final FunctionSelectionWindow functionSelection = new FunctionSelectionWindow(
                (func != null ? func.getFunctionId() : null));
        functionSelection.setCaption("Edit Function");
        functionSelection.setModal(true);
        functionSelection.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Did the user save?
                //
                if (functionSelection.isSaved() == false) {
                    return;
                }
                //
                // Get the function
                //
                String function = functionSelection.getSelectedFunction();
                if (function == null || function.isEmpty()) {
                    logger.error("Function window said it was saved, but there was no function.");
                    return;
                }
                //
                // New one?
                //
                if (func == null) {
                    //
                    // Create the function object
                    //
                    FunctionType hoFunction = new FunctionType();
                    hoFunction.setFunctionId(function);
                    //
                    // Add it into the apply
                    //
                    assert parent.getExpression().size() == 0;
                    parent.getExpression().add(new ObjectFactory().createFunction(hoFunction));
                    //
                    // New Item
                    //
                    Item item = self.container.addItem(func, parent, argument);
                    assert item != null;
                    self.treeExpressions.setCollapsed(parent, false);
                    self.treeExpressions.select(func);
                } else {
                    //
                    // Editing an existing
                    //
                    func.setFunctionId(function);
                    self.container.updateItem(func);
                    //
                    // Warn user
                    //
                    if (parent.getExpression().size() > 1) {
                        AdminNotification.warn(
                                "You have updated the function ID. The rest of the arguments may be invalid for the function. Please verify the other arguments.");
                    }
                }
            }
        });
        functionSelection.center();
        UI.getCurrent().addWindow(functionSelection);
    }

    protected void editExpression(final Object target, final ApplyType parent, final FunctionArgument argument) {
        if (target instanceof ApplyType) {
            //
            this.editApply((ApplyType) target, parent, argument);
            //
        } else if (target instanceof AttributeValueType) {
            //
            this.editValue((AttributeValueType) target, parent, argument);
            //
        } else if (target instanceof AttributeDesignatorType || target instanceof AttributeSelectorType) {
            //
            this.editAttribute(target, parent, argument);
            //
        } else if (target instanceof VariableReferenceType) {
            //
            this.editVariable((VariableReferenceType) target, parent, argument);
            //
        } else if (target instanceof FunctionType) {
            //
            this.editFunction((FunctionType) target, parent, argument);
            //
        }
    }

    protected void deleteExpression(Object target) {
        if (this.container.isRoot(target)) {
            if (this.treeExpressions.removeAllItems() == false) {
                logger.error("Failed to remove everything.");
            }
        } else {
            if (this.treeExpressions.removeItem(target) == false) {
                logger.error("Failed to remove " + target);
            }
        }
        this.setupButtons();
    }

    protected void clearAllExpressions() {
        if (this.treeExpressions.removeAllItems() == false) {
            logger.error("Failed to remove everything.");
        }
        this.setupButtons();
    }

    @Override
    public void applyParameterChanged(ApplyType apply, ApplyType parent, FunctionArgument argument,
            Object container) {
        logger.info("applyParameterChanged: " + apply + " " + parent + " " + argument + " " + container);
        //
        // TODO - figure out if this something being edited, or a new one
        //
    }

    public boolean isSaved() {
        return this.isSaved;
    }

    @AutoGenerated
    private VerticalLayout buildMainLayout() {
        // common part: create layout
        mainLayout = new VerticalLayout();
        mainLayout.setImmediate(false);
        mainLayout.setWidth("100%");
        mainLayout.setHeight("-1px");
        mainLayout.setMargin(true);
        mainLayout.setSpacing(true);

        // top-level component properties
        setWidth("-1px");
        setHeight("-1px");

        // horizontalLayout_1
        horizontalLayout_1 = buildHorizontalLayout_1();
        mainLayout.addComponent(horizontalLayout_1);
        mainLayout.setExpandRatio(horizontalLayout_1, 1.0f);

        // treeExpressions
        treeExpressions = new TreeTable();
        treeExpressions.setImmediate(false);
        treeExpressions.setWidth("100.0%");
        treeExpressions.setHeight("-1px");
        mainLayout.addComponent(treeExpressions);
        mainLayout.setExpandRatio(treeExpressions, 1.0f);

        // buttonSave
        buttonSave = new Button();
        buttonSave.setCaption("Save");
        buttonSave.setImmediate(true);
        buttonSave.setWidth("-1px");
        buttonSave.setHeight("-1px");
        mainLayout.addComponent(buttonSave);
        mainLayout.setComponentAlignment(buttonSave, new Alignment(48));

        return mainLayout;
    }

    @AutoGenerated
    private HorizontalLayout buildHorizontalLayout_1() {
        // common part: create layout
        horizontalLayout_1 = new HorizontalLayout();
        horizontalLayout_1.setImmediate(false);
        horizontalLayout_1.setWidth("-1px");
        horizontalLayout_1.setHeight("-1px");
        horizontalLayout_1.setMargin(false);
        horizontalLayout_1.setSpacing(true);

        // buttonAddExpression
        buttonAddExpression = new Button();
        buttonAddExpression.setCaption("Add Expression");
        buttonAddExpression.setImmediate(true);
        buttonAddExpression.setWidth("-1px");
        buttonAddExpression.setHeight("-1px");
        horizontalLayout_1.addComponent(buttonAddExpression);

        // buttonDeleteExpression
        buttonDeleteExpression = new Button();
        buttonDeleteExpression.setCaption("Delete Expression");
        buttonDeleteExpression.setImmediate(true);
        buttonDeleteExpression.setWidth("-1px");
        buttonDeleteExpression.setHeight("-1px");
        horizontalLayout_1.addComponent(buttonDeleteExpression);

        // buttonClearAll
        buttonClearAll = new Button();
        buttonClearAll.setCaption("Clear All");
        buttonClearAll.setImmediate(true);
        buttonClearAll.setDescription("Clears all the expressions.");
        buttonClearAll.setWidth("-1px");
        buttonClearAll.setHeight("-1px");
        horizontalLayout_1.addComponent(buttonClearAll);

        // checkBoxShortName
        checkBoxShortName = new CheckBox();
        checkBoxShortName.setCaption("Display Short XACML ID's");
        checkBoxShortName.setImmediate(false);
        checkBoxShortName.setDescription(
                "If checked, the right-most string of the function and datatype URI's will only be displayed.");
        checkBoxShortName.setWidth("-1px");
        checkBoxShortName.setHeight("-1px");
        horizontalLayout_1.addComponent(checkBoxShortName);

        return horizontalLayout_1;
    }

}